test(web): add axe-core WCAG AA accessibility tests (ATB-34) (#71)
* docs: ATB-34 axe-core a11y testing design
Captures the approved design for adding axe-core + jsdom automated
accessibility tests to apps/web — single consolidated test file,
per-file jsdom environment pragma, one happy-path test per page route.
* docs: ATB-34 axe-core a11y implementation plan
Step-by-step plan: add axe-core + jsdom deps, create consolidated test
file with jsdom env pragma, one happy-path WCAG AA test per page route.
* chore(web): add axe-core, jsdom, vitest as explicit devDependencies (ATB-34)
* test(web): scaffold a11y test file with jsdom environment and module mocks (ATB-34)
* test(web): add WCAG AA accessibility tests for all page routes (ATB-34)
* test(web): suppress document.write deprecation with explanatory comment (ATB-34)
* test(web): use @ts-ignore to suppress deprecated document.write diagnostic (ATB-34)
* docs: move ATB-34 plan docs to complete
* test(web): address PR review feedback on a11y tests (ATB-34)
- Fix DOMParser comment to explain axe isPageContext() mechanism accurately
- Add DOM replacement guard after document.write() to catch silent no-ops
- Wrap axe.run() in try/catch with routeLabel for infrastructure error context
- Add routeLabel param to checkA11y; update all 6 call sites
- Reset canLockTopics/canModeratePosts/canBanUsers in beforeEach
- Add afterEach DOM cleanup via documentElement.innerHTML
- Fix path.startsWith('/topics/1') to exact match '/topics/1?offset=0&limit=25'
- Add form presence guard in new-topic test to catch silent auth fallback
- Update design doc to document DOMParser divergence and its reason
* test(web): strengthen DOM write guard to check html[lang] (ATB-34)
afterEach now removes lang from <html> so the guard in checkA11y can use
html[lang] as proof that document.write() actually executed, rather than
just checking that the <html> element exists (which it always does after
afterEach resets innerHTML without touching attributes).