diff --git a/packages/cli/src/commands/layout-audit.browser.js b/packages/cli/src/commands/layout-audit.browser.js index 382184309a..1c8cc381bc 100644 --- a/packages/cli/src/commands/layout-audit.browser.js +++ b/packages/cli/src/commands/layout-audit.browser.js @@ -458,8 +458,12 @@ ? tolerance : Math.max(tolerance, parsePx(elementStyle.fontSize) * 0.2); const containerOverflow = overflowFor(textRect, containerRect, tolerance, verticalTolerance); + // A clipping box that is its own nearest constraint is `clipped_text`; billing the same defect + // here as well double-counted it. A NON-clipping self-constraint still reports — nothing else covers it. + const isClippedSelfConstraint = container === element && containerClips; if ( containerOverflow && + !isClippedSelfConstraint && !hasTextClipOptOut(element) && !clippedByAncestor(element, container) ) { diff --git a/packages/cli/src/commands/layout-audit.browser.test.ts b/packages/cli/src/commands/layout-audit.browser.test.ts index eb551164ba..08882ec20a 100644 --- a/packages/cli/src/commands/layout-audit.browser.test.ts +++ b/packages/cli/src/commands/layout-audit.browser.test.ts @@ -219,7 +219,9 @@ describe("layout-audit.browser", () => { .map((issue) => issue.code) .filter((code) => code === "clipped_text" || code === "text_box_overflow"); - expect(textOverflowCodes()).toEqual(["clipped_text", "text_box_overflow"]); + // One code: a clipping box that is its own nearest constraint is `clipped_text`, and billing the + // same defect as `text_box_overflow` too counted it twice. + expect(textOverflowCodes()).toEqual(["clipped_text"]); document.querySelector("#overflow-optout")?.setAttribute("data-layout-allow-overflow", ""); expect(textOverflowCodes()).toEqual([]); document.querySelector("#overflow-optout")?.removeAttribute("data-layout-allow-overflow"); @@ -227,6 +229,29 @@ describe("layout-audit.browser", () => { expect(textOverflowCodes()).toEqual([]); }); + it("still flags a painted, NON-clipping box that is its own nearest constraint", () => { + // `container === element` does not imply the element clips: a painted, sized box is a + // constraint candidate too. `clipped_text` cannot speak for it (nothing is clipped), so the + // de-duplication guard must not swallow this — it would leave the defect with no code at all. + // `#bubble` is the harness's painted, radiused box — here it carries the text itself, so it is + // its own nearest constraint while clipping nothing. + document.body.innerHTML = ` +