LangENKO

Testing

Mandu ships its own batteries-included test runner — unit, integration, E2E, coverage, watch — all driven by a single `mandu test` command.

since v0.24
On this page

Testing

Mandu ships its own batteries-included test runner. No Vitest. No Jest. No Playwright setup (until you want E2E). Just mandu test.

# Everything, sequential: unit → integration
mandu test

# The full pipeline including E2E
mandu test --e2e

# CI: fail fast + coverage
mandu test --coverage --bail

Under the hood mandu test wraps bun:test for unit and integration, @mandujs/ate for E2E spec generation, and playwright test for the browser leg — all with a single config block in mandu.config.ts.

Pages

  • Unitmandu test unit, filling tests, fixtures, Symbol.dispose for mocks.
  • IntegrationcreateTestServer, createTestSession, createTestDb, mockMail, mockStorage.
  • E2Emandu test --e2e, the ATE pipeline, heal-on-failure.
  • Coverage--coverage, LCOV merge, threshold enforcement.
  • Watch--watch, affected-file heuristic, sub-second re-runs.
  • SnapshottoMatchSnapshot, --update-snapshots, golden-file conventions.

Config at a glance

Every knob lives under test in mandu.config.ts. Defaults work for a fresh project — override only what you need:

// mandu.config.ts
import type { ManduConfig } from "@mandujs/core";

export default {
  test: {
    unit: {
      include: ["**/*.test.ts", "**/*.test.tsx"],
      exclude: ["node_modules/**", ".mandu/**"],
      timeout: 30_000,
    },
    integration: {
      include: ["tests/integration/**/*.test.ts"],
      dbUrl: "sqlite::memory:",
      sessionStore: "memory",
      timeout: 60_000,
    },
    coverage: { lines: 80, branches: 70 },
  },
} satisfies ManduConfig;

Unknown keys are rejected at load time — the schema is .strict() and will tell you which keys are valid when you typo (e.g. uint vs unit).

Exit codes

Code Meaning
0 All tests passed, or --dry-run plan
1 At least one test failed
2 Infra failure (spawn error, watcher I/O, timeout)
4 Config error (schema, missing peer dep, etc.)

🤖 Agent Prompt

🤖 Agent Prompt — Testing
Apply the guidance from the Mandu docs page at https://mandujs.com/docs/testing/index to my project.

Summary of the page:
Testing category hub. `mandu test` wraps bun:test for unit + integration + E2E (ATE/Playwright) with coverage merge, watch mode, and snapshot testing. Zero external deps required for unit/integration.

Required invariants — must hold after your changes:
- `mandu test` requires Bun >= 1.3.12 — the runner wraps `bun test` directly
- Test configuration lives under the `test` block of `mandu.config.ts` and is `.strict()` — unknown keys throw at load
- Exit code 0 = success, 1 = test failure, 2 = infra error, 4 = config error
- `--e2e` requires `@playwright/test` as a peer dependency (`bun add -d @playwright/test`)
- Merged LCOV always lands at `.mandu/coverage/lcov.info` (Phase 12.3)

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.

For Agents

Machine-readable contract for the testing surface.

{
  "schema": "mandu.testing/v0.24",
  "runner": "bun:test",
  "e2e_runner": "playwright",
  "config_root": "mandu.config.ts::test",
  "commands": {
    "all": "mandu test",
    "unit": "mandu test unit",
    "integration": "mandu test integration",
    "e2e": "mandu test --e2e",
    "coverage": "mandu test --coverage",
    "watch": "mandu test --watch"
  },
  "exit_codes": {
    "0": "success",
    "1": "test failure",
    "2": "infra error",
    "4": "config/schema error"
  },
  "peer_dependencies": {
    "e2e": "@playwright/test >= 1.40.0"
  },
  "coverage_output": ".mandu/coverage/lcov.info",
  "rules": [
    "Do not bypass `mandu test` by calling `bun test` directly — config normalization is lost",
    "`mandu.config.ts::test` is `.strict()` — unknown keys throw on load",
    "E2E without `@playwright/test` exits with CLI_E063"
  ]
}

For Agents

AI hint

Testing category hub. `mandu test` wraps bun:test for unit + integration + E2E (ATE/Playwright) with coverage merge, watch mode, and snapshot testing. Zero external deps required for unit/integration.

Invariants
  • `mandu test` requires Bun >= 1.3.12 — the runner wraps `bun test` directly
  • Test configuration lives under the `test` block of `mandu.config.ts` and is `.strict()` — unknown keys throw at load
  • Exit code 0 = success, 1 = test failure, 2 = infra error, 4 = config error
  • `--e2e` requires `@playwright/test` as a peer dependency (`bun add -d @playwright/test`)
  • Merged LCOV always lands at `.mandu/coverage/lcov.info` (Phase 12.3)
Guard scope
testing