LangENKO

Testing

Unit, integration, and E2E — all through Bun's test runner with Mandu's ATE auto-generating contract tests for you.

since v0.22
On this page

Testing

TL;DRbun test for unit/integration, bun run test:e2e for browser, bun run mandu ate generate to auto-write contract tests.

Why

Tests are the second-most-skipped thing in agent-generated code (after error handling). Mandu makes the test boilerplate disappear — ATE reads your contracts and emits the tests. Your job becomes "review the generated test, add the cases ATE missed".

Unit tests

// src/server/domain/users.test.ts
import { describe, expect, test } from "bun:test";
import { createUser } from "./users";

describe("createUser", () => {
  test("normalises email to lowercase", () => {
    const u = createUser({ email: "ME@example.com" });
    expect(u.email).toBe("me@example.com");
  });
});
bun test
bun test --watch                 # re-run on save
bun test src/server/domain        # just one folder

Auto-generated contract tests

bun run mandu ate generate
# writes tests/_generated/<contract>.test.ts for every Mandu.contract({...})

ATE inspects the request/response zod schemas, generates positive cases (every required field, every optional combination) and negative cases (missing fields, wrong types, boundary values). Edit the generator config in mandu.config.ts ate section — never the generated files directly.

E2E

// tests/e2e/login.spec.ts
import { test, expect } from "@playwright/test";

test("user can log in", async ({ page }) => {
  await page.goto("http://localhost:3333/login");
  await page.fill('input[name="email"]', "demo@example.com");
  await page.fill('input[name="password"]', "demo1234");
  await page.click('button[type="submit"]');
  await expect(page).toHaveURL(/\/dashboard/);
});
bun run test:e2e            # assumes dev server on :3333
bun run test:e2e:server     # boots dev + runs E2E + tears down

🤖 Agent Prompt

🤖 Agent Prompt — Add tests
Add tests to my Mandu project:

1. Pure functions → `<file>.test.ts` next to the source.
   `import { describe, expect, test } from 'bun:test'`.

2. API contracts → `bun run mandu ate generate`, then review
   `tests/_generated/`. Add missing edge cases in a sibling
   `<contract>.cases.test.ts` (don't edit the generated file).

3. E2E flows → `tests/e2e/<flow>.spec.ts` using `@playwright/test`.
   Assume dev server is on http://localhost:3333.

Required invariants:
- Use `bun:test`, NEVER `vitest` or `jest`.
- Unit tests sit next to source; integration in `tests/`; E2E in `tests/e2e/`.
- `tests/_generated/` is read-only — ATE regenerates.
- DB-backed tests use `tests/setup-db.ts`; no shared state.

After writing, run `bun test` (and `bun run test:e2e:server` if E2E
was added) and report any failures.

Pitfalls

  • Don't import from vitest. Mandu's runner is bun:test. Vitest matchers occasionally compile but blow up on coverage.
  • tests/_generated/ is hands-off. ATE rewrites it. Put your additional cases in a sibling <name>.cases.test.ts.
  • Shared DB state breaks integration tests. Always provision a fresh in-memory SQLite via setup-db.ts.
  • E2E without dev server. A bare bun run test:e2e errors with ECONNREFUSED 3333. Use :server variant or run bun run dev in another terminal.

For Agents

AI hint

Use `bun test` for unit + integration. Mandu's ATE (Automated Test Engineer) auto-generates contract tests via `bun run mandu ate generate`. E2E runs through Playwright via `bun run test:e2e`. Tests live next to the file (`*.test.ts`) for unit, in `tests/` for integration, and in `tests/e2e/` for browser tests.

Invariants
  • Unit tests live alongside the source as `*.test.ts`; integration tests live in `tests/`; E2E in `tests/e2e/`
  • Test runner is Bun (`bun test`); never `vitest` or `jest`
  • Generated contract tests live under `tests/_generated/` and must NOT be hand-edited (ATE regenerates them)
  • For DB-backed tests, use `tests/setup-db.ts` to provision an in-memory SQLite instance — never share DB state across tests
  • E2E tests require `bun run dev` running on port 3333 (or `bun run test:e2e:server` to manage automatically)
Guard scope
testing