diff --git a/.changeset/many-mayflies-share.md b/.changeset/many-mayflies-share.md new file mode 100644 index 0000000000..080afc6ac1 --- /dev/null +++ b/.changeset/many-mayflies-share.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-lighthouse': patch +--- + +Fixed "Emulated Form Factor" field in the audit creation form not working with the latest version (1.0.2) of `lighthouse-audit-service`. diff --git a/plugins/lighthouse/api-report.md b/plugins/lighthouse/api-report.md index 17c771e187..e9089c7e92 100644 --- a/plugins/lighthouse/api-report.md +++ b/plugins/lighthouse/api-report.md @@ -71,6 +71,9 @@ export class FetchError extends Error { get name(): string; } +// @public (undocumented) +export type FormFactor = 'mobile' | 'desktop'; + // @public (undocumented) const isLighthouseAvailable: (entity: Entity) => boolean; export { isLighthouseAvailable }; @@ -132,6 +135,21 @@ export type LighthouseCategoryId = | 'accessibility' | 'best-practices'; +// @public (undocumented) +export type LighthouseConfigSettings = { + formFactor: FormFactor; + screenEmulation: + | { + mobile: boolean; + width: number; + height: number; + deviceScaleFactor: number; + disabled: boolean; + } + | undefined; + emulatedFormFactor: FormFactor; +}; + // @public (undocumented) export const LighthousePage: () => JSX.Element; @@ -172,9 +190,7 @@ export interface TriggerAuditPayload { // (undocumented) options: { lighthouseConfig: { - settings: { - emulatedFormFactor: string; - }; + settings: LighthouseConfigSettings; }; }; // (undocumented) diff --git a/plugins/lighthouse/src/api.ts b/plugins/lighthouse/src/api.ts index e4ccefe2a1..a7197c4b96 100644 --- a/plugins/lighthouse/src/api.ts +++ b/plugins/lighthouse/src/api.ts @@ -85,14 +85,32 @@ export interface Website { /** @public */ export type WebsiteListResponse = LASListResponse; +/** @public */ +export type FormFactor = 'mobile' | 'desktop'; + +/** @public */ +export type LighthouseConfigSettings = { + // For lighthouse 7+ + formFactor: FormFactor; + screenEmulation: + | { + mobile: boolean; + width: number; + height: number; + deviceScaleFactor: number; + disabled: boolean; + } + | undefined; + // For lighthouse before 7 + emulatedFormFactor: FormFactor; +}; + /** @public */ export interface TriggerAuditPayload { url: string; options: { lighthouseConfig: { - settings: { - emulatedFormFactor: string; - }; + settings: LighthouseConfigSettings; }; }; } diff --git a/plugins/lighthouse/src/components/CreateAudit/index.test.tsx b/plugins/lighthouse/src/components/CreateAudit/index.test.tsx index 59847b516e..60a7bc1301 100644 --- a/plugins/lighthouse/src/components/CreateAudit/index.test.tsx +++ b/plugins/lighthouse/src/components/CreateAudit/index.test.tsx @@ -110,6 +110,88 @@ describe('CreateAudit', () => { }); }); + describe('when creating the audit', () => { + it('sends the correct payload for mobile', async () => { + let triggerAuditPayload: {} | undefined = undefined; + server.use( + rest.post('http://lighthouse/v1/audits', async (req, res, ctx) => { + triggerAuditPayload = await req.json(); + return res(ctx.json(createAuditResponse)); + }), + ); + + const rendered = render( + wrapInTestApp( + + + , + ), + ); + + fireEvent.change(rendered.getByLabelText(/URL/), { + target: { value: 'https://spotify.com' }, + }); + fireEvent.click(rendered.getByText(/Create Audit/)); + + await waitFor(() => + expect(triggerAuditPayload).toMatchObject({ + options: { + lighthouseConfig: { + settings: { formFactor: 'mobile', emulatedFormFactor: 'mobile' }, + }, + }, + url: 'https://spotify.com', + }), + ); + }); + + it('sends the correct payload for desktop', async () => { + let triggerAuditPayload: {} | undefined = undefined; + server.use( + rest.post('http://lighthouse/v1/audits', async (req, res, ctx) => { + triggerAuditPayload = await req.json(); + return res(ctx.json(createAuditResponse)); + }), + ); + + const rendered = render( + wrapInTestApp( + + + , + ), + ); + + fireEvent.change(rendered.getByLabelText(/URL/), { + target: { value: 'https://spotify.com' }, + }); + fireEvent.mouseDown(rendered.getByText(/Mobile/)); + fireEvent.click(rendered.getByText(/Desktop/)); + fireEvent.click(rendered.getByText(/Create Audit/)); + + await waitFor(() => + expect(triggerAuditPayload).toMatchObject({ + options: { + lighthouseConfig: { + settings: { + formFactor: 'desktop', + screenEmulation: { + mobile: false, + width: 1350, + height: 940, + deviceScaleFactor: 1, + disabled: false, + }, + emulatedFormFactor: 'desktop', + }, + }, + }, + url: 'https://spotify.com', + }), + ); + }); + }); + describe('when the audit is successfully created', () => { it('triggers a location change to the table', async () => { useNavigate.mockClear(); diff --git a/plugins/lighthouse/src/components/CreateAudit/index.tsx b/plugins/lighthouse/src/components/CreateAudit/index.tsx index f83ad6a8a3..8ed7dc8996 100644 --- a/plugins/lighthouse/src/components/CreateAudit/index.tsx +++ b/plugins/lighthouse/src/components/CreateAudit/index.tsx @@ -25,7 +25,11 @@ import { } from '@material-ui/core'; import React, { useCallback, useState } from 'react'; import { useNavigate } from 'react-router-dom'; -import { lighthouseApiRef } from '../../api'; +import { + FormFactor, + lighthouseApiRef, + LighthouseConfigSettings, +} from '../../api'; import { useQuery } from '../../utils'; import LighthouseSupportButton from '../SupportButton'; @@ -65,6 +69,23 @@ const useStyles = makeStyles(theme => ({ }, })); +const formFactorToScreenEmulationMap: Record< + FormFactor, + LighthouseConfigSettings['screenEmulation'] +> = { + // the default is mobile, so no need to override + mobile: undefined, + // Values from lighthouse's cli "desktop" preset + // https://github.com/GoogleChrome/lighthouse/blob/a6738e0033e7e5ca308b97c1c36f298b7d399402/lighthouse-core/config/constants.js#L71-L77 + desktop: { + mobile: false, + width: 1350, + height: 940, + deviceScaleFactor: 1, + disabled: false, + }, +}; + export const CreateAuditContent = () => { const errorApi = useApi(errorApiRef); const lighthouseApi = useApi(lighthouseApiRef); @@ -73,7 +94,7 @@ export const CreateAuditContent = () => { const navigate = useNavigate(); const [submitting, setSubmitting] = useState(false); const [url, setUrl] = useState(query.get('url') || ''); - const [emulatedFormFactor, setEmulatedFormFactor] = useState('mobile'); + const [formFactor, setFormFactor] = useState('mobile'); const triggerAudit = useCallback(async (): Promise => { setSubmitting(true); @@ -85,7 +106,9 @@ export const CreateAuditContent = () => { options: { lighthouseConfig: { settings: { - emulatedFormFactor, + formFactor, + emulatedFormFactor: formFactor, + screenEmulation: formFactorToScreenEmulationMap[formFactor], }, }, }, @@ -96,14 +119,7 @@ export const CreateAuditContent = () => { } finally { setSubmitting(false); } - }, [ - url, - emulatedFormFactor, - lighthouseApi, - setSubmitting, - errorApi, - navigate, - ]); + }, [url, formFactor, lighthouseApi, setSubmitting, errorApi, navigate]); return ( <> @@ -146,8 +162,10 @@ export const CreateAuditContent = () => { select required disabled={submitting} - onChange={ev => setEmulatedFormFactor(ev.target.value)} - value={emulatedFormFactor} + onChange={ev => + setFormFactor(ev.target.value as FormFactor) + } + value={formFactor} inputProps={{ 'aria-label': 'Emulated form factor' }} > Mobile