Skip to content

staging → main: contract tests and a credential-free Playwright suite - #244

Merged
holkexyz merged 1 commit into
mainfrom
staging
Aug 12, 2026
Merged

holkexyz merged 1 commit into
mainfrom
staging

Conversation

@holkexyz

@holkexyz holkexyz commented Aug 12, 2026 •

Copy link
Copy Markdown
Member

Adds the test layers that can catch a client/server mismatch, plus the doc and setup fixes that go with them. One commit, 16 files.

Why

The vitest suite (147 files, ~1235 tests) is dense on utilities but every test is single-layer — the client/server seam is always cut with vi.mock or a stubbed fetch. That is precisely how the org.hypercerts.context.attachment allowlist gap shipped in #241: the client sent the right collection, the server correctly rejected non-allowlisted collections, and each side passed its own tests. Only the pair was wrong.

Tier 1 — contract tests, no browser

  • Indexer operation contract — scans src/ for every operationName passed to postIndexer/getIndexer and asserts it exists in the server's OPERATIONS map. A missing entry is a runtime 400 that no other test can see. Currently 20 call sites, 19 distinct operations, all present.
  • public-read-methods — pins the signed-out read boundary behaviourally (getRecord/listRecords/sync.getBlob public, everything else 401), so it can neither silently widen nor narrow.

Tier 2 — Playwright, zero credentials

/dev/preview/{surface} already mounted the real production components against fixtures via MockFetchProvider; it had only ever been driven by the screenshot script. It is now a test suite:

  • 8 surfaces across populated / ?fixture=empty / ?managed=1 / dark mode
  • a signed-out walk of the public routes asserting no console errors or uncaught exceptions
  • 39 tests, ~17s, with no ePDS, Redis, or indexer access

Runs as a separate e2e CI job so a flaky browser run is distinguishable from a broken build, and so it does not extend the critical path.

Tier 3 — authenticated flows, skipped by default

There is no password grant (OAuth + emailed OTP), but the cookie and OAuth halves of a session are stored independently and the OAuth half is keyed only by DID with a 30-day TTL. So one interactive login for a throwaway account lets global-setup mint cookies for a month. Ships the update create/edit/delete lifecycle spec — the flow that broke — and skips cleanly without E2E_TEST_DID, so CI and forks are unaffected.

Housekeeping

  • AGENTS.md claimed in three places that no tests exist. Replaced with §27 documenting the layout, the contract-test rule, and the CSRF origin discipline (host spelling + pinned port) that makes these suites reproducible.
  • Removed two manual test plans covering the retired /groups index and the removed notifications system — both described features that no longer exist.
  • Wired @testing-library/jest-dom and a global afterEach(cleanup) into test-setup.ts; both were already dependencies that were never imported.

Known tolerance

The preview harness patches fetch client-side only, so SSR renders empty while the client renders populated — a structural hydration mismatch. It is tolerated on /dev/preview only, never on real routes, which hydrate clean today.

Verification

tsc, typecheck:test, and lint clean. 1245 vitest tests pass. 39 e2e pass, 4 skip. Removing org.hypercerts.context.attachment from ALLOWED_WRITE_COLLECTIONS fails the contract test in 32ms and passes again when restored.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Quality Improvements

    • Added automated browser testing for public pages, authenticated activity updates, preview states, themes, redirects, and error handling.
    • Expanded API contract and anonymous-access validation to help prevent regressions.
  • Developer Experience

    • Added consistent test setup, browser configuration, authentication fixtures, and failure diagnostics.
    • CI now runs end-to-end tests alongside verification and preserves reports for failed runs.
  • Documentation

    • Updated testing guidance and quality gates, including linting, type checks, tests, and production builds.

The vitest suite (147 files, ~1235 tests) is dense on utilities but every
test is single-layer: the client/server seam is always cut with vi.mock or
a stubbed fetch. That is why the org.hypercerts.context.attachment
allowlist gap shipped — client and server were each correct, only the pair
was wrong. Adds the two layers that can see a mismatch.

Tier 1 — contract tests, no browser:
  - indexer operation contract: scans src/ for every operationName passed
    to postIndexer/getIndexer and asserts it exists in the server's
    OPERATIONS map. A missing entry is a 400 at runtime and invisible to
    every other test. Currently 20 call sites, 19 distinct operations.
  - public-read-methods: pins the signed-out read boundary behaviourally
    (getRecord/listRecords/getBlob public; everything else 401) so it
    cannot silently widen or narrow.

