refactor: use route ref instead of relative paths

Using `useRouteRef` allows us to make the component testable, with a relative path we cannot use `mountedRoutes` within `wrapInTestApp`

Signed-off-by: Salih Candir <salih@live.at>
This commit is contained in:
Salih Candir
2022-12-23 17:08:10 +01:00
parent 1bb2630563
commit 1c0fcca4b8
2 changed files with 65 additions and 36 deletions
@@ -16,6 +16,8 @@
/* eslint-disable jest/no-disabled-tests */
import { configApiRef } from '@backstage/core-plugin-api';
jest.mock('react-router-dom', () => {
const actual = jest.requireActual('react-router-dom');
const mockNavigation = jest.fn();
@@ -28,6 +30,7 @@ jest.mock('react-router-dom', () => {
import {
setupRequestMockHandlers,
TestApiProvider,
TestApiRegistry,
wrapInTestApp,
} from '@backstage/test-utils';
@@ -39,13 +42,18 @@ import { Audit, lighthouseApiRef, LighthouseRestApi, Website } from '../../api';
import { formatTime } from '../../utils';
import * as data from '../../__fixtures__/website-response.json';
import AuditView from './index';
import { ApiProvider } from '@backstage/core-app-api';
import { ApiProvider, ConfigReader } from '@backstage/core-app-api';
import { rootRouteRef } from '../../plugin';
const { useParams }: { useParams: jest.Mock } =
jest.requireMock('react-router-dom');
const websiteResponse = data as Website;
describe('AuditView', () => {
const lighthouseRestApiMock = new LighthouseRestApi('https://lighthouse');
const testAppOptions = {
mountedRoutes: { '/': rootRouteRef },
};
let apis: TestApiRegistry;
let id: string;
@@ -59,10 +67,7 @@ describe('AuditView', () => {
),
);
apis = TestApiRegistry.from([
lighthouseApiRef,
new LighthouseRestApi('https://lighthouse'),
]);
apis = TestApiRegistry.from([lighthouseApiRef, lighthouseRestApiMock]);
id = websiteResponse.audits.find(a => a.status === 'COMPLETED')
?.id as string;
useParams.mockReturnValue({ id });
@@ -74,6 +79,7 @@ describe('AuditView', () => {
<ApiProvider apis={apis}>
<AuditView />
</ApiProvider>,
testAppOptions,
),
);
@@ -91,6 +97,7 @@ describe('AuditView', () => {
<ApiProvider apis={apis}>
<AuditView />
</ApiProvider>,
testAppOptions,
),
);
@@ -109,6 +116,7 @@ describe('AuditView', () => {
<ApiProvider apis={apis}>
<AuditView />
</ApiProvider>,
testAppOptions,
),
);
@@ -137,6 +145,7 @@ describe('AuditView', () => {
<ApiProvider apis={apis}>
<AuditView />
</ApiProvider>,
testAppOptions,
),
);
@@ -151,14 +160,22 @@ describe('AuditView', () => {
});
it('navigates to the next report with respect to the base path', async () => {
// TODO: I would need help here. How to set the base path for the test?
const basePath = `/lighthouse`;
const configApiMock = new ConfigReader({
app: { baseUrl: `http://localhost:3000/example` },
});
const rendered = render(
wrapInTestApp(
<ApiProvider apis={apis}>
<TestApiProvider
apis={[
[lighthouseApiRef, lighthouseRestApiMock],
[configApiRef, configApiMock],
]}
>
<AuditView />
</ApiProvider>,
{ routeEntries: [basePath] },
</TestApiProvider>,
{
mountedRoutes: { [`/example/lighthouse`]: rootRouteRef },
},
),
);
@@ -168,7 +185,7 @@ describe('AuditView', () => {
expect(
rendered.getByText(formatTime(a.timeCreated)).parentElement
?.parentElement,
).toHaveAttribute('href', `${basePath}/audit/${a.id}`);
).toHaveAttribute('href', `/example/lighthouse/audit/${a.id}`);
});
});
});
@@ -181,6 +198,7 @@ describe('AuditView', () => {
<ApiProvider apis={apis}>
<AuditView />
</ApiProvider>,
testAppOptions,
),
);
expect(await rendered.findByTestId('progress')).toBeInTheDocument();
@@ -199,6 +217,7 @@ describe('AuditView', () => {
<ApiProvider apis={apis}>
<AuditView />
</ApiProvider>,
testAppOptions,
),
);
expect(await rendered.findByText(/failed to fetch/)).toBeInTheDocument();
@@ -216,6 +235,7 @@ describe('AuditView', () => {
<ApiProvider apis={apis}>
<AuditView />
</ApiProvider>,
testAppOptions,
),
);
@@ -236,6 +256,7 @@ describe('AuditView', () => {
<ApiProvider apis={apis}>
<AuditView />
</ApiProvider>,
testAppOptions,
),
);
@@ -47,7 +47,8 @@ import {
Page,
Progress,
} from '@backstage/core-components';
import { useApi } from '@backstage/core-plugin-api';
import { useApi, useRouteRef } from '@backstage/core-plugin-api';
import { rootRouteRef } from '../../plugin';
// TODO(freben): move all of this out of index
@@ -67,29 +68,35 @@ interface AuditLinkListProps {
audits?: Audit[];
selectedId: string;
}
const AuditLinkList = ({ audits = [], selectedId }: AuditLinkListProps) => (
<List
data-testid="audit-sidebar"
component="nav"
aria-label="lighthouse audit history"
>
{audits.map(audit => (
<ListItem
key={audit.id}
selected={audit.id === selectedId}
button
component={Link}
replace
to={resolvePath(generatePath('audit/:id', { id: audit.id }), '../')}
>
<ListItemIcon>
<AuditStatusIcon audit={audit} />
</ListItemIcon>
<ListItemText primary={formatTime(audit.timeCreated)} />
</ListItem>
))}
</List>
);
const AuditLinkList = ({ audits = [], selectedId }: AuditLinkListProps) => {
const fromPath = useRouteRef(rootRouteRef)?.() ?? '../';
return (
<List
data-testid="audit-sidebar"
component="nav"
aria-label="lighthouse audit history"
>
{audits.map(audit => (
<ListItem
key={audit.id}
selected={audit.id === selectedId}
button
component={Link}
replace
to={resolvePath(
generatePath('audit/:id', { id: audit.id }),
fromPath,
)}
>
<ListItemIcon>
<AuditStatusIcon audit={audit} />
</ListItemIcon>
<ListItemText primary={formatTime(audit.timeCreated)} />
</ListItem>
))}
</List>
);
};
const AuditView = ({ audit }: { audit?: Audit }) => {
const classes = useStyles();
@@ -119,6 +126,7 @@ const AuditView = ({ audit }: { audit?: Audit }) => {
export const AuditViewContent = () => {
const lighthouseApi = useApi(lighthouseApiRef);
const fromPath = useRouteRef(rootRouteRef)?.() ?? '../';
const params = useParams() as { id: string };
const classes = useStyles();
const navigate = useNavigate();
@@ -178,7 +186,7 @@ export const AuditViewContent = () => {
<Button
variant="contained"
color="primary"
onClick={() => navigate(`../${createAuditButtonUrl}`)}
onClick={() => navigate(resolvePath(createAuditButtonUrl, fromPath))}
>
Create New Audit
</Button>