Skip to content

Commit ac5a0e2

Browse files
authored
feat(plugin-lighthouse): add lighthouse plugin (#593)
1 parent b2ec27e commit ac5a0e2

31 files changed

+4904
-6095
lines changed

.github/workflows/code-coverage.yml

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ jobs:
2020
- plugin-eslint
2121
- plugin-coverage
2222
- plugin-js-packages
23+
- plugin-lighthouse
2324
scope: [unit, integration]
2425
name: Update code coverage
2526
runs-on: ubuntu-latest

code-pushup.config.ts

+32-10
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
import 'dotenv/config';
22
import { z } from 'zod';
33
import {
4-
// LIGHTHOUSE_OUTPUT_FILE_DEFAULT,
54
fileSizePlugin,
6-
fileSizeRecommendedRefs, // lighthouseCorePerfGroupRefs,
7-
// lighthousePlugin,
5+
fileSizeRecommendedRefs,
86
packageJsonDocumentationGroupRef,
97
packageJsonPerformanceGroupRef,
108
packageJsonPlugin,
@@ -16,6 +14,10 @@ import eslintPlugin, {
1614
eslintConfigFromNxProjects,
1715
} from './dist/packages/plugin-eslint';
1816
import jsPackagesPlugin from './dist/packages/plugin-js-packages';
17+
import {
18+
lighthouseGroupRef,
19+
lighthousePlugin,
20+
} from './dist/packages/plugin-lighthouse';
1921
import type { CoreConfig } from './packages/models/src';
2022

2123
// load upload configuration from environment
@@ -75,15 +77,36 @@ const config: CoreConfig = {
7577
type: 'module',
7678
}),
7779

78-
// see https://github.com/code-pushup/cli/issues/538
79-
// await lighthousePlugin({
80-
// url: 'https://staging.code-pushup.dev/login',
81-
// outputPath: join('.code-pushup', LIGHTHOUSE_OUTPUT_FILE_DEFAULT),
82-
// headless: true,
83-
// }),
80+
await lighthousePlugin('https://codepushup.dev/'),
8481
],
8582

8683
categories: [
84+
{
85+
slug: 'performance',
86+
title: 'Performance',
87+
refs: [lighthouseGroupRef('performance')],
88+
},
89+
{
90+
slug: 'a11y',
91+
title: 'Accessibility',
92+
refs: [lighthouseGroupRef('accessibility')],
93+
},
94+
{
95+
slug: 'best-practices',
96+
title: 'Best Practices',
97+
refs: [lighthouseGroupRef('best-practices')],
98+
},
99+
{
100+
slug: 'seo',
101+
title: 'SEO',
102+
refs: [lighthouseGroupRef('seo')],
103+
},
104+
{
105+
slug: 'pwa',
106+
title: 'PWA',
107+
isBinary: true,
108+
refs: [lighthouseGroupRef('pwa')],
109+
},
87110
{
88111
slug: 'bug-prevention',
89112
title: 'Bug prevention',
@@ -145,7 +168,6 @@ const config: CoreConfig = {
145168
...fileSizeRecommendedRefs,
146169
packageJsonPerformanceGroupRef,
147170
packageJsonDocumentationGroupRef,
148-
// ...lighthouseCorePerfGroupRefs,
149171
],
150172
},
151173
],

e2e/cli-e2e/tests/__snapshots__/collect.e2e.test.ts.snap

