Testing

Beignet apps should test the boundary that owns the behavior.

BehaviorBest test boundary
Business rulesUse case test
Contract request and response shapeRoute/runtime test
Dependency wiringPort or provider test
Generated resource wiringGenerated resource test plus doctor
Client integrationClient test against a real or mocked HTTP handler

Generated resources include starter tests so new slices compile and have a place for behavior coverage. In framework-style apps, keep feature behavior tests under features/<feature>/tests/. Keep request/runtime integration tests beside the boundary they exercise, such as server/integration.test.ts.

Use case tests

Use case tests are the default for business behavior because they avoid HTTP setup and run against app-owned ports.

import { describe, expect, test } from "bun:test";
import { createUseCaseTester } from "@beignet/core/application";
import type { AppContext } from "@/app-context";
import { appPorts } from "@/infra/app-ports";
import { createProject } from "@/features/projects/use-cases";

describe("createProject", () => {
  test("creates a project", async () => {
    const tester = createUseCaseTester<AppContext>(() => ({
      requestId: "test-request",
      auth: null,
      ports: appPorts,
    }));

    const result = await tester.run(createProject, { name: "Roadmap" });

    expect(result.name).toBe("Roadmap");
  });
});

Keep vendor SDK mocks out of these tests. Mock or implement the app-owned port instead.

Route tests

Use route/runtime tests when the behavior belongs to HTTP: request parsing, contract validation, response validation, hooks, auth, rate limits, and error ownership.

const response = await server.api(
  new Request("http://localhost/api/projects", {
    method: "POST",
    body: JSON.stringify({ name: "Roadmap" }),
    headers: { "content-type": "application/json" },
  }),
);

expect(response.status).toBe(201);

If a route returns { status, body }, Beignet validates the response against the contract. Tests should cover both successful responses and declared business errors.

Generated resource checks

After generating or editing a resource, run:

bun run test
bun run typecheck
bunx -p @beignet/cli beignet lint
bunx -p @beignet/cli beignet doctor

test covers behavior. typecheck catches contract/type drift. lint checks dependency direction. doctor checks app wiring that TypeScript cannot fully prove, such as route files that no longer match registered contracts.

Provider tests

Provider tests should stay close to the adapter. Verify the provider implements the port contract and handles startup, teardown, retries, and error translation the way the app expects.

Application tests should not depend on live providers unless the test is explicitly an integration test.