Skip to main content
Version: 1.0.4

Hooks

Testosa provides a hooks interface to perform actions before and after all and/or each endpoint test. Hooks are currently only supported in JavaScript and are defined as a module or class that implements afterAll, afterEach, beforeAll and beforeEach methods that will be called when any of these events occurs.

Usage

To start using hooks:

  1. Create a JavaScript file with the hook functions you wish to use in your tests. Supported functions include afterAll, afterEach, beforeAll and beforeEach. See the hooks functions reference for details.

    // path/to/your/hooks-file.js
    
    const beforeAll = async () => { /* logic */ };
    const beforeEach = async (transaction) => { /* logic */ };
    const afterEach = async (transaction) => { /* logic */ };
    const afterAll = async () => { /* logic */ };
    
    module.exports = {
      afterAll,
      afterEach,
      beforeAll,
      beforeEach
    }
    
  2. Update your Testosa config to include the hooksFilePath option and set it to the relative path of your hooks file.

  3. Run Testosa

Methods reference

afterAll

Fn: afterAll() -> [void]

Runs once after all tests have executed regardless of their success/failure status. This function takes no parameters and can be asynchronous if your logic requires it.

Typical use cases:

  • Performing global teardown/clean up after your entire test run. For example:
    • deprovisioning your test database
    • deauthenticating mock users
    • deleting mock resources
    • etc.

afterEach

Fn: afterEach(transaction) -> [void]

Runs after each individual test has executed regardless of its success/failure state. The afterEach() function takes a single parameter, transaction containing details about the test.

Typical use cases:

  • Performing teardown/clean up after each test executes. For example:
    • deleting mock resources
    • deauthenticating mock users
    • debugging
    • etc.

Parameters:

NameTypeDescription
transaction[object]Individual test transaction object. See reference for details

beforeAll

Fn: beforeAll() -> [void]

Runs once before all tests have executed. This function takes no parameters and can be asynchronous if your logic requires it.

Typical use cases:

  • Performing global set up before your test run. For example:
    • provisioning your test database
    • creating and authenticating mock users
    • seeding data in your database
    • etc.

beforeEach

Fn: beforeEach(transaction) -> [object]

Runs before each individual test has executed. The beforeEach() function takes a single parameter, transaction containing details about the test.

Typical use cases:

  • Performing set up before each test executes. For example:
    • creating mock resources before modifying or delete them in update or delete endpoint tests
    • replacing placeholder parameters (query, header, path etc.) placeholders with real values
    • skipping a specific test
    • updating the generated test request to trigger a negative scenario
    • debugging
    • etc.

Parameters:

NameTypeDescription
transaction[object]Individual test transaction object. See reference for details

Returns:

Optionally modified transaction object from input parameter. Only properties within transaction.skip or properties within transaction.actual.request may be modified; all other values properties are read only. If a return value is omitted, the original transaction will be assumed.

Methods parameter (transaction)

The transaction parameter is available in the afterEach() and beforeEach() hook methods and provides access to inspecting the actual and expected HTTP request and response properties generated by Testosa. transaction also includes metadata for each test run as well as an optional flag that may be used to skip specific tests. The anatomy of the transaction object is as follows:

NameTypeReadonlyDescription
{}objectnoIndividual test transaction object.
{}.actualobjectnoObject identifying the actual properties of the executed request.
{}.actual.request.bodyobjectnoTest request body generated from OpenAPI path examples or schema.
{}.actual.request.headersobjectnoTest request headers generated from OpenAPI path examples or schema.
{}.actual.request.methodstringnoTest request method derived from OpenAPI schema.
{}.actual.request.pathstringnoTest request endpoint derived from OpenAPI path.
{}.actual.responseobjectyesResponse from executed test HTTP request.
{}.actual.response.bodyobjectyesResponse body from executed test HTTP request.
{}.actual.response.headersobjectyesResponse headers from executed test HTTP request.
{}.actual.response.statusCodeintegeryesResponse status code from executed test HTTP request.
{}.expectedobjectyesObject identifying the expected properties of the executed request.
{}.expected.methodstringyesExpected HTTP method.
{}.expected.requestBodyContentTypestringyesExpected HTTP request body content type.
{}.expected.responseBodyContentTypestringyesExpected HTTP response body content type.
{}.expected.statusCodeintegeryesExpected HTTP response status code.
{}.metaobjectyesObject containing meta data for the test execution.
{}.meta.durationintegeryesTest duration. Note: Property is only available in the afterEach test hook.
{}.meta.endedAtstring<datetime>yesTimestamp marking the completion of a test. Note: Property is only available in the afterEach test hook.
{}.meta.resultstringyesTest result. Note: Property is only available in the afterEach test hook.
{}.meta.startedAtstring<datetime>yesTimestamp marking the beginning of a test.
{}.operationIdstringyesPath operationId if specified in the OpenAPI specification for the endpoint.
{}.skipbooleannoFlag to trigger skipping a test. Default: false.

Examples

The following examples demonstrates the implementation of some of the test hook use cases in a typical test run:

Use caseHooks
Create test databasebeforeAll
Create and authenticate a mock userbeforeAll
Skip single test by operationIdbeforeEach
Skip single test by HTTP method and pathbeforeEach
Create mock resource before modifying itbeforeEach
Delete mock resource after testafterEach
Delete test user after all tests completeafterAll
Destroy test database after all tests completeafterAll
// path/to/your/hooks-file.js

const authenticateUser = require('../test-helpers/authenticate-user');
const createMockUser = require('../test-helpers/create-user');
const deleteMockUser = require('../test-helpers/delete-user');
const createMockVehicle = require('../test-helpers/create-vehicle');
const deleteMockVehicle = require('../test-helpers/delete-vehicle');
const createTestDb = require('../test-helpers/create-test-db');
const destroyTestDb = require('../test-helpers/destroy-test-db');

let accessToken;

const beforeAll = async () => {
  // Create mock database before starting all tests
  await createTestDb();

  // Create and authenticate a mock user to be used for all authenticated requests
  const userName = 'mock-user@my-domain.com';
  const password = 's3cret!123';
  await createMockUser(userName, password);
  accessToken = authenticateUser(userName, password);
};

const beforeEach = async (transaction) => {
  // Skip test identified by "get-users" operationId with status code 200
  if (transaction.operationId === 'get-users' && transaction.expectedStatusCode === 200) {
    transaction.skip = true;
  }

  // Skip all tests under the PUT /users path definition
  if (transaction.expected.method === 'PUT' && transaction.expected.path === '/users') {
    transaction.skip = true;
  }

  // Create mock resource before updating it
  if (transaction.expected.method === 'PUT' && transaction.expected.path === '/vehicles/{vehicleId}') {
    const vehicle = await createMockVehicle(accessToken);
    transaction.expected.path = transaction.expected.path.replace('{vehicleId}', vehicle.id)
  }

  return transaction;
};

const afterEach = async (transaction) => {
  // Delete mock vehicle resource
  if (transaction.expected.method === 'PUT' && transaction.expected.path === '/vehicles/{vehicleId}') {
    await deleteMockVehicle(accessToken);
  }
};

const afterAll = async () => {
  // Destroy test database after all tests
  await destroyTestDb();

  // Delete mock user after all tests
  await deleteMockUser(accessToken);
};

module.exports = {
  afterAll,
  afterEach,
  beforeAll,
  beforeEach
}