From f881869c43a98bdeef9fa1a27aad49d56d86a688 Mon Sep 17 00:00:00 2001 From: Alain Schlesser Date: Sun, 18 Oct 2026 00:11:20 +0200 Subject: [PATCH 1/2] test(diagrams): measure real viewer text font floors --- packages/ui-react/tests/browser/diagrams-axis.layout.tsx | 4 ++-- packages/ui-react/tests/browser/diagrams-renderer.layout.tsx | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/ui-react/tests/browser/diagrams-axis.layout.tsx b/packages/ui-react/tests/browser/diagrams-axis.layout.tsx index 30d0d5af4..7c12de1a1 100644 --- a/packages/ui-react/tests/browser/diagrams-axis.layout.tsx +++ b/packages/ui-react/tests/browser/diagrams-axis.layout.tsx @@ -12,7 +12,7 @@ afterAll(async()=>{styles.remove();await commands.formViewport(previousViewport. function setup(width=760){root=createBrainUiRoot({storage:null,request:async()=>Response.json({renderers:[],enabled:[]})});host=document.createElement("div");host.style.width=`${width}px`;document.body.append(host);render=createRoot(host);} function mount(source:string,theme:"light"|"dark"|"print"){flushSync(()=>render.render());} async function ready(){await expect.poll(()=>host.querySelector('figure>svg')).not.toBeNull();await document.fonts.ready;} -function inspect(svg:SVGSVGElement){const frame=svg.viewBox.baseVal;for(const label of svg.querySelectorAll("text")){const box=label.getBBox(),matrix=label.getScreenCTM()!,scale=Math.min(Math.hypot(matrix.a,matrix.b),Math.hypot(matrix.c,matrix.d));expect(parseFloat(getComputedStyle(label).fontSize)*scale,"AXIS_NORMAL_TEXT_FLOOR").toBeGreaterThanOrEqual(9);expect(box.x,"TEXT_LEFT_BOUND").toBeGreaterThanOrEqual(0);expect(box.x+box.width,"TEXT_RIGHT_BOUND").toBeLessThanOrEqual(frame.width);expect(box.y,"TEXT_TOP_BOUND").toBeGreaterThanOrEqual(0);expect(box.y+box.height,"TEXT_BOTTOM_BOUND").toBeLessThanOrEqual(frame.height);}} +function inspect(svg:SVGSVGElement){expect(svg.querySelectorAll("text").length,"EXPECTED_AXIS_TEXT_POPULATION").toBeGreaterThan(0);const frame=svg.viewBox.baseVal;for(const label of svg.querySelectorAll("text")){const box=label.getBBox(),matrix=label.getScreenCTM()!,scale=Math.min(Math.hypot(matrix.a,matrix.b),Math.hypot(matrix.c,matrix.d));expect(parseFloat(getComputedStyle(label).fontSize)*scale,"AXIS_NORMAL_TEXT_FLOOR").toBeGreaterThanOrEqual(9);expect(box.x,"TEXT_LEFT_BOUND").toBeGreaterThanOrEqual(0);expect(box.x+box.width,"TEXT_RIGHT_BOUND").toBeLessThanOrEqual(frame.width);expect(box.y,"TEXT_TOP_BOUND").toBeGreaterThanOrEqual(0);expect(box.y+box.height,"TEXT_BOTTOM_BOUND").toBeLessThanOrEqual(frame.height);}} for(const [kind,spec] of Object.entries(axisExamples))test(`${kind} real light dark print baselines and static parity`,async()=>{ setup(kind==="swimlane"?1000:760);const source=JSON.stringify(spec); for(const theme of ["light","dark","print"] as const){mount(source,theme);await ready();const svg=host.querySelector('figure>svg')!;inspect(svg);const parsed=new DOMParser().parseFromString(await toStatic(source,{theme}),"image/svg+xml"); @@ -22,7 +22,7 @@ for(const [kind,spec] of Object.entries(axisExamples))test(`${kind} real light d }); test("sequence uses readable derived phone layout and unsafe content opens the full viewer",async()=>{ setup(320);mount(JSON.stringify(axisExamples.sequence),"dark");await ready();const svg=host.querySelector('figure>svg')!;expect(svg.viewBox.baseVal.width).toBe(320);inspect(svg);expect(host.scrollWidth).toBeLessThanOrEqual(320);await expect(page.elementLocator(host)).toMatchScreenshot("axis-sequence-320-dark");await commands.diagramCapture('[data-content-renderer="diagram"]',"axis-sequence-320-dark"); - const unsafe=structuredClone(axisExamples.sequence);unsafe.nodes.push({id:"penelope",label:"Penelope"},{id:"athena",label:"Athena"});mount(JSON.stringify(unsafe),"light");await expect.poll(()=>host.querySelector('[data-diagram-summary]')).not.toBeNull();expect(host.querySelector('figure>svg')).toBeNull();const opener=[...host.querySelectorAll('[role="button"],button')].find(b=>b.textContent==="Open diagram")!;expect(opener.getBoundingClientRect().height).toBeGreaterThanOrEqual(44);await userEvent.click(opener);await expect.poll(()=>document.querySelector('[aria-label="Diagram viewer"] svg')).not.toBeNull();inspect(document.querySelector('[aria-label="Diagram viewer"] svg')!);await userEvent.keyboard("{Escape}"); + const unsafe=structuredClone(axisExamples.sequence);unsafe.nodes.push({id:"penelope",label:"Penelope"},{id:"athena",label:"Athena"});mount(JSON.stringify(unsafe),"light");await expect.poll(()=>host.querySelector('[data-diagram-summary]')).not.toBeNull();expect(host.querySelector('figure>svg')).toBeNull();const opener=[...host.querySelectorAll('[role="button"],button')].find(b=>b.textContent==="Open diagram")!;expect(opener.getBoundingClientRect().height).toBeGreaterThanOrEqual(44);await userEvent.click(opener);await expect.poll(()=>document.querySelector('[aria-label="Diagram viewer"] svg.bk-diagram')).not.toBeNull();inspect(document.querySelector('[aria-label="Diagram viewer"] svg.bk-diagram')!);await userEvent.keyboard("{Escape}"); }); test("axis handoff masks clear every step and tips attach at the boundary",async()=>{ diff --git a/packages/ui-react/tests/browser/diagrams-renderer.layout.tsx b/packages/ui-react/tests/browser/diagrams-renderer.layout.tsx index 960b14726..55953b334 100644 --- a/packages/ui-react/tests/browser/diagrams-renderer.layout.tsx +++ b/packages/ui-react/tests/browser/diagrams-renderer.layout.tsx @@ -18,7 +18,7 @@ function setup(width=1000){root=createBrainUiRoot({storage:null,request:async()= function mount(element:React.ReactNode){flushSync(()=>render.render({element}));} function screenSvg(){return host.querySelector('figure > svg.bk-diagram');} async function ready(){await expect.poll(()=>screenSvg()).not.toBeNull();await document.fonts.ready;} -function fontFloor(svg:SVGSVGElement){for(const text of svg.querySelectorAll("text")){const matrix=text.getScreenCTM()!;const scale=Math.min(Math.hypot(matrix.a,matrix.b),Math.hypot(matrix.c,matrix.d));expect(parseFloat(getComputedStyle(text).fontSize)*scale,"ACTUAL_DISPLAYED_TEXT_FLOOR").toBeGreaterThanOrEqual(9);}} +function fontFloor(svg:SVGSVGElement){expect(svg.querySelectorAll("text").length,"EXPECTED_DIAGRAM_TEXT_POPULATION").toBeGreaterThan(0);for(const text of svg.querySelectorAll("text")){const matrix=text.getScreenCTM()!;const scale=Math.min(Math.hypot(matrix.a,matrix.b),Math.hypot(matrix.c,matrix.d));expect(parseFloat(getComputedStyle(text).fontSize)*scale,"ACTUAL_DISPLAYED_TEXT_FLOOR").toBeGreaterThanOrEqual(9);}} test("registered chat fence renders and follows live light/dark and actual print media",async()=>{ setup();defaultContentRendererRegistry.register(diagramsContentPack);document.documentElement.dataset.theme="light";root.stores.ui.setState({theme:"light"}); mount();await ready(); @@ -34,7 +34,7 @@ test("actual constrained containers select authored layout or semantic fallback, for(const width of [320,480,900]){host.style.width=`${width}px`;await expect.poll(()=>screenSvg()?.getBoundingClientRect().width).toBe(320);fontFloor(screenSvg()!);expect(host.scrollWidth).toBeLessThanOrEqual(width);} const absent=structuredClone(rendererSpec);delete (absent as {layouts?:unknown}).layouts;host.style.width="320px";mount();await expect.poll(()=>screenSvg()).toBeNull();expect(host.querySelector("[data-diagram-summary]")?.textContent).toBe(rendererSpec.desc); const opener=[...host.querySelectorAll("[role=button],button")].find(item=>item.textContent==="Open diagram")!;expect(opener.getBoundingClientRect().height).toBeGreaterThanOrEqual(44);await userEvent.click(opener); - await expect.poll(()=>document.querySelector('[aria-label="Diagram viewer"] svg')).not.toBeNull();const drawing=document.querySelector('[aria-label="Diagram viewer"] svg')!;fontFloor(drawing);await userEvent.keyboard("{Escape}"); + await expect.poll(()=>document.querySelector('[aria-label="Diagram viewer"] svg.bk-diagram')).not.toBeNull();const drawing=document.querySelector('[aria-label="Diagram viewer"] svg.bk-diagram')!;expect([...drawing.querySelectorAll("[data-diagram-node] text")].map(text=>text.textContent),"EXPECTED_VIEWER_NODE_LABELS").toEqual(expect.arrayContaining(rendererSpec.nodes.map(node=>node.label)));fontFloor(drawing);await userEvent.keyboard("{Escape}"); }); test("keyboard nodes navigate like wiki links and incident edges and focus ring remain visible",async()=>{ setup();const paths:string[]=[];root.stores.file.setState({openFile:async(path)=>{paths.push(path);}});mount();await ready(); From 61c2299dc129c3fbce2c97393a14af85ce648435 Mon Sep 17 00:00:00 2001 From: Alain Schlesser Date: Sun, 18 Oct 2026 00:35:20 +0200 Subject: [PATCH 2/2] test(diagrams): qualify viewer proof caller bindings --- scripts/bound-browser-documents.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/scripts/bound-browser-documents.ts b/scripts/bound-browser-documents.ts index 68ddc61e7..f9ae5bb00 100644 --- a/scripts/bound-browser-documents.ts +++ b/scripts/bound-browser-documents.ts @@ -31,11 +31,13 @@ const declarations:DocumentDeclaration[]=[{ },{ // Reviewed against #2295 and #2346: bounded capture tracing, split relay and // callout cases keep the exact HTML/CSS sink, five callers and offline producers. + // #2241 re-audit: renderer/axis edits only strengthen viewer selection and + // font assertions; capture arguments, call counts and producer closure stay fixed. "command": "diagramCapture", "owner": "packages/ui-react/tests/browser/diagram-proof-command.ts", "ownerHash": "d7280cf23ba24bd636f7737d8552801e37f8c03c1e773aee660c9e07ded524a9", "caller": "packages/ui-react/tests/browser/diagrams-renderer.layout.tsx", - "callerHash": "dbac044e90a3b7b84e308a96cca8396874afb9b96d8cc23b2fddb4293d85706c", + "callerHash": "9d5e6b574bc22fb19f47c6d7d813f13bd444920539bf341732700e9d3413de4a", "calls": 2, "additionalCallers": { "packages/ui-react/tests/browser/diagrams-callouts.layout.tsx": { @@ -43,7 +45,7 @@ const declarations:DocumentDeclaration[]=[{ "calls": 8 }, "packages/ui-react/tests/browser/diagrams-axis.layout.tsx": { - "hash": "6512cb4660834ef7b15a52258d51f694c4e34fd530754bdc51580137db22b75c", + "hash": "bd7c728af1ae5c250ddbef4e3423372590aabc65430661fe6afed97e3eb6e933", "calls": 3 }, "packages/ui-react/tests/browser/diagrams-positional.layout.tsx": {