Skip to content

Run browser tests in parallel on per-worker accounts - #72

Merged
nicksan222 merged 15 commits into
mainfrom
perf/parallel-e2e
Oct 16, 2026
Merged

nicksan222 merged 15 commits into
mainfrom
perf/parallel-e2e

Conversation

@nicksan222

Copy link
Copy Markdown
Owner

Why

Browser tests were the slowest CI job: 4 shards × 6–8.5 min of Run browser tests (~29 job-minutes, ~10.5 min wall on main @ 339509a). Every spec signed in as the one shared demo user, built its trips/ideas/issues through the UI, and the suite ran serially within each file because all tests shared data.

What

  • Per-worker accounts. New @groam/app-actions/playwright/test fixture: each worker creates its own user + group through the backend, signs in once, and reuses that storageState. Tests share no data, so fullyParallel: true.
  • Arrange through the backend. arrange fixture creates trips, ideas (startIdea returns the working trip for idea edits), issues, review requests, and members. Specs drive only the journey under test through the UI; second users get newSignedOutPage().
  • Navigation helpers. openApp, openTrip, openIdea, openIssue wait for the canonical short-ID URL and return it.
  • Removed signIn (demo user), addGroupMemberViaInvite, the SEED_USER_* Playwright env, and the CI seed step. Sign-up / sign-in / invite flows keep their own UI specs.
  • CI. 2 shards × 2 workers instead of 4 shards; codegen verification runs once (shard 1); list reporter so logs show per-test durations. Jobs are now Browser (n/2).
  • Dev container. Installs Playwright's Chromium in post-create.sh and libnss3/libnspr4 in the Dockerfile (Chromium could not start before). Needs a container rebuild.

Verification

  • Pre-commit: codegen, vp check, conventions, React Doctor, Fallow — pass.
  • App-actions unit tests (36) and typecheck pass; a local fixture smoke spec passed in 3.6 s.
  • The full parallel suite has not run locally (local dev stack went down); this PR's CI run is the first full run, and I'm tracking its timings against main below.

Timings

Shards Run browser tests per shard Total job time Wall
main @ 339509a 4 359–507 s 1732 s ~10.5 min
this PR 2 pending pending pending

🤖 Generated with Claude Code

Each Playwright worker now creates its own user and group through the
backend, signs in once, and reuses that session. Specs arrange trips,
ideas, issues, and members through @groam/app-actions/backend and drive
only the journey under test through the UI, so the suite runs with
fullyParallel and CI needs two shards instead of four.

The dev container also installs Chromium and its libnss3/libnspr4
dependencies so browser tests run without manual setup.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-15T13:37:18.082513Z 874a02f PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

nicksan222 and others added 14 commits October 15, 2026 13:35
The e2e fixture imports the backend actions, which reach packages/ai
through its #ai subpath imports; map them as the seeder and app-actions
tsconfigs already do.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A shared Vitest setup routes console output through a guard: tests declare
output they produce on purpose with expectConsole(), which hides it, and
any other output fails the test. Every Vitest package now loads it.

Turning it on surfaced real problems behind the CI noise:
- Scheduled Idea reviews loaded their context through the signed-in
  viewer, so every review failed with "Not authenticated". The review
  context now reads the stored proposal directly, like the title agent.
- convex-test ran scheduled functions on real timers, so AI runs and
  Wikipedia cover lookups ran behind unrelated tests. Backend tests now
  fake setTimeout; agent tests opt back into real timers.
- The geospatial index logged every query at INFO.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Trip and idea redirects passed the resolved Convex ID back into the URL
while ReferenceProvider rewrote it to the short ID, so opening
/trips/<convex id> looped on "Opening page…". Redirects now keep the
reference as written and let ReferenceProvider canonicalize it once.