+158
Original file line numberDiff line numberDiff line change
@@ -1696,3 +1696,161 @@ exports[`CLI collect > should run ESLint plugin and create report.json 1`] = `
16961696
],
16971697
}
16981698
`;
1699+
1700+
exports[`CLI collect > should run Lighthouse plugin that runs lighthouse CLI and creates report.json 1`] = `
1701+
{
1702+
"categories": [
1703+
{
1704+
"refs": [
1705+
{
1706+
"plugin": "lighthouse",
1707+
"slug": "performance",
1708+
"type": "group",
1709+
"weight": 1,
1710+
},
1711+
],
1712+
"slug": "performance",
1713+
"title": "Performance",
1714+
},
1715+
{
1716+
"refs": [
1717+
{
1718+
"plugin": "lighthouse",
1719+
"slug": "accessibility",
1720+
"type": "group",
1721+
"weight": 1,
1722+
},
1723+
],
1724+
"slug": "a11y",
1725+
"title": "Accessibility",
1726+
},
1727+
{
1728+
"refs": [
1729+
{
1730+
"plugin": "lighthouse",
1731+
"slug": "best-practices",
1732+
"type": "group",
1733+
"weight": 1,
1734+
},
1735+
],
1736+
"slug": "best-practices",
1737+
"title": "Best Practices",
1738+
},
1739+
{
1740+
"refs": [
1741+
{
1742+
"plugin": "lighthouse",
1743+
"slug": "seo",
1744+
"type": "group",
1745+
"weight": 1,
1746+
},
1747+
],
1748+
"slug": "seo",
1749+
"title": "SEO",
1750+
},
1751+
{
1752+
"isBinary": true,
1753+
"refs": [
1754+
{
1755+
"plugin": "lighthouse",
1756+
"slug": "pwa",
1757+
"type": "group",
1758+
"weight": 1,
1759+
},
1760+
],
1761+
"slug": "pwa",
1762+
"title": "PWA",
1763+
},
1764+
],
1765+
"packageName": "@code-pushup/core",
1766+
"plugins": [
1767+
{
1768+
"audits": [
1769+
{
1770+
"description": "Largest Contentful Paint marks the time at which the largest text or image is painted. [Learn more about the Largest Contentful Paint metric](https://developer.chrome.com/docs/lighthouse/performance/lighthouse-largest-contentful-paint/)",
1771+
"slug": "largest-contentful-paint",
1772+
"title": "Largest Contentful Paint",
1773+
},
1774+
{
1775+
"description": "Service worker is the technology that enables your app to use many Progressive Web App features, such as offline, add to homescreen, and push notifications. With proper service worker and manifest implementations, browsers can proactively prompt users to add your app to their homescreen, which can lead to higher engagement. [Learn more about manifest installability requirements](https://developer.chrome.com/docs/lighthouse/pwa/installable-manifest/).",
1776+
"slug": "installable-manifest",
1777+
"title": "Web app manifest and service worker meet the installability requirements",
1778+
},
1779+
{
1780+
"description": "Deprecated APIs will eventually be removed from the browser. [Learn more about deprecated APIs](https://developer.chrome.com/docs/lighthouse/best-practices/deprecations/).",
1781+
"slug": "deprecations",
1782+
"title": "Avoids deprecated APIs",
1783+
},
1784+
{
1785+
"description": "Each ARIA \`role\` supports a specific subset of \`aria-*\` attributes. Mismatching these invalidates the \`aria-*\` attributes. [Learn how to match ARIA attributes to their roles](https://dequeuniversity.com/rules/axe/4.8/aria-allowed-attr).",
1786+
"slug": "aria-allowed-attr",
1787+
"title": "\`[aria-*]\` attributes match their roles",
1788+
},
1789+
{
1790+
"description": "hreflang links tell search engines what version of a page they should list in search results for a given language or region. [Learn more about \`hreflang\`](https://developer.chrome.com/docs/lighthouse/seo/hreflang/).",
1791+
"slug": "hreflang",
1792+
"title": "Document has a valid \`hreflang\`",
1793+
},
1794+
],
1795+
"groups": [
1796+
{
1797+
"refs": [
1798+
{
1799+
"slug": "largest-contentful-paint",
1800+
"weight": 25,
1801+
},
1802+
],
1803+
"slug": "performance",
1804+
"title": "Performance",
1805+
},
1806+
{
1807+
"description": "These checks highlight opportunities to [improve the accessibility of your web app](https://developer.chrome.com/docs/lighthouse/accessibility/). Automatic detection can only detect a subset of issues and does not guarantee the accessibility of your web app, so [manual testing](https://web.dev/articles/how-to-review) is also encouraged.",
1808+
"refs": [
1809+
{
1810+
"slug": "aria-allowed-attr",
1811+
"weight": 10,
1812+
},
1813+
],
1814+
"slug": "accessibility",
1815+
"title": "Accessibility",
1816+
},
1817+
{
1818+
"refs": [
1819+
{
1820+
"slug": "deprecations",
1821+
"weight": 5,
1822+
},
1823+
],
1824+
"slug": "best-practices",
1825+
"title": "Best Practices",
1826+
},
1827+
{
1828+
"description": "These checks ensure that your page is following basic search engine optimization advice. There are many additional factors Lighthouse does not score here that may affect your search ranking, including performance on [Core Web Vitals](https://web.dev/explore/vitals). [Learn more about Google Search Essentials](https://support.google.com/webmasters/answer/35769).",
1829+
"refs": [
1830+
{
1831+
"slug": "hreflang",
1832+
"weight": 1,
1833+
},
1834+
],
1835+
"slug": "seo",
1836+
"title": "SEO",
1837+
},
1838+
{
1839+
"description": "These checks validate the aspects of a Progressive Web App. [Learn what makes a good Progressive Web App](https://web.dev/articles/pwa-checklist).",
1840+
"refs": [
1841+
{
1842+
"slug": "installable-manifest",
1843+
"weight": 2,
1844+
},
1845+
],
1846+
"slug": "pwa",
1847+
"title": "PWA",
1848+
},
1849+
],
1850+
"icon": "lighthouse",
1851+
"slug": "lighthouse",
1852+
"title": "Lighthouse",
1853+
},
1854+
],
1855+
}
1856+
`;

e2e/cli-e2e/tests/collect.e2e.test.ts

