On this page

On this page

Testing

Introduction

Bunyad apps are tested with Bun’s test runner. @bunyad/testing adds a Laravel-shaped layer on top: a TestCase base class, an in-process HTTP client, response assertions, and helpers to reset the database between tests.

Put feature tests under tests/ (or tests/Feature). Prefer class-based tests that boot your real createApplication factory so routes, middleware, and providers match production. For a single pure function, Bun’s native test() is enough — you do not need to boot the app.

Related chapters: HTTP tests, database testing, console tests, and mocking.

Environment

Point the app at a dedicated test database and an in-memory session before you boot. A common pattern is a beforeBoot hook on @testCase:

@testCase({
  createApplication,
  migrationsPath: "./database/migrations",
  beforeBoot() {
    process.env.SESSION_DRIVER = "memory";
    process.env.DATABASE_PATH = "./storage/testing.sqlite";
  },
})
class ExampleTest extends TestCase {
  // ...
}

Use whatever env keys your config/database.ts and session config read. Prefer a file or memory database that tests may wipe freely.

Creating tests

Extend TestCase, decorate the class with @testCase({ createApplication }), and mark each method with @test():

tests/Feature/ExampleTest.ts
import { TestCase, test, testCase } from "@bunyad/testing";
import { createApplication } from "../../bootstrap/app.ts";

@testCase({ createApplication })
class ExampleTest extends TestCase {
  @test()
  async home_returns_ok(): Promise<void> {
    const response = await this.get("/");
    response.assertOk();
  }
}

@test("custom title") overrides the Bun test name. Each method gets a fresh class instance: the client boots, then setUp() runs, then your method, then tearDown().

You can also create a client by hand when you do not want a class:

import { test } from "bun:test";
import { TestClient } from "@bunyad/testing";
import { createApplication } from "../bootstrap/app.ts";

test("home returns ok", async () => {
  const client = await TestClient.create({ createApplication });
  const response = await client.get("/");
  response.assertOk();
});

There is no make:test stub command yet — add the file under tests/ yourself.

Running tests

From the app root:

bun test
bun test ./tests/Feature/ExampleTest.ts

Bun discovers *.test.ts files (and methods registered by @test()). Pass the same filters and reporters Bun already documents.

Database between tests

Pass migrationsPath on @testCase / TestClient.create so the client wipes and migrates after boot. Call this.refreshDatabase(path) again inside a test when you need a second reset. See Database testing.

Facades under test

Mail, queue, events, cache, storage, HTTP client, and notifications each expose a .fake() helper on their own package. The Mocking chapter lists them and links to the feature pages for full assert APIs.