E2E Tests
`mandu test --e2e` wraps the ATE (Automation Test Engine) pipeline to extract the interaction graph, generate Playwright specs, and run them — with optional heal-on-failure suggestions.
On this page
E2E Tests
mandu test --e2e wraps the ATE (Automation Test Engine) to
produce a complete Playwright run. The pipeline extracts the
interaction graph from app/, generates specs under
tests/e2e/auto/, and invokes playwright test with your config.
It works alongside the existing unit/integration runner — pass --e2e
on its own to run only the E2E leg, or combine with mandu test to
fan out.
Quick start
# Full pipeline: unit → integration → E2E
mandu test --e2e
# Only E2E, with heal-on-failure suggestions
mandu test --e2e --heal
# Preview (no spawn, exit 0)
mandu test --e2e --dry-run
# CI: fail fast + forward CI=true + headless
mandu test --e2e --bail --ci
Prerequisites
bun add -d @playwright/test
mandu test --e2e exits with CLI_E063 and a clear install hint if
@playwright/test is missing. The minimum version is 1.40.0.
Your Playwright config lives at tests/e2e/playwright.config.ts by
default — mandu init templates ship with one.
// tests/e2e/playwright.config.ts
import { defineConfig } from "@playwright/test";
export default defineConfig({
testDir: "./auto", // where `ateGenerate` emits
fullyParallel: true,
use: {
baseURL: process.env.BASE_URL ?? "http://127.0.0.1:3333",
trace: "on-first-retry",
},
reporter: [["json", { outputFile: ".mandu/reports/latest/playwright-report.json" }]],
});
Pipeline stages
┌──────────┐ ┌────────────┐ ┌───────┐ ┌──────────┐
│ Extract │ → │ Generate │ → │ Spawn │ → │ (Heal?) │
└──────────┘ └────────────┘ └───────┘ └──────────┘
- Extract —
ateExtract()scansapp/for routes, islands, and interactions, writing.mandu/interaction-graph.json. - Generate —
ateGenerate()emits one spec per route undertests/e2e/auto/<routeId>.spec.ts. Scenarios are derived from the graph plus any.mandu/scenarios.jsonoverrides. - Spawn —
runE2E()invokesbunx playwright test --config tests/e2e/playwright.config.ts, forwardingCI=true,BASE_URL, and optional--grepfilters. - (Optional) Heal — when
--healis set AND Playwright exited non-zero,ateHeal()inspects the latest report and emits selector-map / test-code diffs. No auto-commit.
Flags
| Flag | Effect |
|---|---|
--e2e |
Enable the pipeline. Combines with unit/integration targets. |
--heal |
Emit healing suggestions after a failing run. |
--dry-run |
Print the plan, skip the subprocess. Exit 0. |
--coverage |
Set PW_COVERAGE=1 + emit LCOV to .mandu/coverage/e2e.lcov. |
--base-url <url> |
Override BASE_URL passed to Playwright. |
--ci |
Forward CI=true. |
--only-route <id> |
Filter via Playwright --grep. Repeatable. |
Dry-run output
$ mandu test --e2e --dry-run
mandu test --e2e --dry-run
ATE E2E generation plan (oracle L1)
out: tests/e2e/auto
routes: 2
- /home [GET] → tests/e2e/auto/_home.spec.ts
- /api/users [GET] → tests/e2e/auto/_api_users.spec.ts
ATE E2E execution plan
cwd: /repo
command: bunx playwright test --config tests/e2e/playwright.config.ts
timeout: 600000ms
lcov output: (coverage off)
Exit codes
| Code | Meaning |
|---|---|
0 |
All specs passed (or dry-run) |
1 |
At least one spec failed |
2 |
Infra failure (spawn error, timeout) |
4 |
Config error (playwright missing, config missing) |
The heal loop
--heal is a suggestion emitter, not an auto-fixer. After a failed
run, ATE reads the Playwright JSON report, matches failing locators
against the interaction graph, and emits a diff you can review and
apply manually:
$ mandu test --e2e --heal
...
FAIL _dashboard.spec.ts › logged-in user → /dashboard
locator `text=Welcome back` — not found after 30000ms
heal suggestion (non-destructive):
selectors:
- /dashboard:heading
diff:
- text=Welcome back
+ h1:has-text("Welcome")
The diff is printed to stdout and written to
.mandu/heal/<routeId>.patch. Apply with git apply or by hand — the
tool never runs git commit.
Troubleshooting
CLI_E063: @playwright/test peer dependency is not installed. —
run bun add -d @playwright/test.
Empty route list in the plan — run mandu test:auto once to
regenerate the interaction graph. The plan reads
.mandu/interaction-graph.json to enumerate routes.
Playwright runs but no specs match — check testDir in your
tests/e2e/playwright.config.ts points at tests/e2e/auto (or
includes it).
Heal loop prints "No failed locators detected" — Playwright's JSON
report must be present at
.mandu/reports/latest/playwright-report.json. Ensure your config
enables the json reporter.
🤖 Agent Prompt
Apply the guidance from the Mandu docs page at https://mandujs.com/docs/testing/e2e to my project.
Summary of the page:
`mandu test --e2e` runs extract → generate → spawn. Specs land under `tests/e2e/auto/`. Requires `@playwright/test >= 1.40.0` as a peer dep. Use `--heal` to emit non-destructive diff suggestions after a failure.
Required invariants — must hold after your changes:
- `@playwright/test >= 1.40.0` is a peer dependency — missing it returns CLI_E063
- Playwright config must live at `tests/e2e/playwright.config.ts` (override via `test.e2e.configPath`)
- Generated specs land under `tests/e2e/auto/<routeId>.spec.ts` (regenerated each run)
- Interaction graph is cached at `.mandu/interaction-graph.json`
- `--heal` NEVER auto-commits — it emits diffs for human review
Then:
1. Make the change in my codebase consistent with the page.
2. Run `bun run guard` and `bun run check` to verify nothing
in src/ or app/ breaks Mandu's invariants.
3. Show me the diff and any guard violations.
Related
- Build with Agents — ATE — the oracle levels + impact graph.
- Coverage — merge Playwright V8 coverage into the canonical LCOV.
- Watch — for an E2E watch loop, use
mandu test:watch(distinct frommandu test --watch).
For Agents
{
"schema": "mandu.testing.e2e/v0.24",
"command": "mandu test --e2e",
"pipeline": ["extract", "generate", "spawn", "heal?"],
"peer_dependency": "@playwright/test >= 1.40.0",
"interaction_graph": ".mandu/interaction-graph.json",
"output_dir": "tests/e2e/auto",
"config_path_default": "tests/e2e/playwright.config.ts",
"exit_codes": {
"0": "success (or dry-run)",
"1": "at least one spec failed",
"2": "infra failure",
"4": "config error (e.g. CLI_E063 for missing peer dep)"
},
"rules": [
"`--heal` never auto-commits — output is a diff for human review",
"Specs are regenerated each run — do not hand-edit `tests/e2e/auto/`",
"Override scenarios via `.mandu/scenarios.json` — not by editing generated files"
]
}For Agents
`mandu test --e2e` runs extract → generate → spawn. Specs land under `tests/e2e/auto/`. Requires `@playwright/test >= 1.40.0` as a peer dep. Use `--heal` to emit non-destructive diff suggestions after a failure.
- `@playwright/test >= 1.40.0` is a peer dependency — missing it returns CLI_E063
- Playwright config must live at `tests/e2e/playwright.config.ts` (override via `test.e2e.configPath`)
- Generated specs land under `tests/e2e/auto/<routeId>.spec.ts` (regenerated each run)
- Interaction graph is cached at `.mandu/interaction-graph.json`
- `--heal` NEVER auto-commits — it emits diffs for human review