diff --git a/docs/redesign/phase-5/p5-15/p5-15-02/TEST_COVERAGE.md b/docs/redesign/phase-5/p5-15/p5-15-02/TEST_COVERAGE.md new file mode 100644 index 0000000..0eb513c --- /dev/null +++ b/docs/redesign/phase-5/p5-15/p5-15-02/TEST_COVERAGE.md @@ -0,0 +1,28 @@ +# P5-15-02 — Native audit coverage checkpoint + +This is test/evidence work only. No application, renderer, API, schema, provider, production configuration or deployment behavior changes. Source `cf847e9b256d9aec733abf3f37c42852c9dd2421`; development branch `codex/ui-redesign-phase4`. + +## New independently runnable coverage + +| Test file / case | Contract exercised | Evidence limitation | +|---|---|---| +| `responsive-accessibility-audit.spec.ts`: thirteen-area collection | Synthetic owned native SQLite/API entries, loaded content, responsive geometry, actual ARIA tree, all enabled axe rules plus explicit WCAG2.2 target-size, screenshots | Collection success is not accessibility acceptance; rule findings are retained rather than asserted away | +| Reduced-motion mobile drawer | Keyboard opening, expected initial focus, Escape return; records active element before/after axe and optional Tab recovery | Real keyboard automation, not a human reader | +| Command/workspace/CV keyboard | Command focus/empty result/Escape, Add dialog, manual-activation Job tabs, CV section selection, persisted keyboard reorder, preview entry/end-scroll/exit | Finite paths, not every field/menu or reader announcement | +| Landscape text-spacing collection | Six areas at844×390 with WCAG text-spacing overrides | Parent app styles only; verified document iframe geometry is untouched | +| CV source action | Actual keyboard activation of Open Career Profile, destination and native source content | Does not replace source/override revision safety tests | +| Upload/import keyboard | Focus and Enter/Space on three real controls; positive pointer comparison to the same native file picker | No file data submitted; no synthetic success response | +| Emulated touch | CV edit/preview, portrait/landscape CSS viewport changes, unchanged persisted CV, drawer Escape | Chromium touch emulation; not native hardware, orientation sensor or software keyboard | +| `browser-zoom-audit.spec.ts`: English/light and Bokmål/dark | Actual Chromium tab zoom100/200/400%; asserts browser zoom, DPR and unchanged pinch scale;13 areas plus text-spacing geometry | Geometry collection is not proof every enabled action is reachable/readable; other browsers/manual vision and hardware remain open | + +Nine ordinary browser cases are added (seven responsive/keyboard cases, two zoom cases). They are not skipped, quarantined, expected-failing or retried. Soft assertions keep known failures failing while collecting additional evidence. No provider requests leave loopback. + +## Focused execution before the coverage commit + +[Native proof](evidence/native-issues.json) retains source-report hashes, test statuses and actual observations. The six-case development audit after separating the drawer from other workflows had **2 passes /4 failures**; one failure was a test assumption: arrows move Job-tab focus, Enter activates. The corrected existing manual-activation contract then passed with command/dialog/CV keyboard checks in the three-case controls rerun (**1 pass /2 failures**). + +The two remaining controls failures are genuine: source action goes to unsupported `/career/profile` (404), and all six Enter/Space picker attempts fail while all three pointer comparisons succeed. No upload/import data was written. The reduced-motion drawer evidence shows focus still on the hidden background trigger before and after axe; immediate Escape leaves the drawer open. Tab plus Escape can close it, but focus lands on another background button rather than returning to the navigation trigger. Emulated CV mode/portrait-landscape/readback succeeds before the same drawer-return assertion fails. + +Genuine zoom collection **2/2 passes**,102 geometry observations. Earlier zoom harness attempts are retained locally: explicit `deviceScaleFactor:undefined` is required with `viewport:null`; Correspondence has two actual H1s, so readiness now identifies its intended inbox heading exactly while still recording both headings. Those harness corrections do not close product heading/manual-review issues. Earlier metadata incorrectly implied tag-only axe selection: installed builder `.options()` replaces earlier `.withTags()` options. The committed collector correctly declares **all enabled rules**, including best practices; per-rule tags distinguish them from WCAG failures. + +App and E2E TypeScript, lint and whitespace checks pass. Complete ordinary regression and final rule/viewport/57-group reconciliation are separate pending audit evidence at this commit; neither the previous134 passes nor collection success is used to claim this audit green. Production remains NO-GO. P5-13 remains deferred, unqualified and Production-withheld; no UI/qualification/Docker work. diff --git a/docs/redesign/phase-5/p5-15/p5-15-02/evidence/native-issues.json b/docs/redesign/phase-5/p5-15/p5-15-02/evidence/native-issues.json new file mode 100644 index 0000000..e13f4df --- /dev/null +++ b/docs/redesign/phase-5/p5-15/p5-15-02/evidence/native-issues.json @@ -0,0 +1,232 @@ +{ + "scope": "Native synthetic owned SQLite/browser evidence; no human AT/device acceptance", + "reports": [ + { + "source": ".artifacts/p5-15-02/browser/audit-attempt3.json", + "sha256": "89af6297f09ad03072e5a617e0e4b0dd55cd8ebe1a8b310872525a8d1d81319d", + "stats": { + "startTime": "2026-10-10T18:25:41.491Z", + "duration": 197611.17, + "expected": 2, + "skipped": 0, + "unexpected": 4, + "flaky": 0 + }, + "tests": [ + { + "name": "[P5-15-02] reduced-motion mobile drawer enters focus and Escape returns it", + "status": "failed", + "errorMessages": [ + "Error: \u001b[2mexpect(\u001b[22m\u001b[31mlocator\u001b[39m\u001b[2m).\u001b[22mtoBeFocused\u001b[2m(\u001b[22m\u001b[2m)\u001b[22m failed\n\nLocator: getByRole('dialog', { name: 'Navigation', exact: true }).getByRole('button', { name: 'Dashboard', exact: true })\nExpected: focused\nReceived: inactive\nTimeout: 5000ms\n\nCall log:\n\u001b[2m - Expect \"soft toBeFocused\" with timeout 5000ms\u001b[22m\n\u001b[2m - waiting for getByRole('dialog', { name: 'Navigation', exact: true }).getByRole('button', { name: 'Dashboard', exact: true })\u001b[22m\n\u001b[2m 12 × locator resolved to
…
\u001b[22m\n\u001b[2m - unexpected value \"inactive\"\u001b[22m\n\n\n 189 | await navigation.focus(); await navigation.press('Enter');\n 190 | const drawer = page.getByRole('dialog', { name: t.navigation, exact: true });\n> 191 | await expect.soft(drawer.getByRole('button', { name: t.dashboard, exact: true })).toBeFocused();\n | ^\n 192 | const focus = () => page.evaluate(() => ({ active: document.activeElement?.outerHTML.slice(0, 500), focusedInDialog: !!document.activeElement?.closest('[role=dialog]') }));\n 193 | const beforeScan = await focus();\n 194 | await collect(page, info, sample, 'navigation-open');\n at E:\\Storage\\Projects\\Active\\Job tracker\\job-tracker-ui\\e2e\\responsive-accessibility-audit.spec.ts:191:85", + "Error: \u001b[2mexpect(\u001b[22m\u001b[31mlocator\u001b[39m\u001b[2m).\u001b[22mtoBeFocused\u001b[2m(\u001b[22m\u001b[2m)\u001b[22m failed\n\nLocator: getByRole('button', { name: 'Open navigation', exact: true })\nExpected: focused\nTimeout: 5000ms\nError: element(s) not found\n\nCall log:\n\u001b[2m - Expect \"soft toBeFocused\" with timeout 5000ms\u001b[22m\n\u001b[2m - waiting for getByRole('button', { name: 'Open navigation', exact: true })\u001b[22m\n\n\n 194 | await collect(page, info, sample, 'navigation-open');\n 195 | const afterScan = await focus();\n> 196 | await page.keyboard.press('Escape'); await expect.soft(navigation).toBeFocused();\n | ^\n 197 | const afterEscape = await focus();\n 198 | const stayedOpen = await drawer.isVisible();\n 199 | if (stayedOpen) {\n at E:\\Storage\\Projects\\Active\\Job tracker\\job-tracker-ui\\e2e\\responsive-accessibility-audit.spec.ts:196:70" + ], + "observations": [ + { + "name": "drawer-focus-recovery", + "value": { + "beforeScan": { + "active": "