The backend addIdea action now names ideas by title, as the UI does, and
openSharedTrip waits for the canonical URL like the other open helpers.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Lint, typecheck, unit tests, browser tests, and desktop builds now start
together as separate jobs instead of waiting on one quality job, and the
browser suite runs as a single job. The showcase recording test declares
its progress output, and createTrip waits for the trip list to load before
opening the dialog.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Component and view tests run in real Chromium through the `views` setup of
`vp test` (page locators, retrying expect.element) instead of jsdom and
Testing Library. Browser e2e becomes the `journeys` setup: the real app
against the local backend, driven by @groam/app-actions/vitest, with backend
arrangements through Vitest browser commands. Playwright Test, jsdom, and
Testing Library are gone; the showcase keeps Playwright for recording.

Real browsers surfaced app fixes: per-group workspace remounts (no stale
pagination cursors), passkeys trusting every local origin on their host, a
single accessible "Attach files" control, labelled issue assignee rows, and
no React warning from the theme script.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Journeys now run in Vite+ browser mode, so the Playwright layer keeps only
what the showcase recording uses. Share the vitest types across packages
and split the itinerary fixture data from its stateful editor.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The 4-core runner starved the local Convex backend with four browsers, so
queries hit the 1s function limit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The server ends the Better Auth session before the client hears of it, so
workspace queries still mounted reran signed out and threw. The app shell
now unmounts the workspace first, and journeys leave the page before
switching people. CI journeys get a timeout sized for the shared runner and
upload their failure screenshots.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
requireWorkspace built a full Better Auth instance and called getSession
and getActiveMemberRole on every guarded function: several component
round trips that made up about 70% of backend CPU in journeys and pushed
queries past the 1s limit on CI. One component query now reads the
session, user, and membership; the guard keeps the same errors and also
rejects a session that belongs to someone else. Sign-out recovers when
the request throws.

CI warnings:
- Remove the dead desktop copy_dir helpers and the unused Turbo cache.
- Let the vendored glib allow the newer rustc lints it trips.
- Size the chunk warning for the single maplibre-gl module.
- Pin Ubuntu runners to 24.04.
- Keep Fallow from reading the backend dev script's -C as an entry.
- Share the phone list-row checks between the idea and issue lists.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…t drivers

Better Auth replaces or ends the session (sign-out, two-factor on or off,
password change) and switches the active group on the server before the
client hears of it, so mounted Convex subscriptions reran against the old
session or with the old group's pagination cursors. The app now hides the
workspace in an Activity, dropping its subscriptions, until Convex or the
session reports the change. A session index stops listSessions from
scanning every session, which returned duplicates through the Better
Auth adapter's pagination.

Journey drivers lose their retry loops, visibility branches, and dead
helpers; absence checks assert a landmark first; CI drops dead Turbo
settings, checks formatting once, pins runner images, and caches Rust
builds; docs and lint rules no longer describe Playwright journeys.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The repository only allows GitHub-owned actions and a short allowlist, so
Swatinem/rust-cache failed the workflow at startup.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Fallow's hotspot analysis needs git history, so Lint checks out the full
history again. A failing journey now keeps its trace in the uploaded
failure artifact.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1.6.26's client session atom read itself with get() while nanostores tore
it down, which mounted it again mid-teardown and left it active without a
refresh manager. A remount soon after an in-flight session fetch then never
refetched after sign-in or sign-up, so journeys that switch people stayed on
the auth screen under load. 1.6.33 reads the value directly.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Playwright 1.63 arms ProgressController's timer with an unclamped
`deadline - monotonicTime()`. Vitest polls elements through Playwright with
1 ms budgets, so on a busy CI runner the deadline has already passed and
Node prints TimeoutNegativeWarning in the journeys job. Patch it the way the
same file clamps its other deadline timer, until a release does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@nicksan222
nicksan222 merged commit 6973052 into main Oct 16, 2026
11 checks passed
@nicksan222
nicksan222 deleted the perf/parallel-e2e branch October 16, 2026 05:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant