fix(showcase): break wn-breadcrumb slotchange infinite loop (WHYNOT-WP-0002 T11)
WnBreadcrumb._onSlot inserted separator <span>s into its own light DOM on slotchange but cleaned up in the shadow DOM, so they were never removed — each insertion re-fired slotchange, looping the main thread and wedging the showcase page. Made _onSlot idempotent: exclude own separators when reading items, and mutate only when separators are not already correct. - Un-fixme the showcase visual test; add a warm-up full-page capture so deviceScaleFactor-2 sub-pixel snapping settles before the assertion. All 5 visual tests pass. - Remove the dead Google-Fonts @import from colors_and_type.css (token stacks are system-ui; webfont unused + a CI-flake source; no visual change). - Unblocks WHYNOT-WP-0003 T08 (showcase = per-version visual catalog); both T11 and T08 marked done. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -8,28 +8,30 @@ import { test, expect } from "@playwright/test";
|
||||
//
|
||||
// To update intentionally: pnpm test:visual:update
|
||||
|
||||
// The design-tokens stylesheet (colors_and_type.css) @imports IBM Plex from
|
||||
// Google Fonts, but every token font stack is system-ui based — the webfont is
|
||||
// unused. Left live it intermittently hangs in CI, blocking the page's module
|
||||
// <script> (a pending stylesheet defers script execution) so custom elements
|
||||
// never register. Abort the font CDNs so baselines are deterministic & offline.
|
||||
// Defensive: no webfont is loaded anymore (token font stacks are system-ui
|
||||
// based), but abort the font CDNs anyway so a re-introduced webfont can never
|
||||
// make a baseline non-deterministic or network-dependent.
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.route(/fonts\.(googleapis|gstatic)\.com/, (route) => route.abort());
|
||||
});
|
||||
|
||||
test.describe("showcase — every component", () => {
|
||||
// KNOWN BROKEN — tracked as adhoc against WHYNOT-WP-0002. The showcase page
|
||||
// (every component on one page) wedges the renderer main thread when its
|
||||
// module executes: components + vendored lit render fine in isolation, but
|
||||
// one demo composition on this page infinite-loops, so the page never
|
||||
// reaches `load` and no `showcase.png` baseline can be captured. The four
|
||||
// whynot-control baselines are unaffected. Remove `.fixme` once the looping
|
||||
// component is fixed and regenerate the baseline.
|
||||
test.fixme("renders", async ({ page }) => {
|
||||
// Previously KNOWN BROKEN (WHYNOT-WP-0002 T11): the page wedged the renderer
|
||||
// main thread because <wn-breadcrumb> inserted separators into its own light
|
||||
// DOM on slotchange, re-firing slotchange in an infinite loop. Fixed by making
|
||||
// WnBreadcrumb._onSlot idempotent (src/elements/layout.js).
|
||||
test("renders", async ({ page }) => {
|
||||
await page.goto("/examples/showcase/index.html");
|
||||
// Wait for custom elements to register + Lit to render.
|
||||
await page.waitForFunction(() => !!customElements.get("wn-button"));
|
||||
await page.waitForTimeout(800);
|
||||
// Warm-up capture: the first full-page screenshot resizes the viewport to
|
||||
// the full content height, and at deviceScaleFactor 2 that first layout pass
|
||||
// snaps several sections by ≤4px. Discard it so the page is settled before
|
||||
// the real assertion — otherwise toHaveScreenshot fails its "two consecutive
|
||||
// stable screenshots" check on this long page.
|
||||
await page.screenshot({ fullPage: true });
|
||||
await page.waitForTimeout(200);
|
||||
await expect(page).toHaveScreenshot("showcase.png", { fullPage: true });
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user