feat(test): adopt @playwright/test + ship playwright.config.js + visual scaffold (P1 #10 step 2) #18

Merged
varutasu merged 3 commits from convoy/adopt-playwright-smoke into main 2026-05-24 20:25:18 -04:00
varutasu commented 2026-05-24 19:47:23 -04:00 (Migrated from github.com)

Summary

Closes P1 #10 step 2 / launch sequence step 10 in .convoys/ship-readiness.md. Three previous convoys laid the infra (bump-next-js got Vercel deploys working again, fix-vercel-deployment-protection-in-ci got the wait-action through the SSO challenge, fix-layout-default-user shipped the sign-in UI the smoke spec asserts on); this convoy wires the actual @playwright/test dep, the playwright.config.js that bridges env to extraHTTPHeaders, three npm scripts, and a single visual spec so the screenshot workflow has something to discover.

After merge, every PR's Playwright smoke workflow reaches npx playwright test and runs the 3 existing smoke tests against the Vercel preview — either green or red on real assertions, no more "playwright not installed" fast-fail.

Convoy artifacts

  • Convoy file: .convoys/adopt-playwright-smoke.md (architect ratified 6 decisions: 3 self + 3 operator)
  • Single brief: .convoys/adopt-playwright-smoke/brief-1-wire-playwright-and-visual-spec.md
  • Architect commit: 3ac527e
  • Implementer commit: c72d006

Decisions ratified

Decision Choice Notes
1 .ts vs .js for specs Keep .ts Empirically npx eslint tests/smoke/app.smoke.spec.ts exits 0 today
2 Missing-secret behavior CI fail-loud, dev warn-and-continue Mirrors lib/rate-limit.js fail-closed (AGENTS.md Gotcha #12)
3 One project or two Two projects, two directories Matches workflows' `--project=smoke
4 First-run baselines Defer to follow-up convoy Architect Boot-the-brief Finding 7: Playwright's custom snapshotPathTemplate has no {platform} token, so Mac-generated baseline would silently overwrite Linux CI baseline. Queued seed-visual-baselines-on-linux.
5 ESLint coverage for tests/ No config change Empirical: eslint parses .ts spec cleanly today
6 Local-test script ergonomics Simple scripts, no auto-boot Matches test:run pattern

Diff

5 files, +246 / -1. Mechanical lockfile churn dominates the byte count:

 .gitignore                    |   7 +++
 package-lock.json             |  64 ++++++++++++++++++++
 package.json                  |   6 +-
 playwright.config.js          | 133 ++++++++++++++++++++++++++++++++++++++++++
 tests/visual/homepage.spec.ts |  37 ++++++++++++
 5 files changed, 246 insertions(+), 1 deletion(-)

tests/smoke/app.smoke.spec.ts is byte-identical (Decision 1). eslint.config.mjs untouched (Decision 5). Workflow YAML untouched (PR #17 owned it). AGENTS.md untouched (doc-writer pass at convoy close handles the seed-on-Linux runbook).

Two implementer deviations (both behavior-neutral, lint-preserving)

A — removed unused eslint-disable-next-line no-console directive

The architect's verbatim shape would have regressed lint baseline (128 → 129) because the active eslint.config.mjs doesn't enable no-console for repo-root config files, making the directive itself reported as unused. Resolution: removed directive, added explanatory comment in its place. The console.warn itself is unchanged. Documented in commit message.

B — placed @playwright/test first in devDependencies (alphabetical)

The brief's prose said "between @testing-library/react and autoprefixer" but @p < @t alphabetically. Resolution: placed FIRST in devDeps to preserve alphabetization per the brief's overarching principle.

Verification

Check Result
npm ci exit 0 (lockfile in sync)
npm run lint exit 1, 128 problems (baseline match)
npm run test:run (vitest) 21/21 (no regression)
npx playwright --version 1.60.0
npx playwright test --list --project=smoke enumerates 3 tests from tests/smoke/app.smoke.spec.ts
npx playwright test --list --project=visual enumerates 1 test from tests/visual/homepage.spec.ts
Dev-path (npm run test:smoke, no BASE_URL, no CI) Warns at config load, no throw, proceeds to test runner
CI-path (CI=true npm run test:smoke) Throws at config load with actionable error naming env var + rotation command + AGENTS.md reference. No secret value echoed.

Expected CI behavior

With @playwright/test + config + bypass header now wired:

  • Playwright smoke: wait-action ~200ms → npm ci + browser install → 3 smoke tests run against Vercel preview with x-vercel-protection-bypass header set. Either green or red on real assertions.
  • Screenshot diff: NOT triggered on this PR (path filter excludes test-infra-only PRs). Will fire on next PR touching pages/**/components/**/styles/**. First run will fail (no baseline yet) but continue-on-error: true swallows it and the comment-on-PR step posts the run link.
  • All other checks: unchanged from main.

First-time baseline seeding (post-merge follow-up)

The seed-visual-baselines-on-linux convoy will:

  1. Run npm run test:visual:update in mcr.microsoft.com/playwright:v1.60.0-noble Docker (so the PNG matches what Linux CI produces)
  2. Commit tests/visual/__screenshots__/home.png
  3. Open a tiny baseline-only PR

tests/visual/homepage.spec.ts has an inline JSDoc comment documenting this exact procedure with the verbatim Docker command.

Out of scope (deferred / pre-existing)

  • seed-visual-baselines-on-linux — first-run baseline curation in a Linux env (architect Boot-the-brief Finding 7)
  • Re-enabling the test: job in .github/workflows/ci.yml — P1 #10 step 3 in ship-readiness; separate convoy
  • Deeper E2E test coverage — feature convoys add their own smoke tests as they ship
  • AGENTS.md § 7 seed-on-Linux runbook — doc-writer pass at convoy close

Test plan

  • npm ci exits 0
  • npm run lint matches 128 baseline
  • npm run test:run 21/21
  • Spec discovery (--list) works for both projects
  • Dev-path: warn-no-throw
  • CI-path: throw with actionable message, no secret echo
  • CI confirms Playwright smoke reaches npx playwright test step (verify post-push)
  • CI confirms 3 smoke tests run against Vercel preview with bypass header (verify post-push)
  • Manual: grep workflow run log for bypass secret's first 8 chars → expect zero matches

Made with Cursor

## Summary Closes P1 #10 step 2 / launch sequence step 10 in `.convoys/ship-readiness.md`. Three previous convoys laid the infra (`bump-next-js` got Vercel deploys working again, `fix-vercel-deployment-protection-in-ci` got the wait-action through the SSO challenge, `fix-layout-default-user` shipped the sign-in UI the smoke spec asserts on); this convoy wires the actual `@playwright/test` dep, the `playwright.config.js` that bridges env to `extraHTTPHeaders`, three npm scripts, and a single visual spec so the screenshot workflow has something to discover. After merge, **every PR's `Playwright smoke` workflow reaches `npx playwright test` and runs the 3 existing smoke tests against the Vercel preview** — either green or red on real assertions, no more "playwright not installed" fast-fail. ## Convoy artifacts - Convoy file: `.convoys/adopt-playwright-smoke.md` (architect ratified 6 decisions: 3 self + 3 operator) - Single brief: `.convoys/adopt-playwright-smoke/brief-1-wire-playwright-and-visual-spec.md` - Architect commit: `3ac527e` - Implementer commit: `c72d006` ## Decisions ratified | | Decision | Choice | Notes | |---|---|---|---| | 1 | `.ts` vs `.js` for specs | **Keep .ts** | Empirically `npx eslint tests/smoke/app.smoke.spec.ts` exits 0 today | | 2 | Missing-secret behavior | **CI fail-loud, dev warn-and-continue** | Mirrors `lib/rate-limit.js` fail-closed (AGENTS.md Gotcha #12) | | 3 | One project or two | **Two projects, two directories** | Matches workflows' `--project=smoke|visual` invocations | | 4 | First-run baselines | **Defer to follow-up convoy** | Architect Boot-the-brief Finding 7: Playwright's custom `snapshotPathTemplate` has no `{platform}` token, so Mac-generated baseline would silently overwrite Linux CI baseline. Queued `seed-visual-baselines-on-linux`. | | 5 | ESLint coverage for `tests/` | **No config change** | Empirical: eslint parses .ts spec cleanly today | | 6 | Local-test script ergonomics | **Simple scripts, no auto-boot** | Matches `test:run` pattern | ## Diff 5 files, **+246 / -1**. Mechanical lockfile churn dominates the byte count: ``` .gitignore | 7 +++ package-lock.json | 64 ++++++++++++++++++++ package.json | 6 +- playwright.config.js | 133 ++++++++++++++++++++++++++++++++++++++++++ tests/visual/homepage.spec.ts | 37 ++++++++++++ 5 files changed, 246 insertions(+), 1 deletion(-) ``` `tests/smoke/app.smoke.spec.ts` is byte-identical (Decision 1). `eslint.config.mjs` untouched (Decision 5). Workflow YAML untouched (PR #17 owned it). `AGENTS.md` untouched (doc-writer pass at convoy close handles the seed-on-Linux runbook). ## Two implementer deviations (both behavior-neutral, lint-preserving) ### A — removed unused `eslint-disable-next-line no-console` directive The architect's verbatim shape would have regressed lint baseline (128 → 129) because the active `eslint.config.mjs` doesn't enable `no-console` for repo-root config files, making the directive itself reported as unused. Resolution: removed directive, added explanatory comment in its place. The `console.warn` itself is unchanged. Documented in commit message. ### B — placed `@playwright/test` first in `devDependencies` (alphabetical) The brief's prose said "between `@testing-library/react` and `autoprefixer`" but `@p` < `@t` alphabetically. Resolution: placed FIRST in devDeps to preserve alphabetization per the brief's overarching principle. ## Verification | Check | Result | |---|---| | `npm ci` | exit 0 (lockfile in sync) | | `npm run lint` | exit 1, **128 problems** (baseline match) | | `npm run test:run` (vitest) | **21/21** (no regression) | | `npx playwright --version` | `1.60.0` | | `npx playwright test --list --project=smoke` | enumerates 3 tests from `tests/smoke/app.smoke.spec.ts` | | `npx playwright test --list --project=visual` | enumerates 1 test from `tests/visual/homepage.spec.ts` | | Dev-path (`npm run test:smoke`, no `BASE_URL`, no `CI`) | Warns at config load, no throw, proceeds to test runner | | CI-path (`CI=true npm run test:smoke`) | Throws at config load with actionable error naming env var + rotation command + AGENTS.md reference. No secret value echoed. | ## Expected CI behavior With `@playwright/test` + config + bypass header now wired: - `Playwright smoke`: wait-action ~200ms → npm ci + browser install → 3 smoke tests run against Vercel preview with `x-vercel-protection-bypass` header set. Either green or red on real assertions. - `Screenshot diff`: NOT triggered on this PR (path filter excludes test-infra-only PRs). Will fire on next PR touching `pages/**`/`components/**`/`styles/**`. First run will fail (no baseline yet) but `continue-on-error: true` swallows it and the comment-on-PR step posts the run link. - All other checks: unchanged from main. ## First-time baseline seeding (post-merge follow-up) The `seed-visual-baselines-on-linux` convoy will: 1. Run `npm run test:visual:update` in `mcr.microsoft.com/playwright:v1.60.0-noble` Docker (so the PNG matches what Linux CI produces) 2. Commit `tests/visual/__screenshots__/home.png` 3. Open a tiny baseline-only PR `tests/visual/homepage.spec.ts` has an inline JSDoc comment documenting this exact procedure with the verbatim Docker command. ## Out of scope (deferred / pre-existing) - **`seed-visual-baselines-on-linux`** — first-run baseline curation in a Linux env (architect Boot-the-brief Finding 7) - **Re-enabling the `test:` job in `.github/workflows/ci.yml`** — P1 #10 step 3 in ship-readiness; separate convoy - **Deeper E2E test coverage** — feature convoys add their own smoke tests as they ship - **`AGENTS.md` § 7 seed-on-Linux runbook** — doc-writer pass at convoy close ## Test plan - [x] `npm ci` exits 0 - [x] `npm run lint` matches 128 baseline - [x] `npm run test:run` 21/21 - [x] Spec discovery (`--list`) works for both projects - [x] Dev-path: warn-no-throw - [x] CI-path: throw with actionable message, no secret echo - [ ] CI confirms `Playwright smoke` reaches `npx playwright test` step (verify post-push) - [ ] CI confirms 3 smoke tests run against Vercel preview with bypass header (verify post-push) - [ ] Manual: grep workflow run log for bypass secret's first 8 chars → expect zero matches Made with [Cursor](https://cursor.com)
vercel[bot] commented 2026-05-24 19:47:28 -04:00 (Migrated from github.com)

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
tcg-vault Ready Ready Preview, Comment May 24, 2026 11:47pm

Request Review

[vc]: #iVz6UeHQFU0ZXGJZJiOcrNyNueQolX7Rsld4l6V3glQ=:eyJpc01vbm9yZXBvIjp0cnVlLCJ0eXBlIjoiZ2l0aHViIiwicHJvamVjdHMiOlt7Im5hbWUiOiJ0Y2ctdmF1bHQiLCJwcm9qZWN0SWQiOiJwcmpfRjZXOEVvRkd3Y0g3aWVGcnRvRlNlOXdVVkFhNSIsImxpdmVGZWVkYmFjayI6eyJyZXNvbHZlZCI6MCwidW5yZXNvbHZlZCI6MCwidG90YWwiOjAsImxpbmsiOiJ0Y2ctdmF1bHQtZ2l0LWNvbnZveS1hZG9wdC1wLWUzNmEzYi1yYW5kYWxsLXN0aWxsd2VsbHMtcHJvamVjdHMudmVyY2VsLmFwcCJ9LCJpbnNwZWN0b3JVcmwiOiJodHRwczovL3ZlcmNlbC5jb20vcmFuZGFsbC1zdGlsbHdlbGxzLXByb2plY3RzL3RjZy12YXVsdC8zTGp6QjdxVXNpZGVSOFBrMVJYNDJhMkhzWEdOIiwicHJldmlld1VybCI6InRjZy12YXVsdC1naXQtY29udm95LWFkb3B0LXAtZTM2YTNiLXJhbmRhbGwtc3RpbGx3ZWxscy1wcm9qZWN0cy52ZXJjZWwuYXBwIiwibmV4dENvbW1pdFN0YXR1cyI6IkRFUExPWUVEIn1dLCJyZXF1ZXN0UmV2aWV3VXJsIjoiaHR0cHM6Ly92ZXJjZWwuY29tL3ZlcmNlbC1hZ2VudC9yZXF1ZXN0LXJldmlldz9vd25lcj12YXJ1dGFzdSZyZXBvPXRjZy12YXVsdCZwcj0xOCJ9 The latest updates on your projects. Learn more about [Vercel for GitHub](https://vercel.link/github-learn-more). | Project | Deployment | Actions | Updated (UTC) | | :--- | :----- | :------ | :------ | | [tcg-vault](https://vercel.com/randall-stillwells-projects/tcg-vault) | ![Ready](https://vercel.com/static/status/ready.svg) [Ready](https://vercel.com/randall-stillwells-projects/tcg-vault/3LjzB7qUsideR8Pk1RX42a2HsXGN) | [Preview](https://tcg-vault-git-convoy-adopt-p-e36a3b-randall-stillwells-projects.vercel.app), [Comment](https://vercel.live/open-feedback/tcg-vault-git-convoy-adopt-p-e36a3b-randall-stillwells-projects.vercel.app?via=pr-comment-feedback-link) | May 24, 2026 11:47pm | <a href="https://vercel.com/vercel-agent/request-review?owner=varutasu&repo=tcg-vault&pr=18" rel="noreferrer"><picture><source media="(prefers-color-scheme: dark)" srcset="https://agents-vade-review.vercel.sh/request-review-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://agents-vade-review.vercel.sh/request-review-light.svg"><img src="https://agents-vade-review.vercel.sh/request-review-light.svg" alt="Request Review"></picture></a>
github-actions[bot] commented 2026-05-24 19:47:32 -04:00 (Migrated from github.com)

Pipeline Health

Build + CI gates

Gate Status
Vercel build (Preview) pass
CI: Lint pass
CI: Schema map fresh skipped
Preview smoke pass
Visual diff ⏭ skipped or pending

Build runs on Vercel; this CI runs lint and schema-map drift only (no duplicate build).

Role reports

Role Status
Reviewer report pending
A11y audit pending
Design system audit pending

See individual comments above for details. This rollup updates automatically.

<!-- pipeline-rollup --> ## Pipeline Health ### Build + CI gates | Gate | Status | | --- | --- | | Vercel build (Preview) | ✅ pass | | CI: Lint | ✅ pass | | CI: Schema map fresh | ❌ skipped | | Preview smoke | ✅ pass | | Visual diff | ⏭ skipped or pending | _Build runs on Vercel; this CI runs lint and schema-map drift only (no duplicate build)._ ### Role reports | Role | Status | | --- | --- | | Reviewer report | ⏳ pending | | A11y audit | ⏳ pending | | Design system audit | ⏳ pending | See individual comments above for details. This rollup updates automatically.
Sign in to join this conversation.
No description provided.