diff --git a/docs/branch-review-records/d545333169b6e7645c813d4f760bcc8d901cef851b57bccb7874d8d6ff114f54.record.md b/docs/branch-review-records/d545333169b6e7645c813d4f760bcc8d901cef851b57bccb7874d8d6ff114f54.record.md new file mode 100644 index 0000000000..abaf23f90b --- /dev/null +++ b/docs/branch-review-records/d545333169b6e7645c813d4f760bcc8d901cef851b57bccb7874d8d6ff114f54.record.md @@ -0,0 +1 @@ +| 2026-08-16 | codex/chat-browser-evidence-235-238-browser-evidence-235-238 | 2d0126d6dd3b3727e8a99549a5e0d3678039960c | PR #2006 AccessibleTable low-confidence 320px mockup journey | No high-confidence PR-introduced defects found; branch required a non-overlapping latest-main merge | Distinct manual adversarial source-contract pass and deterministic normalizer proof passed; exact-head PR required, static, build, unit coverage, Production UI, Advisory UI, SAST, and Secret Scan passed | diff --git a/docs/design-system/adoption-manifest.json b/docs/design-system/adoption-manifest.json index 28d8af2866..1eafffd1c2 100644 --- a/docs/design-system/adoption-manifest.json +++ b/docs/design-system/adoption-manifest.json @@ -112,6 +112,7 @@ "tests/accessible-table.dom.test.tsx", "tests/design-sync-visual-exports.test.ts", "tests/design-system-adoption.test.ts", + "tests/ui-tools.spec.ts", "tests/ward-output.test.ts" ], "baseline": { diff --git a/docs/site-map.md b/docs/site-map.md index d76c558633..c0282f85c6 100644 --- a/docs/site-map.md +++ b/docs/site-map.md @@ -985,6 +985,7 @@ This file is generated by `npm run docs:update` (or `npm run sitemap:update` dir ## Mockup/prototype routes +- `/mockups/accessible-table-browser-fixture` - Route discovered from app directory Source: `src/app/mockups/accessible-table-browser-fixture/page.tsx`. - `/mockups/answer-evidence-popups` - Route discovered from app directory Source: `src/app/mockups/answer-evidence-popups/page.tsx`. - `/mockups/answer-home-proposal` - Route discovered from app directory Source: `src/app/mockups/answer-home-proposal/page.tsx`. - `/mockups/calculators-bedside-sheet` - Route discovered from app directory Source: `src/app/mockups/calculators-bedside-sheet/page.tsx`. diff --git a/src/app/mockups/accessible-table-browser-fixture/page.tsx b/src/app/mockups/accessible-table-browser-fixture/page.tsx new file mode 100644 index 0000000000..cc4e4fd98e --- /dev/null +++ b/src/app/mockups/accessible-table-browser-fixture/page.tsx @@ -0,0 +1,27 @@ +import { AccessibleTable } from "@/components/AccessibleTable"; + +// An interleaved unnamed clinical column is the conservative normalizer's +// `ambiguous_generic_column` case: it preserves the raw grid and marks it +// low-confidence instead of guessing which dose belongs to which action. +const columns = ["ANC level", "", "Action"]; +const rows = [ + ["1.5", "", "Continue clozapine and monitor according to the local protocol"], + ["1.0", "", "Withhold dose and seek specialist advice"], +]; + +export default function AccessibleTableBrowserFixturePage() { + return ( +
+

Accessible table browser fixture

+

+ Low-confidence clinical extraction with an explicitly missing dose value. +

+
+ +
+
+ ); +} diff --git a/tests/ui-tools.spec.ts b/tests/ui-tools.spec.ts index 753d67a843..46f8d08075 100644 --- a/tests/ui-tools.spec.ts +++ b/tests/ui-tools.spec.ts @@ -3134,3 +3134,55 @@ test.describe("Responsive layout guards", () => { await expectNoPageHorizontalOverflow(page); }); }); + +test("low-confidence AccessibleTable keeps its full missing-value phrase readable at 320px @mockup", async ({ + page, +}, testInfo) => { + await page.setViewportSize({ width: 320, height: 700 }); + await page.goto("/mockups/accessible-table-browser-fixture", { waitUntil: "domcontentloaded" }); + + const fixture = visibleByTestId(page, "accessible-table-browser-fixture"); + await expect(fixture).toBeVisible({ timeout: 15_000 }); + await expect(fixture.getByTestId("table-low-confidence-note")).toContainText( + "verify values against the source document", + ); + + const table = fixture.getByRole("table", { name: "Clozapine ANC response" }); + await expect(table).toBeVisible(); + const missingValues = table.getByTestId("missing-value"); + await expect(missingValues).toHaveCount(2); + await expect(missingValues.first()).toHaveText("Not recorded"); + + const layout = await missingValues.first().evaluate((value) => { + const wrapper = value.parentElement; + if (!wrapper) throw new Error("Missing-value wrapper was not rendered"); + const valueRect = value.getBoundingClientRect(); + const wrapperRect = wrapper.getBoundingClientRect(); + const style = getComputedStyle(wrapper); + return { + valueLeft: valueRect.left, + valueRight: valueRect.right, + wrapperLeft: wrapperRect.left, + wrapperRight: wrapperRect.right, + wrapperClientWidth: wrapper.clientWidth, + wrapperScrollWidth: wrapper.scrollWidth, + whiteSpace: style.whiteSpace, + overflow: style.overflow, + textOverflow: style.textOverflow, + }; + }); + + expect(layout.whiteSpace).toBe("normal"); + expect(layout.textOverflow).not.toBe("ellipsis"); + expect(layout.wrapperScrollWidth - layout.wrapperClientWidth).toBeLessThanOrEqual(1); + expect(layout.valueLeft).toBeGreaterThanOrEqual(layout.wrapperLeft - 1); + expect(layout.valueRight).toBeLessThanOrEqual(layout.wrapperRight + 1); + await expectNoPageHorizontalOverflow(page); + + const screenshotPath = testInfo.outputPath("low-confidence-accessible-table-320px.png"); + await fixture.screenshot({ path: screenshotPath }); + await testInfo.attach("low-confidence-accessible-table-320px", { + path: screenshotPath, + contentType: "image/png", + }); +});