Testing
Test functions and in-process routes, then verify production transport behavior against a running backend.
Choose the test boundary that proves the behavior: a function, an application, or a running HTTP server. Function tests exercise one descriptor without a server. Application tests load checked configuration and call an in-process HTTP client. Neither layer needs remote credentials when provider-backed capabilities receive explicit fakes. Use a running backend for final HTTP middleware, origin, cookie, and transport behavior.
Install the selected test tooling
The minimal starter already has development-only @relkit/testing. In another existing app, install
it explicitly before copying these tests:
From this guide’s application/package root, install only its selected requirements:
bun add --dev @relkit/testing@0.8.2
Keep these owner-specific versions and the lockfile together. Runtime SDKs belong in dependencies; build/type tooling belongs in devDependencies. Installing an adapter does not supply its optional SDK peers or enable the feature’s configuration.
The generic harness installs no optional database, authentication or model SDK. Keep feature adapters
and native SDKs in the application’s selected runtime dependencies. Use @relkit/testing/drizzle
for database tests, @relkit/testing/better-auth for database-backed auth, and native agent helpers
from @relkit/langchain or @relkit/langchain/testing after agent setup.
Test one function
Use invokeFunction for input and output validation, declared errors, nested invocation, and handler behavior:
/** Checks orders.function through the supported public RELKIT APIs. */
import { expect, test } from "bun:test";
import { invokeFunction } from "@relkit/testing";
import orders from "@app/services/orders/service.js";
test("createOrder invokes pricing", async () => {
const result = await invokeFunction(orders.createOrder, {
orderId: "order-1",
sku: "book",
quantity: 3,
});
expect(result).toEqual({ orderId: "order-1", sku: "book", totalCents: 300 });
});
bun test tests/unit/orders.function.test.ts
Pass test clients when the function declares cache, bucket, job, or event capabilities. Agent tests should declare or inject a deterministic native LangChain model and inspect recorded effects instead of sleeping or calling a live service.
Test the application boundary
Use createTestApplication for discovered routes, mapped input, function invocation, and provider
wiring. The Orders tutorial test also migrates isolated SQLite and checks
two users’ ownership boundary. The starter’s smallest HTTP test is:
import { afterAll, expect, test } from "bun:test";
import { createTestApplication } from "@relkit/testing";
import config from "../../relkit.config.js";
const testApp = await createTestApplication(config, { resourceProviders: "fake" });
test("POST /orders", async () => {
const response = await testApp.http.request("/orders", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ orderId: "order-1", sku: "book", quantity: 3 }),
});
expect(response.status).toBe(201);
expect(await response.json()).toEqual({
orderId: "order-1",
sku: "book",
totalCents: 300,
});
});
afterAll(() => testApp.close());
The harness runs in process and exposes application.http. It maps invalid function input to a
validation 422, but it does not implement the entire production HTTP pipeline. It does not prove
all middleware, rate limits, OpenAPI behavior, or RPC transport. Close it in afterAll so runtime
state and handles do not leak into another test, then send representative requests to the running
backend as the Start journey does.
Replace provider profiles explicitly
The commerce suite shows the complete shape for cache, bucket, realtime, and agent-state profiles alongside native model execution:
Every graph-required capability and profile must have a replacement. RELKIT_ENV=test does not silently select
fakes. Use createTestCacheFake and createTestBucketFake for deterministic resource behavior, and dedicated
test event, job, or agent utilities for those contracts.
Run the application gate
bun run test
bun run check
bun run typecheck
bun run build
Keep live integration and cloud tests separate and opt-in. In the RELKIT repository, bun run prepush
runs the focused merge-blocking checks without Docker; bun run prepush:full includes Docker acceptance.
Task-first jobs add focused unit, type, contract, restart, client, Inspector, Docker, and provider suites. The Docker/provider commands are explicit gates; managed cloud acceptance remains separately authorized.