From 62b9475a2714fcdaede4e0f0cd3acb6d7266050c Mon Sep 17 00:00:00 2001 From: Daniel Roe Date: Tue, 27 Jan 2026 21:04:17 +0000 Subject: [PATCH 1/5] ci: run lighthouse a11y tests in both light + dark mode --- .github/workflows/ci.yml | 4 ++-- .lighthouserc.json | 1 + lighthouse-setup.js | 28 ++++++++++++++++++++++++++++ scripts/lighthouse-a11y.sh | 18 ++++++++++++++++++ 4 files changed, 49 insertions(+), 2 deletions(-) create mode 100644 lighthouse-setup.js create mode 100755 scripts/lighthouse-a11y.sh diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e686ad6999..46a5ec927a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -91,7 +91,7 @@ jobs: - name: 🏗️ Build project run: pnpm build - - name: ♿ Accessibility audit (Lighthouse) - run: pnpx @lhci/cli autorun + - name: ♿ Accessibility audit (Lighthouse - dark & light mode) + run: ./scripts/lighthouse-a11y.sh env: LHCI_GITHUB_APP_TOKEN: ${{ secrets.LHCI_GITHUB_APP_TOKEN }} diff --git a/.lighthouserc.json b/.lighthouserc.json index 9ad5381fe5..1fc7bd192d 100644 --- a/.lighthouserc.json +++ b/.lighthouserc.json @@ -9,6 +9,7 @@ "http://localhost:3000/nuxt" ], "numberOfRuns": 1, + "puppeteerScript": "./lighthouse-setup.js", "settings": { "onlyCategories": ["accessibility"], "skipAudits": ["valid-source-maps"] diff --git a/lighthouse-setup.js b/lighthouse-setup.js new file mode 100644 index 0000000000..2879a850fc --- /dev/null +++ b/lighthouse-setup.js @@ -0,0 +1,28 @@ +/** + * Lighthouse CI puppeteer setup script. + * Sets the color mode (light/dark) before running accessibility audits. + * + * The color mode is determined by the LIGHTHOUSE_COLOR_MODE environment variable. + * If not set, defaults to 'dark'. + */ + +/** @param {import('puppeteer').Browser} browser */ +export default async function setup(browser, { url }) { + const colorMode = process.env.LIGHTHOUSE_COLOR_MODE || 'dark' + const page = await browser.newPage() + + // Set localStorage before navigating so @nuxtjs/color-mode picks it up + await page.evaluateOnNewDocument(mode => { + localStorage.setItem('npmx-color-mode', mode) + }, colorMode) + + await page.goto(url, { waitUntil: 'networkidle0' }) + + // Also set the data-theme attribute directly to ensure the mode is applied + await page.evaluate(mode => { + document.documentElement.setAttribute('data-theme', mode) + }, colorMode) + + // Close the page - Lighthouse will open its own + await page.close() +} diff --git a/scripts/lighthouse-a11y.sh b/scripts/lighthouse-a11y.sh new file mode 100755 index 0000000000..61f38724fa --- /dev/null +++ b/scripts/lighthouse-a11y.sh @@ -0,0 +1,18 @@ +#!/bin/bash +# Run Lighthouse accessibility tests in both light and dark mode +# +# This script runs lhci autorun twice, once for each color mode. +# The LIGHTHOUSE_COLOR_MODE env var is read by lighthouse-setup.js +# to set the appropriate theme before each audit. + +set -e + +echo "🌙 Running Lighthouse accessibility audit (dark mode)..." +LIGHTHOUSE_COLOR_MODE=dark pnpx @lhci/cli autorun + +echo "" +echo "☀️ Running Lighthouse accessibility audit (light mode)..." +LIGHTHOUSE_COLOR_MODE=light pnpx @lhci/cli autorun + +echo "" +echo "✅ Accessibility audits completed for both color modes" From 1bb0c8a841a9dfce29f1548679f40be65c68b4b0 Mon Sep 17 00:00:00 2001 From: Daniel Roe Date: Tue, 27 Jan 2026 21:19:20 +0000 Subject: [PATCH 2/5] chore: add a helper lighthouse script --- .lighthouserc.cjs | 51 +++++++++++++++++++++ .lighthouserc.json | 27 ----------- lighthouse-setup.js => lighthouse-setup.cjs | 2 +- scripts/lighthouse-a11y.sh | 2 +- 4 files changed, 53 insertions(+), 29 deletions(-) create mode 100644 .lighthouserc.cjs delete mode 100644 .lighthouserc.json rename lighthouse-setup.js => lighthouse-setup.cjs (93%) diff --git a/.lighthouserc.cjs b/.lighthouserc.cjs new file mode 100644 index 0000000000..adb5ffe57f --- /dev/null +++ b/.lighthouserc.cjs @@ -0,0 +1,51 @@ +const fs = require('fs') + +// Auto-detect Chrome executable path +function findChrome() { + const paths = [ + // Linux + '/usr/bin/google-chrome-stable', + '/usr/bin/google-chrome', + '/usr/bin/chromium-browser', + // macOS + '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome', + // Windows + 'C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe', + 'C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe', + ] + + for (const p of paths) { + if (fs.existsSync(p)) return p + } + + return undefined +} + +module.exports = { + ci: { + collect: { + startServerCommand: 'pnpm preview', + startServerReadyPattern: 'Listening', + url: [ + 'http://localhost:3000/', + 'http://localhost:3000/search?q=nuxt', + 'http://localhost:3000/nuxt', + ], + numberOfRuns: 1, + chromePath: findChrome(), + puppeteerScript: './lighthouse-setup.cjs', + settings: { + onlyCategories: ['accessibility'], + skipAudits: ['valid-source-maps'], + }, + }, + assert: { + assertions: { + 'categories:accessibility': ['warn', { minScore: 1 }], + }, + }, + upload: { + target: 'temporary-public-storage', + }, + }, +} diff --git a/.lighthouserc.json b/.lighthouserc.json deleted file mode 100644 index 1fc7bd192d..0000000000 --- a/.lighthouserc.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "ci": { - "collect": { - "startServerCommand": "pnpm preview", - "startServerReadyPattern": "Listening", - "url": [ - "http://localhost:3000/", - "http://localhost:3000/search?q=nuxt", - "http://localhost:3000/nuxt" - ], - "numberOfRuns": 1, - "puppeteerScript": "./lighthouse-setup.js", - "settings": { - "onlyCategories": ["accessibility"], - "skipAudits": ["valid-source-maps"] - } - }, - "assert": { - "assertions": { - "categories:accessibility": ["warn", { "minScore": 1 }] - } - }, - "upload": { - "target": "temporary-public-storage" - } - } -} diff --git a/lighthouse-setup.js b/lighthouse-setup.cjs similarity index 93% rename from lighthouse-setup.js rename to lighthouse-setup.cjs index 2879a850fc..a9031735b5 100644 --- a/lighthouse-setup.js +++ b/lighthouse-setup.cjs @@ -7,7 +7,7 @@ */ /** @param {import('puppeteer').Browser} browser */ -export default async function setup(browser, { url }) { +module.exports = async function setup(browser, { url }) { const colorMode = process.env.LIGHTHOUSE_COLOR_MODE || 'dark' const page = await browser.newPage() diff --git a/scripts/lighthouse-a11y.sh b/scripts/lighthouse-a11y.sh index 61f38724fa..b2d7ed5b3c 100755 --- a/scripts/lighthouse-a11y.sh +++ b/scripts/lighthouse-a11y.sh @@ -2,7 +2,7 @@ # Run Lighthouse accessibility tests in both light and dark mode # # This script runs lhci autorun twice, once for each color mode. -# The LIGHTHOUSE_COLOR_MODE env var is read by lighthouse-setup.js +# The LIGHTHOUSE_COLOR_MODE env var is read by lighthouse-setup.cjs # to set the appropriate theme before each audit. set -e From ffe964be790ecee9aa38d58edcb620f7c268a62f Mon Sep 17 00:00:00 2001 From: Daniel Roe Date: Tue, 27 Jan 2026 21:23:18 +0000 Subject: [PATCH 3/5] chore: simplify --- lighthouse-setup.cjs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/lighthouse-setup.cjs b/lighthouse-setup.cjs index a9031735b5..5576d96606 100644 --- a/lighthouse-setup.cjs +++ b/lighthouse-setup.cjs @@ -16,13 +16,9 @@ module.exports = async function setup(browser, { url }) { localStorage.setItem('npmx-color-mode', mode) }, colorMode) - await page.goto(url, { waitUntil: 'networkidle0' }) + // Navigate and wait for DOM only - Lighthouse will do its own full load + await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 60000 }) - // Also set the data-theme attribute directly to ensure the mode is applied - await page.evaluate(mode => { - document.documentElement.setAttribute('data-theme', mode) - }, colorMode) - - // Close the page - Lighthouse will open its own + // Close the page - Lighthouse will open its own with localStorage already set await page.close() } From 868e4b4b103bbb8793980d64b855e9900d9fefe0 Mon Sep 17 00:00:00 2001 From: Daniel Roe Date: Tue, 27 Jan 2026 21:29:31 +0000 Subject: [PATCH 4/5] ci: fail if <100% --- .lighthouserc.cjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.lighthouserc.cjs b/.lighthouserc.cjs index adb5ffe57f..5c4ba55894 100644 --- a/.lighthouserc.cjs +++ b/.lighthouserc.cjs @@ -41,7 +41,7 @@ module.exports = { }, assert: { assertions: { - 'categories:accessibility': ['warn', { minScore: 1 }], + 'categories:accessibility': ['error', { minScore: 1 }], }, }, upload: { From 2e30b9f68f1da368ea23979f746c870d1915721f Mon Sep 17 00:00:00 2001 From: Daniel Roe Date: Tue, 27 Jan 2026 21:29:39 +0000 Subject: [PATCH 5/5] chore: add unique suffix for statuses --- scripts/lighthouse-a11y.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/lighthouse-a11y.sh b/scripts/lighthouse-a11y.sh index b2d7ed5b3c..2ab4dd1039 100755 --- a/scripts/lighthouse-a11y.sh +++ b/scripts/lighthouse-a11y.sh @@ -8,11 +8,11 @@ set -e echo "🌙 Running Lighthouse accessibility audit (dark mode)..." -LIGHTHOUSE_COLOR_MODE=dark pnpx @lhci/cli autorun +LIGHTHOUSE_COLOR_MODE=dark pnpx @lhci/cli autorun --upload.githubStatusContextSuffix="/dark" echo "" echo "☀️ Running Lighthouse accessibility audit (light mode)..." -LIGHTHOUSE_COLOR_MODE=light pnpx @lhci/cli autorun +LIGHTHOUSE_COLOR_MODE=light pnpx @lhci/cli autorun --upload.githubStatusContextSuffix="/light" echo "" echo "✅ Accessibility audits completed for both color modes"