The Test Utilities module provides a comprehensive set of tools for testing AdonisJS applications. It includes utilities for creating HTTP contexts, starting test servers, and managing cookies during tests.
Import
import { TestUtils } from '@adonisjs/core/test_utils'
TestUtils Class
The main class for managing test utilities in AdonisJS applications.
Constructor
Create a new TestUtils instance.
app
ApplicationService
required
The application service instance
import { TestUtils } from '@adonisjs/core/test_utils'
const testUtils = new TestUtils(app)
await testUtils.boot()
Properties
app
Reference to the application service instance.
The application service passed to the constructor
const app = testUtils.app
cookies
Cookie client instance for handling cookies in tests.
Instance for managing cookies during testing
const encrypted = testUtils.cookies.encrypt('session_data')
const decrypted = testUtils.cookies.decrypt(encrypted)
isBooted
Check if test utils have been booted.
Returns true if boot() has been called
if (!testUtils.isBooted) {
await testUtils.boot()
}
Methods
boot
Boot the test utilities. This must be called before using other methods.
Returns: Promise<void>
const testUtils = new TestUtils(app)
await testUtils.boot()
The application must be booted and the container must have all bindings before calling this method.
createHttpContext
Create an HTTP context for testing.
Optional configuration for creating HTTP contextCustom Node.js IncomingMessage instance
Custom Node.js ServerResponse instance
Returns: Promise<HttpContext> - HTTP context instance for testing
// Create a default context
const ctx = await testUtils.createHttpContext()
// Create context with custom request/response
import { IncomingMessage, ServerResponse } from 'node:http'
import { Socket } from 'node:net'
const req = new IncomingMessage(new Socket())
const res = new ServerResponse(req)
const ctx = await testUtils.createHttpContext({ req, res })
// Use the context in tests
ctx.request.method = 'POST'
ctx.request.url = '/users'
httpServer
Get an instance of HTTP server testing utilities.
Returns: HttpServerUtils - Instance for managing test HTTP server
const httpUtils = testUtils.httpServer()
const closeServer = await httpUtils.start()
// Make HTTP requests to test endpoints
// ...
await closeServer()
Usage Example
import { test } from '@japa/runner'
import { TestUtils } from '@adonisjs/core/test_utils'
test.group('Users', (group) => {
let testUtils: TestUtils
group.setup(async () => {
testUtils = new TestUtils(app)
await testUtils.boot()
})
test('can create http context', async ({ assert }) => {
const ctx = await testUtils.createHttpContext()
assert.exists(ctx.request)
assert.exists(ctx.response)
})
})
HttpServerUtils Class
Utilities for starting and stopping the AdonisJS HTTP server during testing.
Constructor
Creates a new HttpServerUtils instance.
const httpUtils = testUtils.httpServer()
You typically don’t create this directly. Use testUtils.httpServer() instead.
Methods
start
Start the HTTP server for integration testing.
Optional callback to create a custom HTTP server instancehandler
(req: IncomingMessage, res: ServerResponse) => any
The request handler function
Returns: NodeHttpsServer | NodeHttpServer - Custom server instance
Returns: Promise<() => Promise<void>> - Function to close the server
import { test } from '@japa/runner'
import supertest from 'supertest'
test.group('API Tests', (group) => {
let closeServer: () => Promise<void>
group.setup(async () => {
const httpUtils = testUtils.httpServer()
closeServer = await httpUtils.start()
})
group.teardown(async () => {
await closeServer()
})
test('GET /users returns 200', async () => {
const response = await supertest(process.env.HOST)
.get('/users')
.expect(200)
})
})
Using with HTTPS
import https from 'node:https'
import fs from 'node:fs'
const options = {
key: fs.readFileSync('test-key.pem'),
cert: fs.readFileSync('test-cert.pem')
}
const closeServer = await httpUtils.start((handler) => {
return https.createServer(options, handler)
})
Environment Variables
The HTTP server uses the following environment variables:
The host address to bind the server to
The port number to listen on
# .env.test
HOST=127.0.0.1
PORT=4000
CookieClient
The CookieClient class is available through testUtils.cookies and provides methods for encrypting and decrypting cookies.
encrypt
Encrypt a cookie value.
The cookie value to encrypt
Returns: string - Encrypted cookie value
const encrypted = testUtils.cookies.encrypt('user_session_data')
decrypt
Decrypt a cookie value.
The encrypted cookie value to decrypt
Returns: string - Decrypted cookie value
const decrypted = testUtils.cookies.decrypt(encryptedValue)
sign
Sign a cookie value.
Returns: string - Signed cookie value
const signed = testUtils.cookies.sign('remember_token')
unsign
Unsign and verify a signed cookie.
The signed cookie value to verify and unsign
Returns: string | null - Unsigned value if valid, null if invalid
const unsigned = testUtils.cookies.unsign(signedValue)
if (unsigned) {
console.log('Valid cookie:', unsigned)
}
Testing Examples
Basic HTTP Context Testing
import { test } from '@japa/runner'
test('middleware sets user on context', async ({ assert }) => {
const ctx = await testUtils.createHttpContext()
// Simulate request
ctx.request.method = 'GET'
ctx.request.url = '/profile'
// Run middleware
await authMiddleware.handle(ctx, async () => {})
assert.exists(ctx.auth.user)
})
Integration Testing with HTTP Server
import { test } from '@japa/runner'
import supertest from 'supertest'
test.group('User API', (group) => {
let closeServer: () => Promise<void>
let baseUrl: string
group.setup(async () => {
const testUtils = new TestUtils(app)
await testUtils.boot()
const httpUtils = testUtils.httpServer()
closeServer = await httpUtils.start()
baseUrl = `http://${process.env.HOST}:${process.env.PORT}`
})
group.teardown(async () => {
await closeServer()
})
test('can register new user', async ({ assert }) => {
const response = await supertest(baseUrl)
.post('/register')
.send({ email: 'test@example.com', password: 'secret' })
.expect(201)
assert.exists(response.body.id)
})
test('can login user', async ({ assert }) => {
const response = await supertest(baseUrl)
.post('/login')
.send({ email: 'test@example.com', password: 'secret' })
.expect(200)
assert.exists(response.body.token)
})
})
Testing with Cookies
import { test } from '@japa/runner'
test('can encrypt and decrypt session cookie', async ({ assert }) => {
const testUtils = new TestUtils(app)
await testUtils.boot()
const sessionData = JSON.stringify({ userId: 1, role: 'admin' })
const encrypted = testUtils.cookies.encrypt(sessionData)
const decrypted = testUtils.cookies.decrypt(encrypted)
assert.equal(decrypted, sessionData)
})
test('can sign and verify remember token', async ({ assert }) => {
const testUtils = new TestUtils(app)
await testUtils.boot()
const token = 'abc123'
const signed = testUtils.cookies.sign(token)
const unsigned = testUtils.cookies.unsign(signed)
assert.equal(unsigned, token)
})
Testing Route Handlers
import { test } from '@japa/runner'
test('users controller returns user list', async ({ assert }) => {
const ctx = await testUtils.createHttpContext()
const controller = await app.container.make(UsersController)
await controller.index(ctx)
assert.equal(ctx.response.getStatus(), 200)
assert.isArray(ctx.response.getBody())
})
Best Practices
-
Always boot test utils before using them:
const testUtils = new TestUtils(app)
await testUtils.boot()
-
Clean up servers after tests:
group.teardown(async () => {
await closeServer()
})
-
Use environment variables for test configuration:
// .env.test
HOST=127.0.0.1
PORT=4000
NODE_ENV=test
-
Isolate test data by using transactions or cleaning up after each test:
group.each.setup(async () => {
await Database.beginGlobalTransaction()
})
group.each.teardown(async () => {
await Database.rollbackGlobalTransaction()
})
-
Reuse test utils across test groups when possible:
// tests/bootstrap.ts
export const testUtils = new TestUtils(app)
// tests/users.spec.ts
import { testUtils } from './bootstrap.ts'