test(collection): import a Dreamborn export end to end, and keep the gear's focus through it (#1125)

Merged
DO
5d ago
+315-41

Before: no E2E test ever picked a file in the collection import dialog, so the Dreamborn CSV parser, the import and its receipt never ran in a browser, and neither did the dialog's refusals. And after an import from Browse's grid, pressing Done left keyboard focus nowhere: the import opens the binder under the dialog, which rebuilt the toolbar's Collection button and gear, so the gear the dialog handed focus back to was gone.

After: collection-import.spec.ts imports a small Dreamborn export from Browse's gear and from the account page, and checks the receipt ("3 cards, 5 copies in all.", the unmatched row named) and the collection the account receives. Three more tests cover a file with no owned cards, a file the browser can't read, and a card list that won't load, whose Try again brings the file button back. Done after a Browse import now leaves focus on the gear. The toolbar's five raw gaps take spacing tokens, so on desktop its controls sit 12 px apart instead of 10, and filter chips sit 8 px apart instead of 6 on every screen.

How: the export is written in the spec from the card data (two finishes of a set 13 card, a set 3 card, a promo by its code, a row no card answers to and a census row with no copies), with Windows line endings, so no card id or number is hardcoded. The unreadable file comes from an init script that makes Blob.prototype.text reject for that file's name. DockedToolbar now draws Collection and the collection's actions in the same elements in both modes and changes only their boxes' style (display: contents where they sit in the row), so a mode change keeps them and focus on them. Before the spacing change, screenshots of the docked toolbar in both modes matched master's pixel for pixel (maxDiffPixels: 0). BrowseToolbar.tsx then leaves the raw-spacing ledger (the owner's pick): each 10 becomes SPACING.md and the chips' 6 becomes SPACING.sm. The phone's grid and collection rows stay pixel-identical at 390 and 360 px. Before and after shots: Browse Toolbar Spacing.

Each new E2E test was shown to fail with the behaviour it covers broken: the receipt's copy count, the zero-copies check, the unreadable-file message, the card list's Try again, an import that merged instead of replacing, an import that didn't upload, and the toolbar change reverted (focus off the gear). The new unit test in BrowseToolbar.test.tsx fails on master's toolbar too. The other specs that drive Browse's toolbar (collection mode, start, binder, friends, Browse's grid and filters, mobile, search, loading geometry, accessibility, focus rings, skip link) pass in Chromium and mobile Chrome.

Closes #1125


Generated by Claude Code


Summary by cubic

Adds end-to-end coverage for importing a Dreamborn collection export, and fixes two focus and animation-read bugs the tests exposed.

collection-import.spec.ts writes a small Dreamborn CSV from the card data (two finishes, a pre-Core card, a promo, an unmatched row, and a zero-count row) and imports it from Browse's gear and from the account page, checking the receipt and the upload the account receives. Three more tests cover refusals — a file with no owned cards, a file the browser can't read, and a card list that won't load — each verifying that a good file chosen next imports cleanly, its upload the only one the account gets. E2E_TESTS.md records the new tests.

The imports from Browse exposed a real bug: Done left keyboard focus nowhere, because the import opened the binder under the dialog and DockedToolbar rebuilt Collection and the gear in new elements when switching modes. The toolbar now keeps both in the same elements in either mode, changing only their boxes' style, so focus survives; the refactor also snaps its five raw gaps to spacing tokens, so desktop controls sit 12 px apart instead of 10 and filter chips 8 px apart instead of 6.

Bug Fixes

  • Done after a Browse import leaves focus on the gear instead of nowhere.
  • The reduced-motion comparison test in synergy-detail-modal.spec.ts no longer assumes card B lasts four frames after BACK; WebKit can draw its 480 ms stay in three, so the sampler now reads card B as the mode flips and on every frame it lasts.