@dunx/testing
v3.1.3
Published
Test harness for dunx apps: a container with providers replaced in place, and a real Bun.serve on port 0
Maintainers
Readme
@dunx/testing
The container an app already has, with named bindings replaced in place, plus
a real Bun.serve on port 0. Bun binds a socket in about a millisecond, so the
thing under test is the thing that ships: there is no mocking framework, no fake
request object and no in-memory transport.
Install
bun add -d @dunx/testingUsage
import { provide } from '@dunx/core';
import { createTestApp, createTestServer } from '@dunx/testing';
// The container only.
const app = await createTestApp({
modules: [UsersModule],
overrides: [provide(Clock, { useValue: new FixedClock('2026-01-01') })],
});
expect(app.get(UsersService).today()).toBe('2026-01-01');
await app.shutdown();
// The container behind a real server.
const server = await createTestServer({
modules: [ApiModule],
overrides: [provide(Storage, { useClass: MemoryStorage })],
prefix: 'api',
});
const { status, body } = await server.json<User[]>('api/users');
await server.close();What is here
The Testing guide is canonical.
| Export | What it does |
| ------------------ | ---------------------------------------------------------------- |
| createTestApp | The container, with overrides applied before anything resolves |
| createTestServer | The same, behind a real Bun.serve on port 0 |
| testClient | The fetch-and-parse plumbing against a base url |
Notes
- An override replaces the binding in every scope that holds it, so a test
stubbing
Loggerneed not know how many modules bind it. Naming a token nobody binds is an error rather than a silent no-op. - The replacement happens before anything resolves, so the discarded provider is
never constructed: its
useFactorynever runs and itsonInitnever fires, which makes overriding a database safe. - Request logging and boot logging are off unless asked for.
- An
HttpOptionsfield not passed is absent; nothing is inherited from production.middlewareandonErrorchange what the application does, so pass the same objectmain.tspasses.
License
MIT
