project-e2elisted
Install: claude install-skill ubermuda/loupe
# E2E Tests
## General rules
- **CI's `e2e` check gates the suite. Run it locally only to work on one spec.** Push and read the check instead of running the full suite before a PR. Locally the suite is slower, destructive, and prone to failures that belong to the environment, not the diff (see `working-with-prs`). One spec: `just e2e tests/<area>/<spec>.spec.ts`.
- Never fix a failing test by manipulating the database (resetting passwords, deleting rows). A test that needs a specific DB state must create that state. A fix that needs a one-time DB operation breaks again on the next fresh environment.
## Turbo Drive navigation
Turbo Drive performs form submissions as XHR and pushes state with `history.pushState`. So `page.waitForURL(pattern)` waits for a `load` event that never comes. Use `expect(page).toHaveURL(pattern)`, which polls.
After a POST that redirects **to a different page**, assert that an element of the destination page is visible; that is safer than asserting the URL. When the redirect returns to **the same URL**, `toHaveURL` resolves immediately, so assert the updated form value instead (see below).
```typescript
// ✗ fails with Turbo — URL already matches before XHR completes
await page.waitForURL(/\/some\/path/);
// ✓ polls for URL without requiring a load event
await expect(page).toHaveURL(/\/some\/path/);
// �� even better — assert visible content from the destination page
await expect(page.getByRole('button', { name: 'Submit' })).toBeVisible();
```