Test Application API

primate/test builds an application in testing mode and exposes its request pipeline without binding a network listener.

import test from "primate/test";
import type { TestApp } from "primate/test";

This entrypoint is part of the primate package. It is distinct from the repository's separate @primate/test package, which provides framework test runner and fixture utilities rather than this application-facing harness. See the Testing guide for complete examples, coverage boundaries, and dependency-isolation advice.

test()

function test(dirname: string): Promise<TestApp>;

Finds the application project root from dirname, creates a unique temporary build directory beneath that root, builds in "testing" mode, initializes the serving application without starting its network listener, and resolves to a TestApp.

Build and initialization failures reject the promise. If setup fails after the temporary output is created, Primate removes that output before rethrowing the original error.

await using app = await test(import.meta.dirname);
const response = await app.request("https://example.test/api/items");

TestApp

Named type export returned by test().

type TestApp = {
  request(
    url: string | URL,
    init?: RequestInit,
  ): Promise<Response>;
  close(): Promise<void>;
  [Symbol.asyncDispose](): Promise<void>;
};

Each instance has its own built application state and output directory. Application initialization and serve hooks run normally and may have external side effects.

app.request()

request(
  url: string | URL,
  init?: RequestInit,
): Promise<Response>;

Constructs a WHATWG Request with the supplied arguments and sends it through the initialized application's in-process Request-to-Response pipeline. The returned native Response exposes the same status, headers, and body produced by that application path.

The harness exercises application routing, hooks, static assets, request bags and schemas, response conversion, sessions, aborts, and error mapping. It does not exercise HTTP transport, TLS, connection behavior, network backpressure, browser behavior, or WebSocket upgrades. Configured migrations are validated but not automatically applied.

Throws/rejects: Native Request construction errors propagate. Calling after closure throws Error("Test application is closed"). Application failures that Primate maps to error responses resolve as those responses rather than rejecting solely because of their status.

app.close()

close(): Promise<void>;

Stops the serving application and removes the instance's temporary build directory. Closure is idempotent: later calls resolve without repeating work. Await it before a test process exits when not using explicit resource management.

app[Symbol.asyncDispose]()

[Symbol.asyncDispose](): Promise<void>;

Aliases app.close(), allowing await using to dispose the app at the end of its scope, including when the scope exits by throwing.

Lifecycle and isolation

Create separate TestApp instances when tests need isolated bundled module state. Concurrent requests on one instance retain separate request context, but external services and process-global state used by application hooks are not automatically isolated. Closing one instance does not close another.