/supertest-openapi-validator

Performs OpenAPI contract checks with supertest.

Primary LanguageTypeScript


@soufantech/supertest-openapi-validator

Performs OpenAPI contract checks with supertest


typescript-image jest-image npm-image

Install

yarn add @soufantech/supertest-openapi-validator

This package is currently private. You'll need to set a valid npm token to SOUFAN_NPM_TOKEN environment variable in order to install it.

Usage

Specification file loading

Load the specification file (openapi.yaml in the example below) asynchronously.

/// file: get-contract.js

import path from 'path';
import {
  loadOpenapiContract,
} from '@soufantech/supertest-openapi-validator';

// contract is a promise
const contract = loadOpenapiContract(
  path.resolve(__dirname, 'openapi.yaml'),
);

export default (): => contract;

It is also possible to create multiple contract objects when there is multiple specification files.

Attention: loadOpenapiContract will throw an Error exception if the specification file cannot be read or is malformed.

Attention: loadOpenapiContract returns a promise that resolves to the contract object.

Loading the contract test files can be done like this:

/// file: foo.test.js

import getContract from './get-contract';

test('Loads a contract.', async () => {
  // It's necessary to await, because
  // getContract returns a promise.
  const contract = await getContract();
});

Validation

Create a validator using the createValidator contract method and call getChecker on the returned validator object to get a validator callback for use in supertest's expect:

/// file: app.test.js

import getContract from './get-contract';
import supertest from './supertest';
import app from './app'; // express app

const request = supertest(app);

test('Compliant request and response pass validation.', async () => {
  const contract = await getContract();
  const validator = contract.createValidator();

  await request.get('/health').expect(validator.getChecker());
});

Optionally, use the validate method to validate the object returned by supertest directly (this approach is useful for inspecting and debugging). The validate method returns a Result object, so get, getOrThrow and many other Result methods can be used to unwrap the supertest response object or the openapi validation error.

Testing using validate with get and getOrThrow:

/// file: app.test.js

import { OpenapiOperationError } from '@soufantech/supertest-openapi-validator';
import getContract from './get-contract';
import supertest from './supertest';
import app from './app'; // express app

const request = supertest(app);

test('Using `validate` with `getOrThrow`.', async () => {
  const contract = await getContract();
  const validator = contract.createValidator();

  const response = await request.get('/health');

  // returns the response object untouched or throws an exception if
  // validation fails.
  const validatedResponse = validator.validate(response).getOrThrow();
});

test('Using `validate` with `get`.', async () => {
  const contract = await getContract();
  const validator = contract.createValidator();

  const response = await request.get('/health');

  // returns either the response or the validation error.
  const responseOrError = validator.validate(response).get();

  // OpenapiOperationError is the base error for all validation fails.
  expect(responseOrError).not.toBeInstanceOf(OpenapiOperationError);
});

Bypassing specific validations

It's possible to bypass response, request and/or security validation. To do so, turn off (setting the corresponding property to false) one or more validation in the options object passed to the createValidator method:

// bypasses request validation
const validator1 = contract.createValidator({ request: false });

// bypasses response validation
const validator2 = contract.createValidator({ response: false });

// bypasses security and request validation
const validator3 = contract.createValidator({ security: false });

// bypasses security and request validation
const validator4 = contract.createValidator(
  { 
    security: false,
    request: false,
  }
);

// bypasses all validation (may be useful for debugging)
const validator5 = contract.createValidator(
  { 
    security: false,
    request: false,
    response: false,
  }
);

// bypasses no validation
const validator6 = contract.createValidator();

// bypasses no validation (redundant, but valid)
const validator7 = contract.createValidator(
  { 
    security: true,
    request: true,
    response: true,
  }
);

Error hierarchy

In order to identify the source of the error (if it happened during routing, request, response etc.) and to treat them conditionally, there is the following error hierarchy:

Error
└─ OpenapiOperationError
   ├─ OpenapiOperationRoutingError
   └─ OpenapiOperationValidationError
      ├─ OpenapiRequestOperationValidationError 
      ├─ OpenapiResponseOperationValidationError
      └─ OpenapiSecurityOperationValidationError

OpenapiOperationError

The base class for all operation (routing or validation) errors.

Extends: Error
Properties:

  • fulfilledHttpRequest {{ object }} :: a non-enumerable object containing the properties req {{ IHttpRequest }} and res {{ IHttpResponse }}.

OpenapiOperationRoutingError

A routing error - occurs when the request or response does not match any endpoints described in the specification file.

Extends: OpenapiOperationError
Properties:

  • originalError {{ Error }}: the original error thrown inside from prism's router.

OpenapiOperationValidationError

The base class for all validation errors.

Extends: OpenapiOperationError
Properties:

  • diagnostics {{ IPrismDiagnostic[] }} :: an array of prism diagnostic objects.

OpenapiRequestOperationValidationError

A validation error that originated from a request validation operation.

Extends: OpenapiOperationValidationError

OpenapiResponseOperationValidationError

A validation error that originated from a response validation operation.

Extends: OpenapiOperationValidationError

OpenapiResponseOperationValidationError

A validation error that originated from a security validation operation.

Extends: OpenapiSecurityValidationError


Built with ❤︎ by SouFan