LangENKO

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.

since v0.24
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?)  │
  └──────────┘    └────────────┘    └───────┘    └──────────┘
  1. ExtractateExtract() scans app/ for routes, islands, and interactions, writing .mandu/interaction-graph.json.
  2. GenerateateGenerate() emits one spec per route under tests/e2e/auto/<routeId>.spec.ts. Scenarios are derived from the graph plus any .mandu/scenarios.json overrides.
  3. SpawnrunE2E() invokes bunx playwright test --config tests/e2e/playwright.config.ts, forwarding CI=true, BASE_URL, and optional --grep filters.
  4. (Optional) Heal — when --heal is 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

🤖 Agent Prompt — E2E Tests
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.
  • 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 from mandu 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

AI hint

`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.

Invariants
  • `@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
Guard scope
testing