thank you for the comments, @freben

This commit is contained in:
Paul Marbach
2020-04-08 10:18:46 -04:00
parent 06228b71e9
commit 1d6765e044
14 changed files with 61 additions and 65 deletions
+3 -1
View File
@@ -6,6 +6,8 @@
"noEmit": false,
"declarationMap": true,
"incremental": true,
"module": "es6"
"module": "es6",
"resolveJsonModule": true,
"esModuleInterop": true
}
}
+2 -1
View File
@@ -27,7 +27,8 @@ your app's [`plugins.ts`](https://github.com/spotify/backstage/blob/master/packa
to enable the plugin:
```js
export { default as LighthousePlugin } from '@backstage/plugin-lighthouse';
import { default as LighthousePlugin } from '@backstage/plugin-lighthouse';
export LighthousePlugin;
```
Then, you need to use the `lighthouseApiRef` exported from the plugin to initialize the Rest API in
+1 -1
View File
@@ -7,7 +7,7 @@
"private": true,
"scripts": {
"build:watch": "backstage-cli plugin:build --watch",
"build": "backstage-cli build-cache -- backstage-cli plugin:build",
"build": "backstage-cli plugin:build",
"lint": "backstage-cli lint",
"test": "backstage-cli test"
},
+7 -2
View File
@@ -122,13 +122,18 @@ export class LighthouseRestApi implements LighthouseApi {
async getWebsiteList({ limit, offset }: LASListRequest = {}): Promise<
WebsiteListResponse
> {
const params = new URLSearchParams();
if (typeof limit === 'number') params.append('limit', limit.toString());
if (typeof offset === 'number') params.append('offset', offset.toString());
return await this.fetch<WebsiteListResponse>(
`/v1/websites?limit=${limit}&offset=${offset}`,
`/v1/websites?${params.toString()}`,
);
}
async getWebsiteForAuditId(auditId: string): Promise<Website> {
return await this.fetch<Website>(`/v1/audits/${auditId}/website`);
return await this.fetch<Website>(
`/v1/audits/${encodeURIComponent(auditId)}/website`,
);
}
async triggerAudit(payload: TriggerAuditPayload): Promise<Audit> {
@@ -15,8 +15,6 @@
*/
import React from 'react';
import fs from 'fs';
import path from 'path';
import { render } from '@testing-library/react';
import { wrapInThemedTestApp } from '@backstage/test-utils';
@@ -24,15 +22,9 @@ import AuditListTable from './AuditListTable';
import { WebsiteListResponse } from '../../api';
import { formatTime } from '../../utils';
const websiteListResponseJson = fs
.readFileSync(
path.join(__dirname, '../../__fixtures__/website-list-response.json'),
)
.toString();
import * as data from '../../__fixtures__/website-list-response.json';
const websiteListResponse: WebsiteListResponse = JSON.parse(
websiteListResponseJson,
);
const websiteListResponse = data as WebsiteListResponse;
describe('AuditListTable', () => {
it('renders the link to each website', () => {
@@ -51,17 +51,21 @@ export const CATEGORY_LABELS: Record<LighthouseCategoryId, string> = {
pwa: 'Progressive Web App',
};
const useStyles = makeStyles({
const useStyles = makeStyles(theme => ({
table: {
minWidth: 650,
},
status: {
textTransform: 'capitalize',
},
link: { padding: '0.75rem 0', display: 'inline-block' },
link: {
paddingTop: theme.spacing(2),
paddingBottom: theme.spacing(2),
display: 'inline-block',
},
statusCell: { whiteSpace: 'nowrap' },
sparklinesCell: { minWidth: 120 },
});
}));
type SparklinesDataByCategory = Record<LighthouseCategoryId, number[]>;
function buildSparklinesDataForItem(item: Website): SparklinesDataByCategory {
@@ -27,23 +27,22 @@ jest.mock('react-router-dom', () => {
import React from 'react';
import { MemoryRouter } from 'react-router-dom';
import fs from 'fs';
import path from 'path';
import mockFetch from 'jest-fetch-mock';
import { render, fireEvent } from '@testing-library/react';
import { ApiRegistry, ApiProvider } from '@backstage/core';
import { wrapInThemedTestApp, wrapInTheme } from '@backstage/test-utils';
import { lighthouseApiRef, LighthouseRestApi } from '../../api';
import {
lighthouseApiRef,
LighthouseRestApi,
WebsiteListResponse,
} from '../../api';
import AuditList from '.';
const { useHistory } = require.requireMock('react-router-dom');
import * as data from '../../__fixtures__/website-list-response.json';
const websiteListJson = fs
.readFileSync(
path.join(__dirname, '../../__fixtures__/website-list-response.json'),
)
.toString();
const { useHistory } = require.requireMock('react-router-dom');
const websiteListResponse = data as WebsiteListResponse;
describe('AuditList', () => {
let apis: ApiRegistry;
@@ -52,7 +51,7 @@ describe('AuditList', () => {
apis = ApiRegistry.from([
[lighthouseApiRef, new LighthouseRestApi('http://lighthouse')],
]);
mockFetch.mockResponse(websiteListJson);
mockFetch.mockResponse(JSON.stringify(websiteListResponse));
});
it('should render the table', async () => {
@@ -116,7 +115,7 @@ describe('AuditList', () => {
describe('when multiple pages are needed', () => {
beforeEach(() => {
const response = JSON.parse(websiteListJson);
const response = { ...websiteListResponse };
response.limit = 5;
response.offset = 5;
response.total = 7;
@@ -50,9 +50,9 @@ const AuditList: FC<{}> = () => {
: 1;
const lighthouseApi = useApi(lighthouseApiRef);
const { value, loading, error } = useAsync(
async (): Promise<WebsiteListResponse> =>
lighthouseApi.getWebsiteList({
const { value, loading, error } = useAsync<WebsiteListResponse>(
async () =>
await lighthouseApi.getWebsiteList({
limit: LIMIT,
offset: (page - 1) * LIMIT,
}),
@@ -22,8 +22,6 @@ jest.mock('react-router-dom', () => ({
}));
import React from 'react';
import fs from 'fs';
import path from 'path';
import mockFetch from 'jest-fetch-mock';
import { render } from '@testing-library/react';
import { wrapInThemedTestApp } from '@backstage/test-utils';
@@ -32,29 +30,24 @@ import { ApiRegistry, ApiProvider } from '@backstage/core';
import AuditView from '.';
import { lighthouseApiRef, LighthouseRestApi, Audit, Website } from '../../api';
import { formatTime } from '../../utils';
import * as data from '../../__fixtures__/website-response.json';
const { useParams }: { useParams: jest.Mock } = require.requireMock(
'react-router-dom',
);
const websiteResponseJson = fs
.readFileSync(
path.join(__dirname, '../../__fixtures__/website-response.json'),
)
.toString();
const websiteResponse = data as Website;
describe('AuditView', () => {
let apis: ApiRegistry;
let website: Website;
let id: string;
beforeEach(() => {
mockFetch.mockResponse(websiteResponseJson);
mockFetch.mockResponse(JSON.stringify(websiteResponse));
apis = ApiRegistry.from([
[lighthouseApiRef, new LighthouseRestApi('https://lighthouse')],
]);
website = JSON.parse(websiteResponseJson) as Website;
id = website.audits.find(a => a.status === 'COMPLETED')?.id as string;
id = websiteResponse.audits.find(a => a.status === 'COMPLETED')
?.id as string;
useParams.mockReturnValue({ id });
});
@@ -105,7 +98,7 @@ describe('AuditView', () => {
await rendered.findByTestId('audit-sidebar');
website.audits.forEach(a => {
websiteResponse.audits.forEach(a => {
expect(
rendered.queryByText(formatTime(a.timeCreated)),
).toBeInTheDocument();
@@ -123,13 +116,15 @@ describe('AuditView', () => {
await rendered.findByTestId('audit-sidebar');
const audit = website.audits.find(a => a.id === id) as Audit;
const audit = websiteResponse.audits.find(a => a.id === id) as Audit;
const auditElement = rendered.getByText(formatTime(audit.timeCreated));
expect(auditElement.parentElement?.parentElement?.className).toContain(
'selected',
);
const notSelectedAudit = website.audits.find(a => a.id !== id) as Audit;
const notSelectedAudit = websiteResponse.audits.find(
a => a.id !== id,
) as Audit;
const notSelectedAuditElement = rendered.getByText(
formatTime(notSelectedAudit.timeCreated),
);
@@ -149,7 +144,7 @@ describe('AuditView', () => {
await rendered.findByTestId('audit-sidebar');
website.audits.forEach(a => {
websiteResponse.audits.forEach(a => {
expect(
rendered.getByText(formatTime(a.timeCreated)).parentElement
?.parentElement,
@@ -188,7 +183,8 @@ describe('AuditView', () => {
describe.skip('when a loading audit is accessed', () => {
it('shows a loading view', async () => {
id = website.audits.find(a => a.status === 'RUNNING')?.id as string;
id = websiteResponse.audits.find(a => a.status === 'RUNNING')
?.id as string;
useParams.mockReturnValueOnce({ id });
const rendered = render(
@@ -207,7 +203,8 @@ describe('AuditView', () => {
describe.skip('when a failed audit is accessed', () => {
it('shows an error message', async () => {
id = website.audits.find(a => a.status === 'FAILED')?.id as string;
id = websiteResponse.audits.find(a => a.status === 'FAILED')
?.id as string;
useParams.mockReturnValueOnce({ id });
const rendered = render(
@@ -106,7 +106,7 @@ const AuditView: FC<{ audit?: Audit }> = ({ audit }: { audit?: Audit }) => {
<iframe
className={classes.iframe}
title={`Lighthouse audit${audit?.url ? ` for ${audit.url}` : ''}`}
src={`${lighthouseUrl}/v1/audits/${params.id}`}
src={`${lighthouseUrl}/v1/audits/${encodeURIComponent(params.id)}`}
/>
</InfoCard>
);
@@ -118,7 +118,7 @@ const ConnectedAuditView: FC<{}> = () => {
const classes = useStyles();
const { loading, error, value: nextValue } = useAsync<Website>(
async () => lighthouseApi.getWebsiteForAuditId(params.id),
async () => await lighthouseApi.getWebsiteForAuditId(params.id),
[params.id],
);
const [value, setValue] = useState<Website>();
@@ -26,8 +26,6 @@ jest.mock('react-router-dom', () => {
});
import React from 'react';
import fs from 'fs';
import path from 'path';
import mockFetch from 'jest-fetch-mock';
import { wait, render, fireEvent } from '@testing-library/react';
import { MemoryRouter } from 'react-router-dom';
@@ -39,18 +37,14 @@ import {
} from '@backstage/core';
import { wrapInThemedTestApp, wrapInTheme } from '@backstage/test-utils';
import { lighthouseApiRef, LighthouseRestApi } from '../../api';
import { lighthouseApiRef, LighthouseRestApi, Audit } from '../../api';
import CreateAudit from '.';
import * as data from '../../__fixtures__/create-audit-response.json';
const { useHistory }: { useHistory: jest.Mock } = require.requireMock(
'react-router-dom',
);
const createAuditResponseJson = fs
.readFileSync(
path.join(__dirname, '../../__fixtures__/create-audit-response.json'),
)
.toString();
const createAuditResponse = data as Audit;
// TODO add act() to these tests without breaking them!
describe('CreateAudit', () => {
@@ -123,7 +117,7 @@ describe('CreateAudit', () => {
describe('when the audit is successfully created', () => {
it('triggers a location change to the table', async () => {
useHistory().push.mockClear();
mockFetch.mockResponseOnce(createAuditResponseJson);
mockFetch.mockResponseOnce(JSON.stringify(createAuditResponse));
const rendered = render(
wrapInThemedTestApp(
@@ -47,7 +47,8 @@ your app's [\`plugins.ts\`](https://github.com/spotify/backstage/blob/master/pac
to enable the plugin:
\`\`\`js
export { default as LighthousePlugin } from '@backstage/plugin-lighthouse';
import { default as LighthousePlugin } from '@backstage/plugin-lighthouse';
export LighthousePlugin;
\`\`\`
Then, you need to use the \`lighthouseApiRef\` exported from the plugin to initialize the Rest API in
+2 -1
View File
@@ -2,6 +2,7 @@
"extends": "../../tsconfig.json",
"include": ["src"],
"compilerOptions": {
"resolveJsonModule": true
"resolveJsonModule": true,
"esModuleInterop": true
}
}
+1 -1
View File
@@ -17067,7 +17067,7 @@ request@^2.85.0, request@^2.87.0, request@^2.88.0:
tunnel-agent "^0.6.0"
uuid "^3.3.2"
"request@github:cypress-io/request#b5af0d1fa47eec97ba980cde90a13e69a2afcd16":
request@cypress-io/request#b5af0d1fa47eec97ba980cde90a13e69a2afcd16:
version "2.88.1"
resolved "https://codeload.github.com/cypress-io/request/tar.gz/b5af0d1fa47eec97ba980cde90a13e69a2afcd16"
dependencies: