Learning path

Frontend Testing

Grounded in flowbase/apps/frontend/e2e — ~200 Playwright specs across 16 projects, retries: 3.

Assessed 2026-08-24 and 2026-09-08 · A1 completed 2026-08-25 · MISSION.md · RESOURCES.md

Renamed 2026-09-08. This path was concurrency/ — same mission, narrower name. The 2026-09-08 session widened scope to determinism, test-level allocation and the canvas editor, and nearly created a duplicate path before the overlap was caught. A1–A4, the original assessment and all suite findings carry forward unchanged.

Knowledge graph

Green = mastered. Amber = inner fringe (just learnt, still fragile — A1). Blue = outer fringe / zone of proximal development, lessons written and ready (six of them: A2–A4, C1–C3). Grey = locked. Click a node to open its lesson.

graph TD
  A[Async/await mechanics]:::got
  B[Playwright auto-waiting
web-first assertions]:::got C[Locator strategy]:::got D[Worker model:
process per worker]:::got E[Flake taxonomy:
async wait / concurrency / TOD]:::inner F[Symptom-first diagnosis]:::inner G[Retry policy as signal]:::inner H[The isolation ladder]:::zpd I[Fixture scope as a
sharing decision]:::zpd J[Collision surface audit:
what is actually shared]:::zpd K[Per-tenant test isolation]:::locked L[Serialisation primitives:
serial / mutex / lease]:::locked M[Cleanup contracts &
failure-safe teardown]:::locked N[Convergent assertions over
shared collections]:::locked O[Flake budgets & quarantine]:::locked P[Actionability: the five checks]:::zpd Q[Determinism inventory:
time / network / locale]:::zpd R[Size vs scope:
what belongs in e2e/]:::zpd S[Flakiness score:
entropy + flip rate]:::locked T[Trace-driven diagnosis]:::locked U[Network stubbing &
fault injection]:::locked V[Canvas behaviour testing
without pixels]:::locked W[Sharding & CI economics]:::locked A --> B --> C B --> E D --> J E --> F --> G E --> H E --> J D --> I H --> I H --> J H --> K H --> L J --> M J --> N G --> O B --> P P --> T P --> V E --> Q Q --> U U --> V R --> U R --> W G --> S O --> S J --> W click E "lessons/a1-naming-the-flake.html" "A1" click F "lessons/a1-naming-the-flake.html" "A1" click G "lessons/a1-naming-the-flake.html" "A1" click H "lessons/a2-the-isolation-ladder.html" "A2" click J "lessons/a3-collision-surface-audit.html" "A3" click I "lessons/a4-fixture-scope.html" "A4" click P "lessons/c1-the-five-checks.html" "C1" click Q "lessons/c2-the-determinism-inventory.html" "C2" click R "lessons/c3-size-and-scope.html" "C3" classDef got fill:#dcfce7,stroke:#16a34a,color:#14532d classDef inner fill:#fed7aa,stroke:#ea580c,color:#7c2d12,stroke-width:2px classDef zpd fill:#dbeafe,stroke:#2563eb,color:#1e3a8a,stroke-width:3px classDef locked fill:#f5f5f4,stroke:#a8a29e,color:#78716c

Assessment · 2026-08-24

ProbeResult
Q1 · slow vs. racyPartial. Defined racy purely as inter-test contention. Missing: a solo test can race the application's own asynchrony. Conflates the ~45% category with the ~20% one.
Q2 · worker collision surfacePartial. Strong on the system under test. Correct instinct that separate processes share little memory. Missed the on-disk and cross-cutting surfaces: storageState, seed artefacts, ports, output dirs.
Q3 · await expect placementCorrect and precise. Named the polling distinction unprompted. Treated as mastered.
Q4 · retry legitimacyHealthy instinct, absolutist. "Never acceptable" is right about retry-as-fix, misses retry-as-instrument (counted, budgeted, ratcheted). Refined in A1 §6.
Q5 · isolation strategiesBlank — the clearest gap. Produced two of six-ish rungs and no cost analysis. This defines the ZPD.

