From 191ef3be917c8e7fc9ddaa3d5ea635dafcafeba9 Mon Sep 17 00:00:00 2001 From: Hongming Wang Date: Tue, 5 May 2026 03:05:17 -0700 Subject: [PATCH] fix(canvas/tests): pin Expand-to-Team absence with literal assertion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Multi-model review of #2862 caught a non-load-bearing assertion: the test used \`expect(labels).not.toContain(expect.stringMatching(...))\` to claim the "Expand to Team" right-click item is gone. But vitest's toContain uses Object.is/===, so asymmetric matchers like expect.stringMatching are plain objects that never === any string — the assertion silently passed for ANY string array, including arrays that DID contain "Expand to Team". The test would have green-lit the unfixed code. Switch to the literal substring shape the rest of this file already uses (see lines 175/183/254 — labels.some((l) => l.includes(...))). Verified the new assertion is load-bearing: 1. Reintroduced \`{ label: "Expand to Team", ... }\` into the childless-workspace branch of ContextMenu.tsx 2. Ran the test — failed at the new assertion line as expected 3. Reverted the regression — test passes again Net diff: replaces one broken expect with one correct expect + a WHY-comment noting the toContain/asymmetric-matcher gotcha so the next reader (or test writer) doesn't reintroduce the same shape. Per memory feedback_assert_exact_not_substring.md: pin assertions that fail on the old code path; this assertion never fired even on the bug it was written to catch. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../src/components/__tests__/ContextMenu.keyboard.test.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/canvas/src/components/__tests__/ContextMenu.keyboard.test.tsx b/canvas/src/components/__tests__/ContextMenu.keyboard.test.tsx index 07d85489..afdeaf43 100644 --- a/canvas/src/components/__tests__/ContextMenu.keyboard.test.tsx +++ b/canvas/src/components/__tests__/ContextMenu.keyboard.test.tsx @@ -240,7 +240,11 @@ describe("ContextMenu — keyboard accessibility", () => { render(); const items = screen.getAllByRole("menuitem"); const labels = items.map((el) => el.textContent?.trim() ?? ""); - expect(labels).not.toContain(expect.stringMatching(/Expand to Team/)); + // Literal absence — vitest's toContain uses Object.is/===, so the + // earlier `.not.toContain(expect.stringMatching(...))` shape passed + // for ANY string array (asymmetric matchers only work with toEqual / + // arrayContaining). Pin the production string verbatim. + expect(labels.some((l) => l.includes("Expand to Team"))).toBe(false); // Sanity: childless menu still has the regular actions. expect(labels.some((l) => l.includes("Delete"))).toBe(true); expect(labels.some((l) => l.includes("Restart"))).toBe(true);