Skip to content

Commit 4e889c2

Browse files
committed
test: mock client side requests in lighthouse
1 parent 16b012a commit 4e889c2

File tree

6 files changed

+593
-449
lines changed

6 files changed

+593
-449
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ jobs:
184184
run: pnpm build:test
185185

186186
- name: ♿ Accessibility audit (Lighthouse - ${{ matrix.mode }} mode)
187-
run: ./scripts/lighthouse-a11y.sh
187+
run: pnpm test:a11y:prebuilt
188188
env:
189189
LHCI_GITHUB_APP_TOKEN: ${{ secrets.LHCI_GITHUB_APP_TOKEN }}
190190
LIGHTHOUSE_COLOR_MODE: ${{ matrix.mode }}

CONTRIBUTING.md

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ This focus helps guide our project decisions as a community and what we choose t
5252
- [Testing](#testing)
5353
- [Unit tests](#unit-tests)
5454
- [Component accessibility tests](#component-accessibility-tests)
55+
- [Lighthouse accessibility tests](#lighthouse-accessibility-tests)
5556
- [End to end tests](#end-to-end-tests)
5657
- [Test fixtures (mocking external APIs)](#test-fixtures-mocking-external-apis)
5758
- [Submitting changes](#submitting-changes)
@@ -111,6 +112,7 @@ pnpm test # Run all Vitest tests
111112
pnpm test:unit # Unit tests only
112113
pnpm test:nuxt # Nuxt component tests
113114
pnpm test:browser # Playwright E2E tests
115+
pnpm test:a11y # Lighthouse accessibility audits
114116
```
115117

116118
### Project structure
@@ -598,6 +600,40 @@ A coverage test in `test/unit/a11y-component-coverage.spec.ts` ensures all compo
598600
> [!IMPORTANT]
599601
> Just because axe-core doesn't find any obvious issues, it does not mean a component is accessible. Please do additional checks and use best practices.
600602
603+
### Lighthouse accessibility tests
604+
605+
In addition to component-level axe audits, the project runs full-page accessibility audits using [Lighthouse CI](https://github.com/GoogleChrome/lighthouse-ci). These test the rendered pages in both light and dark mode against Lighthouse's accessibility category, requiring a perfect score.
606+
607+
#### How it works
608+
609+
1. The project is built in test mode (`pnpm build:test`), which activates server-side fixture mocking
610+
2. Lighthouse CI starts a preview server and audits three URLs: `/`, `/search?q=nuxt`, and `/package/nuxt`
611+
3. A Puppeteer setup script (`lighthouse-setup.cjs`) runs before each audit to set the color mode and intercept client-side API requests using the same fixtures as the E2E tests
612+
613+
#### Running locally
614+
615+
```bash
616+
# Build + run both light and dark audits
617+
pnpm test:a11y
618+
619+
# Or against an existing test build
620+
pnpm test:a11y:prebuilt
621+
622+
# Or run a single color mode manually
623+
pnpm build:test
624+
LIGHTHOUSE_COLOR_MODE=dark ./scripts/lighthouse-a11y.sh
625+
```
626+
627+
This requires Chrome or Chromium to be installed. The script will auto-detect common installation paths. Results are printed to the terminal and saved in `.lighthouseci/`.
628+
629+
#### Configuration
630+
631+
| File | Purpose |
632+
| ---------------------------- | --------------------------------------------------------- |
633+
| `.lighthouserc.cjs` | Lighthouse CI config (URLs, assertions, Chrome path) |
634+
| `lighthouse-setup.cjs` | Puppeteer script for color mode + client-side API mocking |
635+
| `scripts/lighthouse-a11y.sh` | Shell wrapper that runs the audit for a given color mode |
636+
601637
### End to end tests
602638

603639
Write end-to-end tests using Playwright:
@@ -619,10 +655,12 @@ E2E tests use a fixture system to mock external API requests, ensuring tests are
619655
- Serves pre-recorded fixture data from `test/fixtures/`
620656
- Enabled via `NUXT_TEST_FIXTURES=true` or Nuxt test mode
621657

622-
**Client-side mocking** (`test/e2e/test-utils.ts`):
658+
**Client-side mocking** (`test/fixtures/mock-routes.cjs`):
623659

624-
- Uses Playwright's route interception to mock browser requests
625-
- All test files import from `./test-utils` instead of `@nuxt/test-utils/playwright`
660+
- Shared URL matching and response generation logic used by both Playwright E2E tests and Lighthouse CI
661+
- Playwright tests (`test/e2e/test-utils.ts`) use this via `page.route()` interception
662+
- Lighthouse tests (`lighthouse-setup.cjs`) use this via Puppeteer request interception
663+
- All E2E test files import from `./test-utils` instead of `@nuxt/test-utils/playwright`
626664
- Throws a clear error if an unmocked external request is detected
627665

628666
#### Fixture files
@@ -670,7 +708,7 @@ URL: https://registry.npmjs.org/some-package
670708
You need to either:
671709

672710
1. Add a fixture file for that package/endpoint
673-
2. Update the mock handlers in `test/e2e/test-utils.ts` (client) or `modules/runtime/server/cache.ts` (server)
711+
2. Update the mock handlers in `test/fixtures/mock-routes.cjs` (client) or `modules/runtime/server/cache.ts` (server)
674712

675713
## Submitting changes
676714

lighthouse-setup.cjs

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,26 @@
11
/**
22
* Lighthouse CI puppeteer setup script.
3-
* Sets the color mode (light/dark) before running accessibility audits.
3+
*
4+
* Sets the color mode (light/dark) before running accessibility audits
5+
* and intercepts client-side API requests using the same fixture data
6+
* as the Playwright E2E tests.
47
*
58
* The color mode is determined by the LIGHTHOUSE_COLOR_MODE environment variable.
69
* If not set, defaults to 'dark'.
10+
*
11+
* Request interception uses CDP (Chrome DevTools Protocol) at the browser level
12+
* so it applies to all pages Lighthouse opens, not just the setup page.
713
*/
814

15+
const mockRoutes = require('./test/fixtures/mock-routes.cjs')
16+
917
module.exports = async function setup(browser, { url }) {
1018
const colorMode = process.env.LIGHTHOUSE_COLOR_MODE || 'dark'
19+
20+
// Set up browser-level request interception via CDP.
21+
// This ensures mocking applies to pages Lighthouse creates after setup.
22+
setupBrowserRequestInterception(browser)
23+
1124
const page = await browser.newPage()
1225

1326
// Set localStorage before navigating so @nuxtjs/color-mode picks it up
@@ -21,3 +34,40 @@ module.exports = async function setup(browser, { url }) {
2134
// Close the page - Lighthouse will open its own with localStorage already set
2235
await page.close()
2336
}
37+
38+
/**
39+
* Set up request interception on every new page target the browser creates.
40+
* Uses Puppeteer's page-level request interception, applied automatically
41+
* to each new page via the 'targetcreated' event.
42+
*
43+
* @param {import('puppeteer').Browser} browser
44+
*/
45+
function setupBrowserRequestInterception(browser) {
46+
browser.on('targetcreated', async target => {
47+
if (target.type() !== 'page') return
48+
49+
try {
50+
const page = await target.page()
51+
if (!page) return
52+
53+
await page.setRequestInterception(true)
54+
page.on('request', request => {
55+
const requestUrl = request.url()
56+
const result = mockRoutes.matchRoute(requestUrl)
57+
58+
if (result) {
59+
request.respond({
60+
status: result.response.status,
61+
contentType: result.response.contentType,
62+
body: result.response.body,
63+
})
64+
} else {
65+
request.continue()
66+
}
67+
})
68+
} catch {
69+
// Target may have been closed before we could set up interception.
70+
// This is expected for transient targets like service workers.
71+
}
72+
})
73+
}

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131
"generate:fixtures": "node scripts/generate-fixtures.ts",
3232
"generate:lexicons": "lex build --lexicons lexicons --out shared/types/lexicons --clear",
3333
"test": "vite test",
34+
"test:a11y": "pnpm build:test && pnpm test:a11y:prebuilt",
35+
"test:a11y:prebuilt": "LIGHTHOUSE_COLOR_MODE=dark ./scripts/lighthouse-a11y.sh && LIGHTHOUSE_COLOR_MODE=light ./scripts/lighthouse-a11y.sh",
3436
"test:browser": "pnpm build:test && pnpm test:browser:prebuilt",
3537
"test:browser:prebuilt": "playwright test",
3638
"test:browser:ui": "pnpm build:test && pnpm test:browser:prebuilt --ui",

0 commit comments

Comments
 (0)