Assessment · 2026-09-08

Five single-part probes after the scope widened. Answers were terse and honest; three clean blanks, which is what defined the C-block.

ProbeResult
Q1 · which actionability check fails under an overlayBlank. The check list is not held at all — which means every timeout is currently read as an undifferentiated timeout. Foundational, and independent of A2–A4, so it became C1. (Also: I said six checks; there are five.)
Q2 · name for a test that fails only in the suiteMechanism right, vocabulary missing. Named order dependency via shared mutable state, and load, unprompted — A1 landed. Did not produce victim, and the polluter/cleaner triple is not yet available. Cheap to close inside A2/A3 rather than needing its own lesson.
Q3 · how a 9th worker reddens a correct testCorrect. "Resource contention, e.g. lower CPU." Treat as mastered. Escalation path is the literature term — resource-affected flakes, Parry et al. TSE 2024 — and the config consequence, not the mechanism.
Q4 · how refetchOnWindowFocus flakes a specBlank. The TanStack cache is not yet modelled as a nondeterminism source. Notable because the suite already has app-idle absorbing the symptom, so the gap is invisible in day-to-day work. Became C2.
Q5 · criterion for keeping a behaviour out of e2e/Blank — the most expensive one. No level-allocation model, which is consistent with a suite that has exactly one level. This is the only lever that moves flake rate and CI wall-clock together. Became C3.

Suite findings feeding the path

Read on 2026-09-08, after the scope widened:

Lessons

A1 · inner fringe · completed 2026-08-25
Naming the Flake

Taxonomy, glossary, symptom-first diagnosis, retry policy. Ends with your suite classified.

Covers: E · F · G

A2 · outer fringe · ready · start here
The Isolation Ladder

Seven rungs from share-everything to a tenant per test, priced. A rung per resource, not per suite. Places your six main resources on it.

Covers: H · closes the Q5 blank

A3 · outer fringe · ready
The Collision Surface Audit

Four questions, seven layers. The procedure that catches the non-database surfaces — auth artefacts, filesystem, ports, background jobs. Applied to this repo.

Covers: J · closes the Q2 gap

A4 · outer fringe · ready
Fixture Scope Is a Sharing Decision

Run / worker / test / ambient scope as blast radius. Scope contagion, the three teardown failures, and your suite's scope map.

Covers: I

C1 · outer fringe · ready · cheapest start
The Five Checks

Playwright's actionability checks, which action runs which, and the row that explains why hotkey helpers must own their waits. Ends with a force: audit of your repo.

Covers: P · closes the Q1 blank · prerequisite for T and V

C2 · outer fringe · ready
The Determinism Inventory

The five environmental inputs to a test result. TanStack's defaults read as a hazard list, why app-idle absorbs rather than fixes, and the trap in page.clock for gesture specs.

Covers: Q · closes the Q4 blank

C3 · outer fringe · ready · highest leverage
Size, Scope, and What Belongs in e2e/

Size vs scope as independent axes, the five-clause criterion for an e2e spec, Khorikov's four pillars as the honest counter-argument, and the empty medium tier priced three ways.

Covers: R · closes the Q5 blank · unlocks the team-standards work

B-block · locked until A2–A4 land
Per-tenant isolation · serialisation primitives · cleanup contracts · convergent assertions · flake budgets

K, L, M, N, O. Pick which after A2–A4.

D-block · locked until C1–C3 land
Flakiness scoring · trace-driven diagnosis · network fault injection · canvas without pixels · sharding economics

S, T, U, V, W. S additionally blocked on resolving where per-spec outcome history lives.

Recommended order

C1 → A2 → C3 → C2 → A3 → A4. C1 first because it is 15 minutes and every later diagnosis depends on it. A2 second because the isolation ladder was already the biggest single win before today and still is. C3 third because it is the only lever that moves flake rate and CI time together, and because the team-standards goal blocks on it.

Findings surfaced while writing A2–A4

Read from the suite; each is used as a worked example in the lesson noted.

Teaching preferences