-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
build(plugin-lighthouse): add tools to lighthouse plugin (#458)
- Loading branch information
Showing
6 changed files
with
192 additions
and
35 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
import { | ||
type Config, | ||
type IcuMessage, | ||
Audit as LHAudit, | ||
defaultConfig, | ||
} from 'lighthouse'; | ||
import { Audit, Group } from '@code-pushup/models'; | ||
|
||
export const LIGHTHOUSE_PLUGIN_SLUG = 'lighthouse'; | ||
export const LIGHTHOUSE_REPORT_NAME = 'lighthouse-report.json'; | ||
|
||
const { audits, categories } = defaultConfig; | ||
|
||
export const GROUPS: Group[] = Object.entries(categories ?? {}).map( | ||
([id, category]) => ({ | ||
slug: id, | ||
title: getMetaString(category.title), | ||
...(category.description && { | ||
description: getMetaString(category.description), | ||
}), | ||
refs: category.auditRefs.map(ref => ({ slug: ref.id, weight: ref.weight })), | ||
}), | ||
); | ||
|
||
export const AUDITS: Audit[] = await Promise.all( | ||
(audits ?? []).map(async value => { | ||
const audit = await loadLighthouseAudit(value); | ||
return { | ||
slug: audit.meta.id, | ||
title: getMetaString(audit.meta.title), | ||
description: getMetaString(audit.meta.description), | ||
}; | ||
}), | ||
); | ||
|
||
function getMetaString(value: string | IcuMessage): string { | ||
if (typeof value === 'string') { | ||
return value; | ||
} | ||
return value.formattedDefault; | ||
} | ||
|
||
async function loadLighthouseAudit( | ||
value: Config.AuditJson, | ||
): Promise<typeof LHAudit> { | ||
// the passed value directly includes the implementation as JS object | ||
// shape: { implementation: typeof LHAudit; options?: {}; } | ||
if (typeof value === 'object' && 'implementation' in value) { | ||
return value.implementation; | ||
} | ||
// the passed value is a `LH.Audit` class instance | ||
// shape: LHAudit | ||
if (typeof value === 'function') { | ||
return value; | ||
} | ||
// the passed value is the path directly | ||
// shape: string | ||
// otherwise it is a JS object maintaining a `path` property | ||
// shape: { path: string, options?: {}; } | ||
const path = typeof value === 'string' ? value : value.path; | ||
const module = (await import(`lighthouse/core/audits/${path}.js`)) as { | ||
default: typeof LHAudit; | ||
}; | ||
return module.default; | ||
} |
35 changes: 31 additions & 4 deletions
35
packages/plugin-lighthouse/src/lib/lighthouse-plugin.integration.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,36 @@ | ||
import { expect } from 'vitest'; | ||
import { | ||
auditSchema, | ||
groupSchema, | ||
pluginConfigSchema, | ||
} from '@code-pushup/models'; | ||
import { AUDITS, GROUPS } from './constants'; | ||
import { lighthousePlugin } from './lighthouse-plugin'; | ||
|
||
describe('lighthousePlugin', () => { | ||
it('should initialize Lighthouse plugin', () => { | ||
expect(lighthousePlugin({ config: '.lighthouserc.json' }).slug).toBe( | ||
'lighthouse', | ||
); | ||
it('should create valid plugin config', () => { | ||
const pluginConfig = lighthousePlugin({ | ||
url: 'https://code-pushup-portal.com', | ||
}); | ||
expect(() => pluginConfigSchema.parse(pluginConfig)).not.toThrow(); | ||
expect(pluginConfig.audits).toHaveLength(168); | ||
expect(pluginConfig.groups).toHaveLength(5); | ||
}); | ||
}); | ||
|
||
describe('generated-constants', () => { | ||
it.each(AUDITS.map(a => [a.slug, a]))( | ||
'should parse audit "%s" correctly', | ||
(_, audit) => { | ||
expect(() => auditSchema.parse(audit)).not.toThrow(); | ||
expect(audit.description).toEqual(expect.any(String)); | ||
}, | ||
); | ||
|
||
it.each(GROUPS.map(a => [a.slug, a]))( | ||
'should parse group "%s" correctly', | ||
(_, group) => { | ||
expect(() => groupSchema.parse(group)).not.toThrow(); | ||
}, | ||
); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,38 +1,28 @@ | ||
import { defaultConfig } from 'lighthouse'; | ||
import { join } from 'node:path'; | ||
import { PluginConfig } from '@code-pushup/models'; | ||
import { echoRunnerConfigMock } from '@code-pushup/testing-utils'; | ||
import { AuditOutputs, PluginConfig } from '@code-pushup/models'; | ||
import { AUDITS, GROUPS, LIGHTHOUSE_PLUGIN_SLUG } from './constants'; | ||
|
||
type LighthousePluginConfig = { | ||
config: string; | ||
export type LighthousePluginOptions = { | ||
url: string; | ||
outputPath?: string; | ||
onlyAudits?: string | string[]; | ||
verbose?: boolean; | ||
headless?: boolean; | ||
userDataDir?: string; | ||
}; | ||
|
||
const outputDir = 'tmp'; | ||
const outputFile = join(outputDir, `out.${Date.now()}.json`); | ||
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
export function lighthousePlugin(_: LighthousePluginConfig): PluginConfig { | ||
// This line is here to have import and engines errors still present | ||
// eslint-disable-next-line @typescript-eslint/no-unused-expressions | ||
defaultConfig; | ||
export function lighthousePlugin(_: LighthousePluginOptions): PluginConfig { | ||
return { | ||
slug: 'lighthouse', | ||
title: 'ChromeDevTools Lighthouse', | ||
slug: LIGHTHOUSE_PLUGIN_SLUG, | ||
title: 'Lighthouse', | ||
icon: 'lighthouse', | ||
audits: [ | ||
{ | ||
slug: 'largest-contentful-paint', | ||
title: 'Largest Contentful Paint', | ||
}, | ||
], | ||
runner: echoRunnerConfigMock( | ||
[ | ||
{ | ||
slug: 'largest-contentful-paint', | ||
value: 0, | ||
score: 0, | ||
}, | ||
], | ||
outputFile, | ||
), | ||
audits: AUDITS, | ||
groups: GROUPS, | ||
runner: (): AuditOutputs => | ||
AUDITS.map(audit => ({ | ||
...audit, | ||
score: 0, | ||
value: 0, | ||
})), | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import type { CliFlags } from 'lighthouse'; | ||
import { objectToCliArgs } from '@code-pushup/utils'; | ||
import { LIGHTHOUSE_REPORT_NAME } from './constants'; | ||
|
||
type RefinedLighthouseOption = { | ||
url: CliFlags['_']; | ||
chromeFlags?: Record<CliFlags['chromeFlags'][number], string>; | ||
}; | ||
export type LighthouseCliOptions = RefinedLighthouseOption & | ||
Partial<Omit<CliFlags, keyof RefinedLighthouseOption>>; | ||
|
||
export function getLighthouseCliArguments( | ||
options: LighthouseCliOptions, | ||
): string[] { | ||
const { | ||
url, | ||
outputPath = LIGHTHOUSE_REPORT_NAME, | ||
onlyAudits = [], | ||
output = 'json', | ||
verbose = false, | ||
chromeFlags = {}, | ||
} = options; | ||
|
||
// eslint-disable-next-line functional/no-let | ||
let argsObj: Record<string, unknown> = { | ||
_: ['lighthouse', url.join(',')], | ||
verbose, | ||
output, | ||
'output-path': outputPath, | ||
}; | ||
|
||
if (onlyAudits != null && onlyAudits.length > 0) { | ||
argsObj = { | ||
...argsObj, | ||
onlyAudits, | ||
}; | ||
} | ||
|
||
// handle chrome flags | ||
if (Object.keys(chromeFlags).length > 0) { | ||
argsObj = { | ||
...argsObj, | ||
chromeFlags: Object.entries(chromeFlags) | ||
.map(([key, value]) => `--${key}=${value}`) | ||
.join(' '), | ||
}; | ||
} | ||
|
||
return objectToCliArgs(argsObj); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import { expect } from 'vitest'; | ||
import { getLighthouseCliArguments } from './utils'; | ||
|
||
describe('getLighthouseCliArguments', () => { | ||
it('should parse valid options', () => { | ||
expect( | ||
getLighthouseCliArguments({ | ||
url: ['https://code-pushup-portal.com'], | ||
}), | ||
).toEqual(expect.arrayContaining(['https://code-pushup-portal.com'])); | ||
}); | ||
|
||
it('should parse chrome-flags options correctly', () => { | ||
const args = getLighthouseCliArguments({ | ||
url: ['https://code-pushup-portal.com'], | ||
chromeFlags: { headless: 'new', 'user-data-dir': 'test' }, | ||
}); | ||
expect(args).toEqual( | ||
expect.arrayContaining([ | ||
'--chromeFlags="--headless=new --user-data-dir=test"', | ||
]), | ||
); | ||
}); | ||
}); |