Testing
Feature Testing
Feature tests validate end-to-end application behavior through real HTTP requests. They run with bun test (not Vitest) and live in tests/Feature/.
Basic structure
HTTP methods
All methods accept an optional headers object as the last argument.
Sending custom headers
Pass headers as the last argument — useful for sending auth tokens:
TestResponse — all assertions
Status
Redirects
JSON body
Headers
Chaining
All assert* methods return this, so you can chain:
Accessing the body
Database isolation with withTransaction
Wrap any test that writes to the database in withTransaction. The callback runs inside a Knex transaction that is always rolled back — keeping the database clean between tests.
All database queries made inside the callback (including those inside your controllers and models) automatically use the same transaction because the framework uses AsyncLocalStorage to propagate it.
Using factories to seed test data
Factory and Faker live in Testing/Factory.ts:
Factory methods
| Method | Description |
|---|---|
Factory.define(Model, () => attrs) | Create a factory |
factory.create(attrs?) | Insert one record, return model instance |
factory.createMany(n, attrs?) | Insert n records |
factory.make(attrs?) | Build instance without saving |
factory.makeMany(n, attrs?) | Build n instances without saving |
factory.state(name, attrs) | Define a named state |
factory.withState(...names) | Apply states before create/make |
Faker helpers
For richer data generation, install @faker-js/faker and use it in your factory definitions.
Testing authentication
Most authenticated routes require a valid auth_token cookie or Authorization header. The cleanest approach in tests is to log in first: