You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Captured while reviewing the overall structure of test/browser/ after adding the #239 report-frequency suite. The bones of the suite are sound — fixture-based, text/label-first locators, shared helpers — but upkeep discipline and scaffolding have lagged. This issue gathers the observations so they can be tackled incrementally.
Every file boots off testdata/gtfs/calact_tlserver.dump via a local tlserver + the downtown Portland bbox.
Strengths to preserve
One fixture, real protocol. Every test exercises the real proxy → real GraphQL → real renderer. No mocks, hermetic, reproducible.
Text/label-first locators.getByRole, getByLabel, getByText dominate; CSS selectors appear only where needed. Ages well against markup churn.
Helpers encode UI semantics.openFilterSubtab, resetFilters, ensureFilterPanelOpen, enableAllDay/disableAllDay capture non-obvious behaviors (e.g. the outer Filter tab being a toggle) so each new test author doesn't rediscover them.
No documented independence convention. Files are mixed: query.test.ts is strictly sequential, filters.test.ts is strictly independent, choropleth.test.ts drifts, the new Revise calculations for frequency/visits calculations in tabular reports #239 files are independent. Readers have to figure out per-file which style is in play.
query.test.ts has stale tests."Showing fixed-route service by:", the Route radio, and Individual results no longer exist in the UI. The 3 tests asserting on them silently failed pre-auth-fix (because the scenario fetch 401'd first); now that the data-loading hook works, the staleness is visible. They actively erode trust.
Per-file scenario load is the dominant cost. Six files × ~30s scenario boot = ~3 minutes before any assertions, with workers: 1 and no cross-file sharing.
waitForScenarioLoad hooks on a toast. The "Browsing query data loaded successfully" notification is a UX side effect, not a functional completion signal. If the toast is removed or renamed, every integration test breaks silently.
Big holes in surface coverage.
CSV and GeoJSON download (the feature the tool ships)
URL share / permalink round-trip (scenario config is in the URL)
Filter ↔ report propagation (does a filter change re-render the report tables?)
Flex services — untested UI-side
WSDOT / VisionEval analyses — ignored
Auth-gated production mode — only the requireLogin=false path runs
Fixture data is undocumented. Tests lean on the Portland bbox having "a mix of modes and agencies", but what's actually in calact_tlserver.dump? Which agencies, which route types, what date range, any cross-midnight service? When a test fails, debugging is guesswork.
No visible CI integration.pnpm test:browser is in package.json but no GitHub Actions workflow runs it. If these tests only run when a developer remembers to, that's most of why query.test.ts rotted.
Mixed test-name register.query.test.ts names are task-level ("map shows legend and share button"); the Revise calculations for frequency/visits calculations in tabular reports #239 file uses mechanism-level ("Routes (all-day) Slowest Frequency tooltip preserves the cross-service-day exclusion"). Both defensible, but inconsistency hurts triage.
Locator class coupling..cal-report .cat-tabs couples tests to both an app class and a Catenary class; renames in either repo break tests.
Fix or delete the 3 stale query.test.ts assertions ("Showing fixed-route service by:", Route radio, Individual results).
Add test/browser/README.md documenting the independence convention and the shape-not-magnitude philosophy.
Add a functional-signal fallback to waitForScenarioLoad alongside the toast check (e.g. .cal-report-table presence, non-zero route count).
Write a short testdata/gtfs/FIXTURE.md enumerating the Portland dump's known properties — agencies, modes, date range, anything tests depend on.
Medium
CI workflow that boots tlserver from the dump and runs pnpm test:browser on PRs.
Playwright test fixture (test.extend) that shares a loaded scenario across tests in a worker — cuts suite time ~6× for files that don't mutate state.
One test per download path (CSV + GeoJSON), verifying content.
URL share / reload round-trip test.
Large
Smoke vs. full split: test:browser:smoke (no scenario load, asserts labels/DOM only) vs. test:browser (full). Keeps PR runs under a minute.
Screenshot regression for map/legend surfaces where textual assertions are awkward.
Coverage for WSDOT / VisionEval flows.
Not in scope for this issue
Mock-based testing (MSW / GraphQL mocking). Worth exploring eventually but a much bigger investment than the follow-ups above.
Replacing Playwright. The framework isn't the problem.
Context: analysis produced during #328 (revise frequency calculations) after the suite was expanded with #239 coverage. #333 (merged) fixed the underlying 401-on-unauth issue that had been papering over the query.test.ts staleness.
Captured while reviewing the overall structure of
test/browser/after adding the #239 report-frequency suite. The bones of the suite are sound — fixture-based, text/label-first locators, shared helpers — but upkeep discipline and scaffolding have lagged. This issue gathers the observations so they can be tackled incrementally.Inventory (at time of writing)
smoke.test.ts— 3 tests, static page-loadquery.test.ts— 6 tests, run-a-query happy path (3 stale, see below)filters.test.ts— 4 tests, filter interactions & count deltaschoropleth.test.ts— 7 tests, aggregation overlay UIreport-frequency.test.ts— 15 tests, Revise calculations for frequency/visits calculations in tabular reports #239 report columns (new)map-legend.test.ts— 2 tests, Revise calculations for frequency/visits calculations in tabular reports #239 mode-aware legend (new)helpers.ts— shared utilitiesEvery file boots off
testdata/gtfs/calact_tlserver.dumpvia a local tlserver + the downtown Portland bbox.Strengths to preserve
getByRole,getByLabel,getByTextdominate; CSS selectors appear only where needed. Ages well against markup churn.openFilterSubtab,resetFilters,ensureFilterPanelOpen,enableAllDay/disableAllDaycapture non-obvious behaviors (e.g. the outer Filter tab being a toggle) so each new test author doesn't rediscover them.MM:SS/HH:MM/ non-negative integer — exact arithmetic lives in Vitest against synthetic fixtures. Good split.Weaknesses
No documented independence convention. Files are mixed:
query.test.tsis strictly sequential,filters.test.tsis strictly independent,choropleth.test.tsdrifts, the new Revise calculations for frequency/visits calculations in tabular reports #239 files are independent. Readers have to figure out per-file which style is in play.query.test.tshas stale tests."Showing fixed-route service by:", theRouteradio, andIndividual resultsno longer exist in the UI. The 3 tests asserting on them silently failed pre-auth-fix (because the scenario fetch 401'd first); now that the data-loading hook works, the staleness is visible. They actively erode trust.Per-file scenario load is the dominant cost. Six files × ~30s scenario boot = ~3 minutes before any assertions, with
workers: 1and no cross-file sharing.waitForScenarioLoadhooks on a toast. The "Browsing query data loaded successfully" notification is a UX side effect, not a functional completion signal. If the toast is removed or renamed, every integration test breaks silently.Big holes in surface coverage.
requireLogin=falsepath runsFixture data is undocumented. Tests lean on the Portland bbox having "a mix of modes and agencies", but what's actually in
calact_tlserver.dump? Which agencies, which route types, what date range, any cross-midnight service? When a test fails, debugging is guesswork.No visible CI integration.
pnpm test:browseris inpackage.jsonbut no GitHub Actions workflow runs it. If these tests only run when a developer remembers to, that's most of whyquery.test.tsrotted.Mixed test-name register.
query.test.tsnames are task-level ("map shows legend and share button"); the Revise calculations for frequency/visits calculations in tabular reports #239 file uses mechanism-level ("Routes (all-day) Slowest Frequency tooltip preserves the cross-service-day exclusion"). Both defensible, but inconsistency hurts triage.Locator class coupling.
.cal-report .cat-tabscouples tests to both an app class and a Catenary class; renames in either repo break tests.No visual/screenshot regression. Pure DOM/text assertions. The choropleth magnitude shift called out in the Revise calculations for frequency/visits calculations in tabular reports #239 plan (values ~5–30× larger) is exactly the kind of thing a screenshot diff would catch.
Prioritized follow-ups
Small
query.test.tsassertions ("Showing fixed-route service by:",Routeradio,Individual results).test/browser/README.mddocumenting the independence convention and the shape-not-magnitude philosophy.waitForScenarioLoadalongside the toast check (e.g..cal-report-tablepresence, non-zero route count).testdata/gtfs/FIXTURE.mdenumerating the Portland dump's known properties — agencies, modes, date range, anything tests depend on.Medium
pnpm test:browseron PRs.test.extend) that shares a loaded scenario across tests in a worker — cuts suite time ~6× for files that don't mutate state.Large
test:browser:smoke(no scenario load, asserts labels/DOM only) vs.test:browser(full). Keeps PR runs under a minute.Not in scope for this issue
Context: analysis produced during #328 (revise frequency calculations) after the suite was expanded with #239 coverage. #333 (merged) fixed the underlying 401-on-unauth issue that had been papering over the
query.test.tsstaleness.