Testing
Beignet apps should test the boundary that owns the behavior.
| Behavior | Best test boundary |
|---|---|
| Business rules | Use case test |
| Contract request and response shape | Route/runtime test |
| Dependency wiring | Port or provider test |
| Generated resource wiring | Generated resource test plus doctor |
| Client integration | Client 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.