webviews: browser tests open a gallery frame for their own entry alone, and a guard keeps it so (composer batch)

Merged
TE
15d ago
+338-321

Browser tests open /gallery/frame.html?entry=<id> without entryPath. The frame then starts loading every one of the 153 *.gallery.ts(x) files (src/gallery/entryStore.ts) before it finds the entry it renders. Each test also warms the dev server by crawling /gallery/frame.html, which follows the registry's lazy imports and transforms all of them again: about 3,000 modules per test file (the crawl's count, imports included). #23080 fixed one test (markdown-selection-drag); this makes the fix system-wide and guards it.

This PR adds the helper, the guard, and the composer batch: 23 composer files, quiet-access-chip, and gallery-composer-paste (new on base; the guard caught it). Two follow-ups narrow the rest.

What changed

  • test/support/galleryFrame.ts (new).
    • galleryFrame(entry, params) builds the frame URL with entryPath. It finds the entry's file from its id: "<id>" line, so tests never hard-code a path, and it throws if no file or several files define the id.
    • warmGalleryFrame(vite, entries, { browser, params }) warms by loading each entry's frame once in a browser and waiting for data-gallery-ready. It replaces both warmViteServer(vite, "/gallery/frame.html") and the hand-written warm-page loops.
    • If Vite's dependency optimizer reloads the page, during the navigation or after it, the warm-up starts the load again within the same budget. A stage that fails to mount (data-gallery-ready="error") fails the warm-up and names the entry.
    • Why a browser load and not the module crawl: measured on Huge Blue with a cold server and the composer entry, the crawl follows lazy page hosts the frame never loads (frame/pages.ts names every page, Monaco among them). It cost 25 s and 1,227 modules, where one page load cost 20 s and 685.
  • Guard (scripts/check-browser-test-lanes.ts, runs in bun run check).
    • Fails any browser test that opens frame.html without entryPath, unless the file carries // gallery-frame-every-entry: <reason> (the reason is required).
    • EVERY_ENTRY_PENDING names the files not narrowed yet, each with why. The guard fails on a listed file that is already narrowed, or that no longer exists, so the list can only shrink.
    • Two of those files are changed by other lanes' open PRs and wait for them: suggestion-lists-float (#22795) and transcript-thought (#23084). composer-location-strip was narrowed on base by #23210, and quiet-access-chip is migrated here now that #22902 has merged.
    • The opt-out comment counts only at the start of a line, and a test counts as a browser test only if it really imports playwright.
    • checkDevServerWarmSource accepts warmGalleryFrame as a warm-up.
    • test/check-browser-test-lanes.test.ts covers the new rule.
  • The composer batch: composer-history and 22 other composer-* files open their frames through galleryFrame and warm with warmGalleryFrame.
    • A multi-entry file warms the old warm page's entry with its variant, then the other entries at their default variant (variant names differ between entries).
    • Two-engine files warm once, in Chromium if it launched, else WebKit.

No assertion, test name, skip or test timeout changed. The old warm loops waited with no limit; the warm-up now has a 100 s budget, the same as warmViteServer's default.

Testing

Each file ran on Huge Blue (Linux, bun 1.4.2, CMUX_BROWSER_TESTS=1) at base and with this change. The same tests pass, and every file is faster. Huge Blue was loaded, so the times are noisy.

filebasethis PR
composer-history (first head)0/1 (base red then: layout shift 0.0002), 77.6 ssame failure, 26.5 s
composer-chip-press52 pass, 349.0 s52 pass, 249.3 s
composer-menu-dismiss60 pass, 417.5 s60 pass, 337.0 s
composer-caret-focus42 pass, 217.2 s42 pass, 155.9 s
composer-quiet-chips32 pass, 172.0 s32 pass, 127.0 s
composer-draft-wrap32 pass, 160.5 s32 pass, 114.2 s
composer-top-strip-variants47 pass, 166.0 s47 pass, 122.0 s
composer-type-scale41 pass, 142.9 s41 pass, 110.3 s
composer-row-layout29 pass, 126.1 s29 pass, 86.7 s
composer-claude-split16 pass / 2 fail (base red), 118.4 ssame, 80.9 s
composer-footer-plain19 pass, 100.3 s19 pass, 74.4 s
composer-mention1 pass / 6 fail (base red), 63.1 ssame, 38.3 s
the other 11 composer files1โ€“9 tests each, 40.9โ€“58.5 ssame results, 16.8โ€“40.8 s
quiet-access-chip (rebased head)4 pass, 76.7 s4 pass, 41.8 s
gallery-composer-paste (rebased head)5 pass, 57.6 s5 pass, 38.1 s
composer-history (rebased head)1 pass, 45.6 s1 pass, 27.5 s
  • bun scripts/check-browser-test-lanes.ts passes, and vp check reports no warnings, lint errors or type errors. bun run check stops earlier, at check:text-focus, which is red on base (run-board/variants/timeline/timeline.css:14, not in this PR).
  • test/check-browser-test-lanes.test.ts: 3 pass.

Observed / Not run

  • Observed: the table above, the guard flagging exactly the 66 files at base, and the check above.
  • Not run: the suite on CI. CI's react-apps-check on this PR gives the runtime change; I'll compare it with base runs (the Test webviews step summed over 4 shards was 1,539โ€“1,624 s on three recent runs).
  • Found along the way, not changed here: pages.markdown's default variant (showcase) never sets data-gallery-ready. A probe gave up at 131 s.

Changelog

none

Agent session: cosmic-gray

๐Ÿค– Generated with Claude Code