# End-to-end tests (`tests/e2e/`)

Hand-written behavioral tests that drive the running SpecVerse runtime
through a real browser.

## How this differs from `tests/contract/`

| | `tests/contract/` | `tests/e2e/` |
|---|---|---|
| **Source** | Auto-generated by `spv realize` from spec inference rules | Hand-written by you |
| **Purpose** | Verify the framework honors the spec contract | Verify your specific user journeys |
| **Config** | `playwright.contract.config.ts` (regenerated, do not edit) | `playwright.config.ts` (yours, edit freely) |
| **Lifecycle** | Wiped + regenerated on every `spv realize` | Persistent — your tests stay |

Both use Playwright and both import helpers from
`@specverse/runtime/test-harness`. The harness exposes spec-level
verbs (`createEntity`, `navigateToModel`, `expectEntityInList`,
`expectLifecycleState`) so test code stays stable across runtime
internal rewrites.

## Running

```bash
# 1. Install Playwright browsers (once)
npx playwright install chromium

# 2. Boot backend + frontend in two terminals
npm run dev:backend
npm run dev:frontend

# 3. Run e2e tests
npm run test:e2e
```

In CI, use a single script that starts both servers in the background,
waits for both ports, then runs `npm run test:e2e`.

## Writing a test

Start from `example.spec.ts` and replace the placeholder journey with
something specific to your spec. Helpful imports:

```ts
import { test, expect } from '@playwright/test';
import {
  bootRuntime,
  navigateToModel,
  navigateToModelForm,
  createEntity,
  deleteEntity,
  evolveEntity,
  expectEntityInList,
  expectEntityAbsent,
  expectLifecycleState,
  expectActionButton,
} from '@specverse/runtime/test-harness';
```

The harness's design contract: helpers describe **what** the user
does, not **how** the runtime renders it. Your tests should not
contain CSS selectors, React Query keys, or DOM IDs — if you find
yourself reaching for those, the helper you need is probably missing
from the harness. File an issue.
