Test macros
Test macros are functions that are bound to the lifecycle of a given test and therefore they can create and destroy resources around a test without using the lifecycle hooks.
Let's take a example of creating a file and automatically deleting it after the test finishes. You can write a macro for it as follows.
- The test.macrofunction accepts a callback function.
- This function receives the currently executed test as the first argument. Therefore, you can assign it a cleanup function as shown in the following example.
- The callback function can receive additional arguments and they must be supplied when calling the macro.
- Finally, you can return any value from the callback function.
import { test } from '@japa/runner'
import { writeFile, rm } from 'node:fs/promises'
export const useFile = test.macro((t, filePath: string, contents: string) => {
  /**
   * Assign a hook on the test to remove the file when the
   * test finishes
   */
  t.cleanup(() => rm(filePath))
  /**
   * Create file
   */
  return writeFile(filePath, contents)
})
Once you have defined a macro, you can import it and use it inside a test. Again, after the test finishes, the file will be removed automatically via the t.cleanup hook.
import { test } from '@japa/runner'
import { useFile } from './macros.js'
test('read main property from package.json file', async () => {
  await useFile('package.json', JSON.stringify({ main: 'index.js' }))
})
Let's take another example. This time we will create an instance of the HTTP server and close it automatically after the test finishes.
import { test } from '@japa/runner'
import { promisify } from 'node:utils'
import { createServer } from 'node:http'
export const useServer = test.macro((t, callback) => {
  /**
   * Create an HTTP server instance
   */
  const server = createServer(callback)
  /**
   * Assign the hook to close the server when test finishes
   */
  t.cleanup(() => promisify(server.close)())
  /**
   * Listen on some random port
   */
  server.listen(':0')
  /**
   * Return server instance
   */
  return server
})
Usage
import { test } from '@japa/runner'
import { useServer } from './macros.js'
test('serve static files', async () => {
  const server = useServer((req, res) => {
  })
})