---
name: development-testing-ui-test
description: >
  Phase 5 UI tests — drives dev-browser to navigate every scaffolded page,
  submit forms with role-based seeded users, and auto-correct failures via
  the existing fix-bug skill loop (max 50 iterations per test). Runs after
  the frontend scaffolders complete (routes + component + api-client +
  extension-config) and verifies the full backend ↔ frontend round-trip.
phase: development/testing
cli: cli/run-ui-test
allowed-tools: [Read, Glob, Grep, Bash]  # Bash: CLI invocation
---

# Phase 5 — UI Test (dev-browser, auto-correction)

After Phase 4 (seed-data) and Phase 4f (frontend scaffolders), Phase 5 verifies
that every page actually works with a real backend, real users, and real DB.
The previous phases produce code that COMPILES; Phase 5 ensures it RUNS.

## When to use

- Right after `scaffold-component` + `scaffold-routes` + `scaffold-api-client`
  finish for a module
- Whenever the user reports "the new page doesn't work" — Phase 5 reproduces
  + auto-fixes most 400/401/403/404/500/blank-page bugs
- Before announcing a module as "done"

## Prerequisites

1. **dev-runner is running** — backend + frontend must be live. The CLI does
   NOT spawn them (that's `dev-runner.ts`'s job). It pings `/health` first
   and fails clear if either is down.
2. **`tests/ui-test/test-users.json` exists** — produced by `scaffold-seed`
   when `testUsers[]` is non-empty. One user per role.
3. **`tests/ui-test/manifest.json` exists** — produced by `build-manifest` from
   the same spec that drove scaffold-controller + scaffold-component. Lists
   one test per (entity × scenario × role) tuple.
4. **`dev-browser` installed** — `npm install --save-dev dev-browser@0.2.7
   && npx dev-browser install` (downloads bundled Chromium via Playwright).

## Two CLIs in this skill

### `cli/build-manifest/` (generate sub-pattern)

Reads a self-contained spec (entities + roles per scenario + fixtures) and
emits `tests/ui-test/manifest.json`. Invoke after frontend scaffolders for a
module, before run-ui-test.

```bash
npx --prefer-offline tsx skills/development/testing/ui-test/cli/build-manifest/index.ts \
  --spec '{"module":"hrm","appCode":"myapp","projectPath":"/abs/path","entities":[
    {"name":"Employee","section":"employees","plural":"employees",
     "rolesWithRead":["admin","manager"],
     "rolesWithCreate":["admin"],
     "rolesWithUpdate":["admin"],
     "rolesWithDelete":["admin"],
     "rolesWithoutAccess":["viewer"],
     "fixture":{"firstName":"Alice","lastName":"Test","email":"alice@t.local"}}
  ]}'
```

### `cli/run-ui-test/` (execute sub-pattern)

Runs each test ONCE via `dev-browser --headless`, emits an envelope on stdout
with all results. Auto-correction is NOT in this CLI — it lives in the Studio
runner (`src/backend/application/runners/ui-test-runner.ts`) which wraps the
CLI in a 50-iteration retry loop with `claude -p fix-bug` between iterations.

```bash
npx --prefer-offline tsx skills/development/testing/ui-test/cli/run-ui-test/index.ts \
  --project-path /abs/path \
  --frontend-url http://localhost:5173 \
  --api-url http://localhost:5142 \
  --module hrm \
  --test-id <optional> \
  --manifest-path <optional> \
  --users-path <optional> \
  --capture-dir <optional> \
  --timeout-ms <optional>
```

| Flag | Type | Default | Notes |
|------|------|---------|-------|
| `--project-path` | string | required | Absolute path to project root. |
| `--frontend-url` | string | required | Frontend URL (e.g. `http://localhost:5173`). |
| `--api-url` | string | required | API URL (e.g. `http://localhost:5142`). |
| `--module` | string | optional | Module filter (run tests only for this module). |
| `--test-id` | string | optional | Run only one test by ID. |
| `--manifest-path` | string | `tests/ui-test/manifest.json` | Path to test manifest (relative to project root). |
| `--users-path` | string | `tests/ui-test/test-users.json` | Path to test users (relative to project root). |
| `--capture-dir` | string | `tests/ui-test/captures` | Directory for screenshots (relative to project root). |
| `--timeout-ms` | integer | `60000` | Test timeout in milliseconds. |

## Auto-correction loop (Studio runner only)

`runUiTestSession()` in `src/backend/application/runners/ui-test-runner.ts`:

1. Spawn `run-ui-test` CLI for the whole manifest.
2. For each failing test:
   - Spawn `claude -p fix-bug` with the runtime capture (HTTP, console, screenshot path).
   - Re-spawn the CLI with `--test-id <single>` to verify the fix.
   - Loop until pass, OR same fix proposed 5× (convergence-fail), OR 50 iterations (max-iter).
3. On convergence-fail or max-iter: auto-create a `StudioBug` with `source='ui-test'` + the runtime context. The existing audit-bug pipeline picks up the bug when the user clicks "Lancer l'audit".

## Six scenarios

Each entity × eligible role produces tests in these scenarios. Templates are at
`cli/run-ui-test/templates/{scenario}.js.hbs`.

| Scenario | What it does | Common failures it catches |
|----------|--------------|----------------------------|
| `list` | Login, navigate to list, assert no 4xx/5xx + table renders | Missing RolePermission, wrong API path, ComponentKey mismatch |
| `detail` | Open list, click first row, assert detail loads | Wrong route param shape (`:id` vs `:slug`), broken detail loader |
| `form-submit` | Open create form, fill fixture, submit, expect 201 | DTO validator mismatch, wrong POST path, missing form-field testIds |
| `edit` | Open list, click edit row, modify field, submit, expect 200/204 | Same as create + missing PUT route |
| `delete` | Open list, click delete, confirm, expect 204 | Missing DELETE route, missing confirm testId |
| `permission-negative` | Login as denied role, navigate, expect 403 OR PermissionGuard fallback | Permission constants applied to wrong role; PermissionGuard not wired |

## data-testid contract

Templates assume the component scaffolder emits these testIds. If a test fails
with "selector not found", the scaffolder is missing a testId — fix the
scaffolder, not the test.

| Testid | Where | Required by |
|--------|-------|-------------|
| `login-email` / `login-password` / `login-submit` | login page | every scenario |
| `{section}-list-table` | list page | list scenario |
| `{section}-list-row` (per row) | list page | detail/edit/delete (clicks first row) |
| `row-edit` (per row, inside) | list row | edit scenario |
| `row-delete` (per row, inside) | list row | delete scenario |
| `confirm-delete` | confirm modal | delete scenario |
| `{section}-detail` | detail page | detail scenario |
| `form-field-{key}` | create/edit form — NATIVE `<input>` controls only (primitives like EnumSelect/DateInput own their internals) | form-submit/edit (per fixture key) |
| `form-submit` | create/edit form | form-submit/edit |
| `section-edit-{key}` / `section-done-{key}` | per-section "Modifier"/"Terminer" toggle (SectionCard) on a read-first EDIT fiche | edit scenario (opens every section BEFORE filling — the controls only exist while their section is editing; a page without toggles is direct-edit, the loop is a no-op) |
| `{section}-permission-denied` | guarded routes for denied roles | permission-negative |

## Output → Studio UI

The Studio's "UI Tests" pages (`/projects/:projectId/ui-tests` + run detail)
display every run, every result, every iteration, with screenshots and
iteration log. Live updates via `ui_test_*` broadcast events.

Auto-bugs created from convergence-fail / max-iter appear in the existing
bugs UI with `source='ui-test'` badge.
