From 5e89a201f78b106e2f3cc2bd409d93e6b9edd086 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Mon, 31 Aug 2026 00:06:50 +0200 Subject: [PATCH] test(labs): assert the outlier's distance from the edge, not one string Follow-up to #860, promised in review rather than asked of the contributor. `not.toContain("left: 4%")" passes for a marker at 4.02%, which is the same defect one rounding away, so the test now reads the marker position and asserts it sits inside the padding at both ends. EDGE_PADDING_PERCENT moves to module scope and is exported, so the assertion uses the number the component clamps with instead of a copy that can drift. It was being reallocated on every render besides. Verified by mutation: dropping the outlier expansion puts the marker at exactly 4 and turns this test red. --- .../targets/__tests__/range-bar.test.tsx | 15 +++++++++++++-- src/components/targets/range-bar.tsx | 9 ++++++++- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/components/targets/__tests__/range-bar.test.tsx b/src/components/targets/__tests__/range-bar.test.tsx index 2f4f2df3e..1f6e54c95 100644 --- a/src/components/targets/__tests__/range-bar.test.tsx +++ b/src/components/targets/__tests__/range-bar.test.tsx @@ -2,7 +2,7 @@ import { describe, expect, it } from "vitest"; import { renderToStaticMarkup } from "react-dom/server"; import { I18nProvider } from "@/lib/i18n/context"; -import { RangeBar } from "../range-bar"; +import { EDGE_PADDING_PERCENT, RangeBar } from "../range-bar"; /** * v1.4.25 W3e — `` was extracted from the inline 790-line @@ -68,7 +68,18 @@ describe("", () => { tone: "lab", }); - expect(html).not.toContain("left: 4%"); + // Assert the distance, not one unlucky string. `not.toContain("left: 4%")` + // passes for a marker at 4.02%, which is the same defect one rounding away. + // The marker is the fourth `left:` in the markup — the three before it are + // the bar slot and the band edges. + const positions = [...html.matchAll(/left:\s*([0-9.]+)%/g)].map((m) => + Number(m[1]), + ); + const marker = positions[3]; + + expect(marker).toBeGreaterThan(EDGE_PADDING_PERCENT); + // And not flung to the other end by an over-eager expansion. + expect(marker).toBeLessThan(100 - EDGE_PADDING_PERCENT); }); it("makes the marker focusable with a text alternative for the value + range (2026-07-17 a11y audit M1)", () => { diff --git a/src/components/targets/range-bar.tsx b/src/components/targets/range-bar.tsx index a4a992117..ba90f1047 100644 --- a/src/components/targets/range-bar.tsx +++ b/src/components/targets/range-bar.tsx @@ -30,6 +30,14 @@ export interface RangeBarProps { maxLabel?: string | null; } +/** + * How far from either end the value marker is allowed to sit, in percent. + * + * Module scope rather than the render body so the test can assert against the + * same number the component clamps with, instead of a copy that can drift. + */ +export const EDGE_PADDING_PERCENT = 4; + export function RangeBar({ value, min, @@ -83,7 +91,6 @@ export function RangeBar({ const visualSpan = visualMax - visualMin; const clampedValue = Math.max(visualMin, Math.min(visualMax, value)); const rawPosition = ((clampedValue - visualMin) / visualSpan) * 100; - const EDGE_PADDING_PERCENT = 4; const position = Math.max( EDGE_PADDING_PERCENT, Math.min(100 - EDGE_PADDING_PERCENT, rawPosition),