Tier 2 — Playwright, no credentials. /dev/preview/{surface} already mounts
the real production components against fixtures via MockFetchProvider; it
was only ever driven by the screenshot script. Adds playwright.config.ts
plus specs covering the 8 surfaces across populated/empty/managed
scenarios and dark mode, and a signed-out walk of the public routes
asserting no console errors or uncaught exceptions. 39 pass in ~17s
against next dev, with no ePDS, Redis, or indexer access.

Tier 3 — authenticated flows, scaffolded and skipped by default. There is
no password grant (OAuth + emailed OTP), but the cookie and OAuth halves
of a session are stored independently, so one interactive login for a
throwaway account lets global-setup mint cookies for 30 days. Ships the
update create/edit/delete lifecycle spec; skips cleanly without
E2E_TEST_DID so CI and forks are unaffected.

Also: the preview harness mocks fetch client-side only, so its SSR/client
hydration mismatch is structural — tolerated on /dev/preview only, never
on real routes, which hydrate clean today.

Housekeeping: AGENTS.md claimed in three places that no tests exist; adds
§27 documenting the layout, the contract-test rule, and the CSRF origin
discipline that makes these suites reproducible. Removes two manual test
plans covering the retired /groups index and the removed notifications
system. Wires @testing-library/jest-dom and a global afterEach(cleanup)
into test-setup.ts — both were dependencies that were never imported.

Verified: tsc, typecheck:test, lint clean; 1245 vitest tests pass;
39 e2e pass / 4 skip. Removing the collection from ALLOWED_WRITE_COLLECTIONS
fails the contract test in 32ms.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@vercel

vercel Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

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

Project Deployment Actions Updated (UTC)
certified-app Ready Ready Preview Aug 12, 2026 3:51pm

Request Review

@coderabbitai

coderabbitai Bot commented Aug 12, 2026 •

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 4a8ffbe5-c92a-424e-82c0-bae1f7c09838

📥 Commits

Reviewing files that changed from the base of the PR and between 97d8593 and 4f244c5.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (15)
  • .github/workflows/ci.yml
  • .gitignore
  • AGENTS.md
  • e2e/auth/global-setup.ts
  • e2e/auth/update-lifecycle.spec.ts
  • e2e/helpers.ts
  • e2e/public-routes.spec.ts
  • e2e/smoke.spec.ts
  • package.json
  • playwright.config.ts
  • src/app/api/indexer/__tests__/operation-contract.test.ts
  • src/app/api/xrpc/[...method]/__tests__/public-read-methods.test.ts
  • src/test-setup.ts
  • tests/groups.test-plan.md
  • tests/notifications.test-plan.md

📝 Walkthrough

Walkthrough

The pull request adds Vitest contract tests and Playwright coverage for API boundaries, public routes, preview surfaces, and authenticated update lifecycles. It also adds local authentication setup, CI execution, shared helpers, and testing documentation.

Changes

Automated testing

Layer / File(s) Summary
Vitest API contracts and test setup
src/app/api/indexer/__tests__/operation-contract.test.ts, src/app/api/xrpc/[...method]/__tests__/public-read-methods.test.ts, src/test-setup.ts
Adds indexer operation validation, XRPC authentication-boundary tests, and automatic React Testing Library cleanup.
Playwright configuration and browser coverage
package.json, playwright.config.ts, e2e/helpers.ts, e2e/public-routes.spec.ts, e2e/smoke.spec.ts, .gitignore
Adds Playwright scripts, Chromium configuration, shared diagnostics and navigation helpers, public-route tests, preview smoke tests, and output exclusions.
Authenticated update lifecycle
e2e/auth/global-setup.ts, e2e/auth/update-lifecycle.spec.ts
Creates Redis-backed session state and tests authenticated update creation, editing, deletion, and cleanup requirements.
CI and testing guidance
.github/workflows/ci.yml, AGENTS.md, tests/*.test-plan.md
Adds a concurrent Playwright CI job, documents the Vitest and Playwright test stack, and removes the replaced manual test plans.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant CI
  participant Playwright
  participant DevServer
  participant Redis
  CI->>Playwright: Start browser tests
  Playwright->>DevServer: Run E2E scenarios
  Playwright->>Redis: Use seeded authenticated session when configured
  DevServer-->>Playwright: Return rendered pages and API responses
  Playwright-->>CI: Report test results and failure artifacts
Loading

Possibly related PRs

Suggested reviewers: holkeb

✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch staging

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@socket-security

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Added@​playwright/​test@​1.60.010010010099100

View full report

@holkexyz
holkexyz marked this pull request as ready for review August 12, 2026 15:58
@holkexyz
holkexyz merged commit 6753417 into main Aug 12, 2026
7 of 9 checks passed

This branch was successfully deployed

1 active deployment
staging — 4f244c55 Deployed Aug 12, 2026 by vercel[bot]
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