From 1907335ce52aeea7d38b3f86335986132a711890 Mon Sep 17 00:00:00 2001 From: Paul Bakaus Date: Sat, 25 Jul 2026 18:01:14 -0700 Subject: [PATCH] Give each named-color flag case a unique snippet signature Review bots (Greptile, Copilot) correctly noted the aggregate count assertion could pass if one FLAG case stopped emitting while a PASS case started. Each flag case now carries a distinct width/radius combination and the test deep-equals the sorted snippet list, so every finding attributes to exactly one case. Prepared with AI assistance (Claude Code), directed by @pbakaus. Co-Authored-By: Claude Code --- tests/detect-antipatterns-fixtures.test.mjs | 34 +++++++++++-------- .../antipatterns/named-color-borders.html | 14 ++++---- 2 files changed, 28 insertions(+), 20 deletions(-) diff --git a/tests/detect-antipatterns-fixtures.test.mjs b/tests/detect-antipatterns-fixtures.test.mjs index bec634f32..149bea698 100644 --- a/tests/detect-antipatterns-fixtures.test.mjs +++ b/tests/detect-antipatterns-fixtures.test.mjs @@ -375,20 +375,26 @@ describe('detectHtml — static HTML/CSS fixtures', () => { // by the regex engine. The extraction list is now derived from the same // CSS_NAMED_COLORS table the parser uses, so the two can't drift apart. const f = await detectHtml(path.join(FIXTURES, 'named-color-borders.html')); - const sideTabs = f.filter(r => r.antipattern === 'side-tab'); - // Six FLAG cases: purple + radius (the issue reproducer), rebeccapurple - // (contains "purple" as a substring — whole-token matching), crimson - // top stripe, bare 3px teal, a var() resolving to a named color, and an - // inline style attribute. Each must produce exactly one side-tab. - assert.equal( - sideTabs.length, 6, - `expected 6 side-tab findings from the FLAG column, got ${sideTabs.length}: ${sideTabs.map(r => r.snippet).join('; ')}` - ); - const topFindings = sideTabs.filter(r => /border-top/.test(r.snippet || '')); - assert.equal(topFindings.length, 1, `expected 1 border-top finding, got ${topFindings.length}`); - // PASS column (neutral named colors, thin, and uniform borders) must - // contribute nothing — dimgray/gainsboro/black have to parse AND read - // as neutral rather than being dropped as unknown colors. + const sideTabs = f.filter(r => r.antipattern === 'side-tab').map(r => r.snippet).sort(); + // Six FLAG cases, each with a unique width/radius signature so every + // finding attributes to exactly one case (an offsetting miss + false + // positive can't cancel out in an aggregate count): + // purple 4px + radius 8 (the issue reproducer), rebeccapurple 5px + + // radius 4 (contains "purple" as a substring — whole-token matching), + // crimson 4px top stripe, bare 3px teal, var() resolving to a named + // color at 6px + radius 4, and a 7px inline style attribute. + // The PASS column (neutral named colors at 3-4px, 1px thin, uniform) + // must contribute nothing — dimgray/gainsboro/black have to parse AND + // read as neutral rather than being dropped as unknown colors, and none + // of its shapes can produce any of the signatures below. + assert.deepEqual(sideTabs, [ + 'border-left: 3px', + 'border-left: 4px + border-radius: 8px', + 'border-left: 5px + border-radius: 4px', + 'border-left: 6px + border-radius: 4px', + 'border-left: 7px', + 'border-top: 4px', + ]); const borderAccent = f.filter(r => r.antipattern === 'border-accent-on-rounded'); assert.equal( borderAccent.length, 0, diff --git a/tests/fixtures/antipatterns/named-color-borders.html b/tests/fixtures/antipatterns/named-color-borders.html index 10fa21afb..f3e0e2db7 100644 --- a/tests/fixtures/antipatterns/named-color-borders.html +++ b/tests/fixtures/antipatterns/named-color-borders.html @@ -37,12 +37,13 @@ } /* 2: rebeccapurple — a longer name that contains another color name - ("purple") as a substring; must match whole-token */ + ("purple") as a substring; must match whole-token. Width 5px so the + finding snippet is unique to this case. */ #flag-named-rebecca { width: 400px; background: #ffffff; border-radius: 4px; - border-left: 4px solid rebeccapurple; + border-left: 5px solid rebeccapurple; } /* 3: horizontal stripe variant — named crimson riding the top edge */ @@ -59,12 +60,13 @@ border-left: 3px solid teal; } - /* 5: named color behind a var() in the shorthand */ + /* 5: named color behind a var() in the shorthand. Width 6px so the + finding snippet is unique to this case. */ #flag-named-var { width: 400px; background: #ffffff; border-radius: 4px; - border-left: 4px solid var(--accent); + border-left: 6px solid var(--accent); } /* ── PASS cases: neutral named colors and non-side-tab shapes ── */ @@ -119,8 +121,8 @@

crimson top stripe

border-top 4px, horizontal variant

named teal

border-left 3px, no radius

var() to named

border-left 4px solid var(--accent)

-
-

inline named purple

style attribute, issue #359 case (a)

+
+

inline named purple

style attribute, issue #359 case (a); width 7px keeps the snippet unique