+46-8
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
import { dirname, join } from 'node:path';
22
import { fileURLToPath } from 'node:url';
3-
import { PluginReport, Report, reportSchema } from '@code-pushup/models';
3+
import {
4+
AuditReport,
5+
PluginReport,
6+
Report,
7+
reportSchema,
8+
} from '@code-pushup/models';
49
import { cleanTestFolder } from '@code-pushup/test-setup';
510
import { executeProcess, readJsonFile, readTextFile } from '@code-pushup/utils';
611

@@ -9,17 +14,35 @@ describe('CLI collect', () => {
914
const exampleAuditTitle = 'Disallow unused variables';
1015

1116
/* eslint-disable @typescript-eslint/no-unused-vars */
12-
const omitVariableData = ({
17+
const omitVariableAuditData = ({
18+
score,
19+
value,
20+
displayValue,
21+
...auditReport
22+
}: AuditReport) => auditReport;
23+
const omitVariablePluginData = ({
24+
date,
25+
duration,
26+
version,
27+
audits,
28+
...pluginReport
29+
}: PluginReport) =>
30+
({
31+
...pluginReport,
32+
audits: audits.map(
33+
pluginReport.slug === 'lighthouse' ? omitVariableAuditData : p => p,
34+
) as AuditReport[],
35+
} as PluginReport);
36+
const omitVariableReportData = ({
37+
commit,
1338
date,
1439
duration,
1540
version,
1641
...report
17-
}: Omit<Report, 'commit'> | PluginReport) => report;
18-
const omitVariableReportData = ({ commit, ...report }: Report) =>
19-
omitVariableData({
20-
...report,
21-
plugins: report.plugins.map(omitVariableData) as PluginReport[],
22-
});
42+
}: Report) => ({
43+
...report,
44+
plugins: report.plugins.map(omitVariablePluginData),
45+
});
2346
/* eslint-enable @typescript-eslint/no-unused-vars */
2447

2548
beforeEach(async () => {
@@ -95,6 +118,21 @@ describe('CLI collect', () => {
95118
expect(omitVariableReportData(report as Report)).toMatchSnapshot();
96119
});
97120

121+
it('should run Lighthouse plugin that runs lighthouse CLI and creates report.json', async () => {
122+
const { code, stderr } = await executeProcess({
123+
command: 'code-pushup',
124+
args: ['collect', '--no-progress', '--onlyPlugins=lighthouse'],
125+
cwd: 'examples/react-todos-app',
126+
});
127+
128+
expect(code).toBe(0);
129+
expect(stderr).toBe('');
130+
131+
const report = await readJsonFile('tmp/e2e/react-todos-app/report.json');
132+
expect(() => reportSchema.parse(report)).not.toThrow();
133+
expect(omitVariableReportData(report as Report)).toMatchSnapshot();
134+
});
135+
98136
it('should create report.md', async () => {
99137
const { code, stderr } = await executeProcess({
100138
command: 'code-pushup',

examples/react-todos-app/code-pushup.config.js

+44-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
import coveragePlugin from '../../dist/packages/plugin-coverage';
22
import eslintPlugin from '../../dist/packages/plugin-eslint';
3+
import lighthousePlugin, {
4+
lighthouseAuditRef,
5+
lighthouseGroupRef,
6+
} from '../../dist/packages/plugin-lighthouse';
37

48
const eslintAuditRef = (slug, weight) => ({
59
type: 'audit',
@@ -24,9 +28,48 @@ export default {
2428
eslintrc: '.eslintrc.js',
2529
patterns: ['src/**/*.js', 'src/**/*.jsx'],
2630
}),
31+
await lighthousePlugin('https://codepushup.dev/', {
32+
onlyAudits: [
33+
// performance category
34+
'largest-contentful-paint',
35+
// a11y category
36+
'aria-allowed-attr',
37+
// best-practices category
38+
'deprecations',
39+
// seo category
40+
'hreflang',
41+
// pwa category
42+
'installable-manifest',
43+
],
44+
}),
2745
],
2846
categories: [
29-
// TODO: add performance category once Lighthouse plugin implemented, include eslintAuditRef('react-jsx-key', 0)
47+
{
48+
slug: 'performance',
49+
title: 'Performance',
50+
refs: [lighthouseGroupRef('performance')],
51+
},
52+
{
53+
slug: 'a11y',
54+
title: 'Accessibility',
55+
refs: [lighthouseGroupRef('accessibility')],
56+
},
57+
{
58+
slug: 'best-practices',
59+
title: 'Best Practices',
60+
refs: [lighthouseGroupRef('best-practices')],
61+
},
62+
{
63+
slug: 'seo',
64+
title: 'SEO',
65+
refs: [lighthouseGroupRef('seo')],
66+
},
67+
{
68+
slug: 'pwa',
69+
title: 'PWA',
70+
isBinary: true,
71+
refs: [lighthouseGroupRef('pwa')],
72+
},
3073
{
3174
slug: 'code-coverage',
3275
title: 'Code coverage',

0 commit comments

Comments
 (0)