Files
defiQUGandCursor 6c0de165d3 P0: mim-api, live conversion paths, and CWV sprint to ~2.56s LCP.
Ship VMID 7811 API (assistance, contact, Stripe checkout), wire donate and forms to API with accessible success UI, static LCP shell with deferred React mount, and perf gate tooling (P0 72/2600ms; world-class 85/2500ms tracked separately).

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-15 23:42:45 -07:00

79 lines
2.5 KiB
JavaScript

#!/usr/bin/env node
/**
* Full-site Lighthouse accessibility audit (live URL).
* Usage: node scripts/a11y/audit-site-lighthouse.mjs [--url=https://mim4u.org]
*/
import { spawnSync } from 'node:child_process'
import { mkdirSync, readFileSync, writeFileSync } from 'node:fs'
import { dirname, join } from 'node:path'
import { fileURLToPath } from 'node:url'
const __dirname = dirname(fileURLToPath(import.meta.url))
const repoRoot = join(__dirname, '../..')
const outDir = join(repoRoot, 'reports/status')
const urlArg = process.argv.find((a) => a.startsWith('--url='))
const url = urlArg ? urlArg.split('=')[1] : 'https://mim4u.org'
const lhOut = join(outDir, 'lighthouse-site-a11y-latest.json')
mkdirSync(outDir, { recursive: true })
const chromePath = process.env.CHROME_PATH || '/usr/bin/google-chrome'
const result = spawnSync(
'npx',
[
'--yes',
'lighthouse',
url,
'--only-categories=accessibility,performance,best-practices,seo',
'--skip-audits=full-page-screenshot,screenshot-thumbnails',
'--output=json',
`--output-path=${lhOut}`,
'--chrome-flags=--headless --no-sandbox',
],
{
cwd: repoRoot,
env: { ...process.env, CHROME_PATH: chromePath },
encoding: 'utf8',
stdio: ['ignore', 'pipe', 'pipe'],
}
)
if (result.status !== 0 && !readFileSync(lhOut, 'utf8').includes('"categories"')) {
console.error((result.stderr || result.stdout || 'Lighthouse failed').trim())
process.exit(1)
}
const raw = JSON.parse(readFileSync(lhOut, 'utf8'))
const scores = Object.fromEntries(
Object.entries(raw.categories).map(([k, v]) => [k, Math.round(v.score * 100)])
)
const failing = raw.categories.accessibility.auditRefs
.filter((ref) => {
const audit = raw.audits[ref.id]
return audit && audit.score !== null && audit.score < 1
})
.map((ref) => ({ id: ref.id, title: raw.audits[ref.id].title }))
const report = {
schemaVersion: '1.0.0',
assessmentDate: new Date().toISOString().slice(0, 10),
url,
scores,
lcpMs: raw.audits['largest-contentful-paint']?.numericValue
? Math.round(raw.audits['largest-contentful-paint'].numericValue)
: undefined,
accessibilityFailingAudits: failing,
reportPath: lhOut,
}
const outPath = join(outDir, 'mim4u-site-lighthouse-latest.json')
writeFileSync(outPath, `${JSON.stringify(report, null, 2)}\n`)
console.log('Lighthouse scores:', scores)
if (failing.length) {
failing.forEach((f) => console.log(` a11y FAIL: ${f.id}${f.title}`))
}
console.log(`Report: ${outPath}`)
process.exit(scores.accessibility >= 95 ? 0 : 1)