On this page

On this page

Database Testing

Introduction

Feature tests that touch the database need a clean schema and predictable rows. @bunyad/testing gives you refreshDatabase (wipe + migrate, optional seed). Model factories from @bunyad/orm build attributes for inserts. There are no assertDatabaseHas-style helpers yet — query with the ORM or the query builder and assert with Bun’s expect.

Refreshing the database

Pass migrationsPath when you create the client so tables reset after boot:

@testCase({
  createApplication,
  migrationsPath: "./database/migrations",
  seed: async () => {
    await new DatabaseSeeder().run();
  },
  beforeBoot() {
    process.env.DATABASE_PATH = "./storage/testing.sqlite";
  },
})
class OrderTest extends TestCase {
  // ...
}

Or call it from a test / setUp:

await this.refreshDatabase("./database/migrations", {
  seed: async () => {
    await new DatabaseSeeder().run();
  },
});

Standalone helper (when you are not using TestCase):

import { refreshDatabase } from "@bunyad/testing";
import { Model } from "@bunyad/orm";

await refreshDatabase({
  connection: Model.getConnection(),
  migrationsPath: "./database/migrations",
  fresh: true, // wipe then migrate (default)
  seed: async () => {
    // ...
  },
});

Set fresh: false to run pending migrations only, without wiping.

Model factories

Define a factory, attach it with @HasFactory, then create / make in the test:

import User from "@/Models/User.ts";

const user = await User.factory().create({
  email: "ada@example.com",
});

const unsaved = User.factory().make({ name: "Ada" });

Full factory API: ORM factories.

Seeders

Pass a seed callback to refreshDatabase / @testCase, or call a seeder after refresh:

import DatabaseSeeder from "../../database/seeders/DatabaseSeeder.ts";

await this.refreshDatabase("./database/migrations", {
  seed: () => new DatabaseSeeder().run(),
});

See Seeding.

Asserting rows

Query the model (or connection) and use Bun’s matchers:

import { expect } from "bun:test";
import User from "@/Models/User.ts";

await this.postJson("/register", {
  name: "Ada",
  email: "ada@example.com",
  password: "secret",
});

const user = await User.where("email", "ada@example.com").first();
expect(user).not.toBeNull();
expect(user!.name).toBe("Ada");

expect(await User.count()).toBe(1);

Soft deletes: reload with withTrashed() or check trashed() on the instance after delete().