Test Context

An instance of Test Context class is shared every Japa test. Therefore, you can access it as the first argument within the test callback.

import { test } from '@japa/runner'
test('add two numbers', (ctx) => {
console.log(ctx)
})
const { test } = require('@japa/runner')
test('add two numbers', (ctx) => {
console.log(ctx)
})

The goal of the test context is to share/pass data to the test. So, for example, the @japa/assert package adds the assert property to the context, and the @japa/expect package adds the expect property.

The context object is isolated between tests; hence you can safely assume that properties/mutations from one test context will not leak to other tests.

Extending context

The Test Context class is extensible by nature. You can use the Macros and Getters to add custom properties to it.

You can write the code for extending the context within the bin/test.js file or create a new file and import it inside the bin/test.js file.

Getters

A getter accepts the property name as the first argument and a callback function that returns the value for the property.

import { TestContext } from '@japa/runner'
TestContext.getter('foo', function () {
return 'bar'
})
const { TestContext } = require('@japa/runner')
TestContext.getter('foo', function () {
return 'bar'
})

Once defined, you can access the getter as follows.

test('add two numbers', (ctx) => {
console.log(ctx.foo) // logs 'bar'
})

By default, the callback is called every time the property is accessed. However, you can also create singleton getters by passing a third argument.

TestContext.getter('foo', function () {
return 'bar'
}, true) // 👈 singleton

The this property inside the callback is scoped to the instance of the test context.

TestContext.getter('foo', function () {
console.log(this instanceof TestContext) // true
})

Macros

A macro also accepts the property name as the first argument, followed by the value. The value can be a literal or a function. For example:

TestContext.macro('getTime', function () {
return new Date().getTime()
})
TestContext.macro('nodeVersion', process.version)
// Access as a function
ctx.getTime()
// Access as a property
ctx.nodeVersion

Usage with TypeScript

Since getters and macros are added at runtime, you must inform the TypeScript compiler about these new properties separately.

You can make use of module augmentation to define these properties.

Create a new file, bin/japa_types.ts, and paste the following code inside it.

declare module '@japa/runner' {
// Interface must match the class name
interface TestContext {
getTime(): number
nodeVersion: string
foo: { foo: boolean }
}
}