Testing
Unit-test services directly and exercise HTTP routes in process with Bun.
Unit-test a controller
import { describe, expect, test } from "bun:test";
import { GreetingController } from "./greeting.controller.ts";
import { GreetingService } from "./greeting.service.ts";
describe("GreetingController", () => {
test("returns a greeting from the service", () => {
const controller = new GreetingController(new GreetingService());
expect(controller.getGreeting()).toBe("Hello, AponiaJS!");
});
});Direct construction keeps unit tests independent of the container.
Test the complete route
import { expect, test } from "bun:test";
import { AponiaFactory } from "@aponiajs/platform-elysia";
import { AppModule } from "../src/app.module.ts";
test("GET /greetings", async () => {
const application = await AponiaFactory.create(AppModule, {
logger: false,
});
const response = await application.handle(
new Request("http://localhost/greetings"),
);
expect(response.status).toBe(200);
expect(await response.text()).toBe("Hello, AponiaJS!");
});Assert a validation failure
A schema rejects the request before the handler runs, so the test asserts the status rather than a message body:
import { expect, test } from "bun:test";
import { AponiaFactory } from "@aponiajs/platform-elysia";
import { AppModule } from "../src/app.module.ts";
test("POST /users rejects an invalid body", async () => {
const application = await AponiaFactory.create(AppModule, {
logger: false,
});
const rejected = await application.handle(
new Request("http://localhost/users", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ name: "A" }),
}),
);
expect(rejected.status).toBe(422);
});Test a typed native route
When the module graph declares routes statically, return the native application and pass it directly to Eden Treaty:
import { expect, test } from "bun:test";
import { treaty } from "@elysia/eden";
import { app } from "../src/server.ts";
test("reads a user through Treaty", async () => {
const api = treaty(app);
const result = await api.users({ id: 42 }).get();
expect(result.error).toBeNull();
expect(result.data).toEqual({ id: 42, name: "user-42" });
});This performs no network I/O and keeps the route contract inferred from the same Elysia application. See Eden Treaty for the static inference boundary.
Assert a graph failure
Graph and container failures happen while the application is being created.
Assert the code, never the message:
import { expect, test } from "bun:test";
import { Injectable, Module } from "@aponiajs/common";
import { AponiaFactory } from "@aponiajs/platform-elysia";
class MissingDependency {}
@Injectable()
class BrokenService {
constructor(readonly dependency: MissingDependency) {}
}
@Module({ providers: [BrokenService] })
class BrokenModule {}
test("reports a stable graph error code", async () => {
await expect(
AponiaFactory.create(BrokenModule, { logger: false }),
).rejects.toMatchObject({
code: "MISSING_PROVIDER",
});
});The complete list is in error codes.
Run tests with:
bun testhandle() never binds a port, so nothing needs to be closed.
application.close() only stops an existing Elysia server, so call it after
application.listen(port). There is no testing module or provider override API
yet.