feat(a11y): add axe-core Playwright scorecard for 10 key routes

- Installs @axe-core/playwright at workspace root
- Creates e2e/a11y/scorecard.spec.ts scanning /, /search, /listings/[id],
  /listings/create, /login, /register, /dashboard, /agent/[id],
  /inquiries, /admin/moderation
- API mock layer lets pages render with stubbed JSON so axe sees real DOM
- Critical/serious violations fail the build; moderate/minor are recorded only
- Writes per-route JSON reports to e2e/a11y/reports/ (committed for before/after diffing in PRs)
- Adds dedicated "a11y" Playwright project in playwright.config.ts
- Pre-existing API unit test failures are unrelated to this change

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
Ho Ngoc Hai
2026-04-24 10:41:42 +07:00
parent ec066dfa28
commit 8a15df0bdb
5 changed files with 216 additions and 9 deletions

28
pnpm-lock.yaml generated
View File

@@ -18,6 +18,9 @@ importers:
specifier: ^7.7.0
version: 7.7.0(prisma@7.7.0(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@6.0.2))(typescript@6.0.2)
devDependencies:
'@axe-core/playwright':
specifier: ^4.11.2
version: 4.11.2(playwright-core@1.59.1)
'@eslint/js':
specifier: ^9.39.4
version: 9.39.4
@@ -168,9 +171,6 @@ importers:
class-validator:
specifier: ^0.15.1
version: 0.15.1
cockatiel:
specifier: ^3.2.1
version: 3.2.1
cookie-parser:
specifier: ^1.4.7
version: 1.4.7
@@ -662,6 +662,11 @@ packages:
resolution: {integrity: sha512-iY8yvjE0y651BixKNPgmv1WrQc+GZ142sb0z4gYnChDDY2YqI4P/jsSopBWrKfAt7LOJAkOXt7rC/hms+WclQQ==}
engines: {node: '>=18.0.0'}
'@axe-core/playwright@4.11.2':
resolution: {integrity: sha512-iP6hfNl9G0j/SEUSo8M7D80RbcDo9KRAAfDP4IT5OHB+Wm6zUHIrm8Y51BKI+Oyqduvipf9u1hcRy57zCBKzWQ==}
peerDependencies:
playwright-core: '>= 1.0.0'
'@babel/code-frame@7.29.0':
resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==}
engines: {node: '>=6.9.0'}
@@ -3744,6 +3749,10 @@ packages:
resolution: {integrity: sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g==}
engines: {node: '>= 6.0.0'}
axe-core@4.11.3:
resolution: {integrity: sha512-zBQouZixDTbo3jMGqHKyePxYxr1e5W8UdTmBQ7sNtaA9M2bE32daxxPLS/jojhKOHxQ7LWwPjfiwf/fhaJWzlg==}
engines: {node: '>=4'}
axios@1.15.0:
resolution: {integrity: sha512-wWyJDlAatxk30ZJer+GeCWS209sA42X+N5jU2jy6oHTp7ufw8uzUTVFBX9+wTfAlhiJXGS0Bq7X6efruWjuK9Q==}
@@ -4046,10 +4055,6 @@ packages:
resolution: {integrity: sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==}
engines: {node: '>=0.10.0'}
cockatiel@3.2.1:
resolution: {integrity: sha512-gfrHV6ZPkquExvMh9IOkKsBzNDk6sDuZ6DdBGUBkvFnTCqCxzpuq48RySgP0AnaqQkw2zynOFj9yly6T1Q2G5Q==}
engines: {node: '>=16'}
color-convert@2.0.1:
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
engines: {node: '>=7.0.0'}
@@ -7880,6 +7885,11 @@ snapshots:
'@aws/lambda-invoke-store@0.2.4': {}
'@axe-core/playwright@4.11.2(playwright-core@1.59.1)':
dependencies:
axe-core: 4.11.3
playwright-core: 1.59.1
'@babel/code-frame@7.29.0':
dependencies:
'@babel/helper-validator-identifier': 7.28.5
@@ -11136,6 +11146,8 @@ snapshots:
aws-ssl-profiles@1.1.2: {}
axe-core@4.11.3: {}
axios@1.15.0:
dependencies:
follow-redirects: 1.15.11
@@ -11447,8 +11459,6 @@ snapshots:
cluster-key-slot@1.1.2: {}
cockatiel@3.2.1: {}
color-convert@2.0.1:
dependencies:
color-name: 1.1.4