test(e2e): Playwright harness and smoke suite #329
No reviewers
Labels
No labels
area:auth
area:ci
area:db
area:infra
area:native
area:pwa
area:service
epic
feature
foundation
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
james/carol!329
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "test/e2e-playwright-foundation"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
What
Stands up Carol's first browser-level e2e: a new
@carol/e2eworkspace (apps/e2e/) with a Playwright harness that boots the assembled app and one smoke spec that drives it end to end. This is the foundation slice of #150 — broader coverage is split into child tickets.Closes #150
How the harness boots the app
Playwright's
webServerrunsscripts/serve.sh, which is build-aware and idempotent:pnpm -F @carol/client export:webifapps/client/distis missing.pnpm -F @carol/api buildifapps/api/.nextis missing.pnpm -F @carol/api start— the Next.js API serving/api/*and the built Expo RN-Web SPA (SPA_BUNDLE_PATH=apps/client/dist) against a throwaway file-backed SQLite underapps/e2e/.tmp/, wiped on every boot.Readiness gates on
GET /api/health;reuseExistingServeris on outside CI. Chromium + SQLite only;retries: 2andtrace: on-first-retryin CI.A note on the DB: the plan called for
sqlite::memory:, butnext startapplies migrations from the instrumentation hook, whose module graph is separate from the API route handlers in a production build — a libsql:memory:DB isn't shared across those two module instances, so requests hit an unmigrated (empty) DB ("no such table: users"). A throwaway file DB is shared by every connection in the process and still fresh per boot, so it preserves the plan's intent while actually working. Documented inserve.shand the workspace README.Smoke flow (
tests/smoke.spec.ts)One ordered spec: register a
uniqueEmail()user (fresh DB ⇒ first user is admin, lands authenticated at/notes) → assert the sidebar renders → create a note and assert it appears → navigate two sidebar destinations, asserting the route changes → log out (redirect to/login) → log back in and assert authenticated.Selector + CI conventions
getByPlaceholder; buttons viagetByRole('button', { name }); nav by visible label text; log-out by its existingaccessibilityLabel.packages/i18n/messages/en.json) throughfixtures/strings.ts.apps/client/app/(app)/notes.tsx: onetestID="note-row"on the list item (RN-Web →data-testid) so the created note is unambiguous; plusaccessibilityRole="button"on the create button.apps/client/app/login.tsx,register.tsx:accessibilityRole="button"on the submit buttons. Their visible label equals the screen heading, so without a button role they were ambiguous — and these primary actions genuinely should expose a button role to assistive tech (the OAuth/log-out buttons already do). An accessibility improvement, not test-only scaffolding.e2ejob in.forgejo/workflows/pr.ymlmirroring the existing scaffold (catthehacker image, the same SHA-pinnedactions/checkout+actions/setup-node,corepack enable,pnpm install --frozen-lockfile --ignore-scripts,pnpm rebuild), thenexport:web+api build+playwright install --with-deps chromium+pnpm -F @carol/e2e test. SQLite + Chromium only. No artifact-upload step — no SHA-pinnable artifact action is used elsewhere in the repo, so none was invented.No new runtime env var, so no README Configuration-table change.
Verification
pnpm -F @carol/e2e test— smoke spec passes headless Chromium (boots the app, all 6 steps green; verified across consecutive runs to confirm the per-boot DB wipe).pnpm -F @carol/e2e exec tsc --noEmit— clean.actionlint .forgejo/workflows/pr.yml— passes.pnpm -F @carol/client lint+typecheck— clean (touched client files).Follow-ups
storageStatefixture).🤖 Generated with Claude Code
📊 Test coverage
Patch coverage: no testable lines changed.
Overall (
app/,lib/,db/, excluding UI per ADR-0019):Soft thresholds per ADR-0019. Coverage is informational and does not block merge.