AdonisJS provides a comprehensive set of testing utilities to make integration and unit testing seamless. The TestUtils class offers helpers for HTTP testing, context creation, and cookie handling.
Overview
The testing utilities are automatically available through the IoC container and provide:
- HTTP context creation for unit tests
- HTTP server management for integration tests
- Cookie client for testing cookie-based functionality
- Macroable interface for custom extensions
Getting Started
Access test utilities from the application container:
import { test } from '@japa/runner'
test('example test', async ({ assert }) => {
const testUtils = await app.container.make('testUtils')
await testUtils.boot()
// Use test utilities
})
Creating HTTP Contexts
Create HTTP context instances for testing controllers, middleware, and other HTTP-related code:
const testUtils = await app.container.make('testUtils')
await testUtils.boot()
const ctx = await testUtils.createHttpContext()
// Access request and response
ctx.request.updateBody({ name: 'John' })
ctx.response.send({ success: true })
Custom Request and Response
Provide custom IncomingMessage and ServerResponse objects:
import { IncomingMessage, ServerResponse } from 'node:http'
import { Socket } from 'node:net'
const req = new IncomingMessage(new Socket())
const res = new ServerResponse(req)
// Customize request
req.url = '/users/1'
req.method = 'GET'
const ctx = await testUtils.createHttpContext({ req, res })
HTTP Server Testing
Start the AdonisJS HTTP server for integration testing:
const testUtils = await app.container.make('testUtils')
const httpUtils = testUtils.httpServer()
const closeServer = await httpUtils.start()
// Make HTTP requests to your server
// Using your preferred HTTP client
await closeServer() // Clean up
With Custom Server
Provide a custom HTTP/HTTPS server callback:
import { createServer } from 'node:https'
import { readFileSync } from 'node:fs'
const closeServer = await httpUtils.start((handler) => {
return createServer({
key: readFileSync('key.pem'),
cert: readFileSync('cert.pem')
}, handler)
})
Environment Variables
The server respects HOST and PORT environment variables:
process.env.HOST = '127.0.0.1'
process.env.PORT = '4000'
const closeServer = await httpUtils.start()
// Server listening on http://127.0.0.1:4000
Cookie Testing
The cookies client helps test cookie-based functionality:
const testUtils = await app.container.make('testUtils')
await testUtils.boot()
// Access cookie client
const cookies = testUtils.cookies
// Sign cookies
const signed = cookies.sign('session_id', 'abc123')
// Encrypt cookies
const encrypted = cookies.encrypt('user_data', { id: 1 })
// Verify and decrypt in tests
const verified = cookies.verify('session_id', signed)
const decrypted = cookies.decrypt('user_data', encrypted)
API Reference
TestUtils
The application service instance
Flag indicating if test utilities have been booted
Cookie client instance for handling cookies in tests
Methods
Boots the test utilities. Must be called before using other methods. Requires the app to be booted with all container bindings.
Returns an instance of HTTP server testing utilities.const httpUtils = testUtils.httpServer()
createHttpContext
(options?) => Promise<HttpContext>
Creates an HTTP context instance for testing.Parameters:
options.req - Custom IncomingMessage object (optional)
options.res - Custom ServerResponse object (optional)
const ctx = await testUtils.createHttpContext()
HttpServerUtils
start
(serverCallback?) => Promise<() => Promise<void>>
Starts the HTTP server and returns a cleanup function.Parameters:
serverCallback - Optional callback to create a custom HTTP/HTTPS server
Returns: Promise that resolves to a cleanup function to close the serverconst closeServer = await httpUtils.start()
// ... make requests
await closeServer()
Extending Test Utils
TestUtils extends Macroable, allowing you to add custom methods:
import { TestUtils } from '@adonisjs/core/test_utils'
TestUtils.macro('createAuthenticatedContext', async function (user) {
const ctx = await this.createHttpContext()
ctx.auth.user = user
return ctx
})
// Use in tests
const ctx = await testUtils.createAuthenticatedContext({ id: 1 })
Best Practices
Always call boot() on test utils before using other methods. The boot method initializes the cookie client and other dependencies.
Store the cleanup function from httpServer().start() and call it in test teardown hooks to properly close the server.
import { test } from '@japa/runner'
test.group('API tests', (group) => {
let closeServer: () => Promise<void>
group.setup(async () => {
const testUtils = await app.container.make('testUtils')
const httpUtils = testUtils.httpServer()
closeServer = await httpUtils.start()
})
group.teardown(async () => {
await closeServer()
})
test('GET /users', async ({ client }) => {
// Your test here
})
})