Have ideas to improve npm?Join in the discussion! »

    jest-openapi
    TypeScript icon, indicating that this package has built-in type declarations

    0.13.0 • Public • Published

    jest-openapi

    downloads npm build status style codecov included contributions welcome

    Additional Jest matchers for asserting that HTTP responses satisfy an OpenAPI spec.

    Problem 😕

    If your server's behaviour doesn't match your API documentation, then you need to correct your server, your documentation, or both. The sooner you know the better.

    Solution 😄

    This plugin lets you automatically test whether your server's behaviour and documentation match. It adds Jest matchers that support the OpenAPI standard for documenting REST APIs. In your JavaScript tests, you can simply assert expect(responseObject).toSatisfyApiSpec()

    Features:

    • Validates the status and body of HTTP responses against your OpenAPI spec (see example)
    • Validates objects against schemas defined in your OpenAPI spec (see example)
    • Load your OpenAPI spec just once in your tests (load from a filepath or object)
    • Supports OpenAPI 2 and 3
    • Supports OpenAPI specs in YAML and JSON formats
    • Supports $ref in response definitions (i.e. $ref: '#/definitions/ComponentType/ComponentName')
    • Informs you if your OpenAPI spec is invalid
    • Supports responses from axios, request-promise, supertest, superagent, and chai-http
    • Bundled with a TypeScript Declaration File for use in TypeScript projects
    • Use in Jest, or use our sister package for Mocha and other test runners that support Chai

    Contributing

    If you've come here to help contribute - thanks! Take a look at the contributing docs to get started.

    Installation

    With npm:

    npm install --save-dev jest-openapi

    Usage

    In API tests, validate the status and body of HTTP responses against your OpenAPI spec:

    1. Write a test:

    // Import this plugin
    const jestOpenAPI = require('jest-openapi');
    
    // Load an OpenAPI file (YAML or JSON) into this plugin
    jestOpenAPI('path/to/openapi.yml');
    
    // Write your test
    describe('GET /example/endpoint', () => {
      it('should satisfy OpenAPI spec', async () => {
        // Get an HTTP response from your server (e.g. using axios)
        const res = await axios.get('http://localhost:3000/example/endpoint');
    
        expect(res.status).toEqual(200);
    
        // Assert that the HTTP response satisfies the OpenAPI spec
        expect(res).toSatisfyApiSpec();
      });
    });

    2. Write an OpenAPI Spec (and save to path/to/openapi.yml):

    openapi: 3.0.0
    info:
      title: Example API
      version: 1.0.0
    paths:
      /example:
        get:
          responses:
            200:
              description: Response body should be an object with fields 'stringProperty' and 'integerProperty'
              content:
                application/json:
                  schema:
                    type: object
                    required:
                      - stringProperty
                      - integerProperty
                    properties:
                      stringProperty:
                        type: string
                      integerProperty:
                        type: integer

    3. Run your test to validate your server's response against your OpenAPI spec:

    The assertion passes if the response status and body satisfy openapi.yml:
    // Response includes:
    {
      status: 200,
      body: {
        stringProperty: 'string',
        integerProperty: 123,
      },
    };
    The assertion fails if the response body is invalid:
    // Response includes:
    {
      status: 200,
      body: {
        stringProperty: 'string',
        integerProperty: 'invalid (should be an integer)',
      },
    };
    Output from test failure:
    expect(received).toSatisfyApiSpec() // Matches 'received' to a response defined in your API spec, then validates 'received' against it
    
    expected received to satisfy the '200' response defined for endpoint 'GET /example/endpoint' in your API spec
    received did not satisfy it because: integerProperty should be integer
    
    received contained: {
      body: {
          stringProperty: 'string',
          integerProperty: 'invalid (should be an integer)'
        }
      }
    }
    
    The '200' response defined for endpoint 'GET /example/endpoint' in API spec: {
      '200': {
        description: 'Response body should be a string',
        content: {
          'application/json': {
            schema: {
              type: 'string'
            }
          }
        }
      },
    }

    In unit tests, validate objects against schemas defined in your OpenAPI spec:

    1. Write a test:

    // Import this plugin
    const jestOpenAPI = require('jest-openapi');
    
    // Load an OpenAPI file (YAML or JSON) into this plugin
    jestOpenAPI('path/to/openapi.yml');
    
    // Write your test
    describe('myModule.getObject()', () => {
      it('should satisfy OpenAPI spec', async () => {
        // Run the function you want to test
        const myModule = require('path/to/your/module.js');
        const output = myModule.getObject();
    
        // Assert that the output satisfies a schema defined in your OpenAPI spec
        expect(output).toSatisfySchemaInApiSpec('ExampleSchemaObject');
      });
    });

    2. Write an OpenAPI Spec (and save to path/to/openapi.yml):

    openapi: 3.0.0
    info:
      title: Example API
      version: 1.0.0
    paths:
      /example:
        get:
          responses:
            200:
              description: Response body should be an ExampleSchemaObject
              content:
                application/json:
                  schema: '#/components/schemas/ExampleSchemaObject'
    components:
      schemas:
        ExampleSchemaObject:
          type: object
          required:
            - stringProperty
            - integerProperty
          properties:
            stringProperty:
              type: string
            integerProperty:
              type: integer

    3. Run your test to validate your object against your OpenAPI spec:

    The assertion passes if the object satisfies the schema ExampleSchemaObject:
    // object includes:
    {
      stringProperty: 'string',
      integerProperty: 123,
    };
    The assertion fails if the object does not satisfy the schema ExampleSchemaObject:
    // object includes:
    {
      stringProperty: 123,
      integerProperty: 123,
    };
    Output from test failure:
    expect(received).not.toSatisfySchemaInApiSpec(schemaName) // Matches 'received' to a schema defined in your API spec, then validates 'received' against it
    
    expected received to satisfy the 'StringSchema' schema defined in your API spec
    object did not satisfy it because: stringProperty should be string
    
    object was: {
        {
          stringProperty: 123,
          integerProperty: 123
        }
      }
    }
    
    The 'ExampleSchemaObject' schema in API spec: {
      type: 'object',
      required: [
        'stringProperty'
        'integerProperty'
      ],
      properties: {
        stringProperty: {
          type: 'string'
        },
        integerProperty: {
          type: 'integer'
        }
      }
    }

    Loading your OpenAPI spec (3 different ways):

    1. From an absolute filepath (see above)

    2. From an object:

    // Import this plugin
    const jestOpenAPI = require('jest-openapi');
    
    // Get an object representing your OpenAPI spec
    const openApiSpec = {
      openapi: '3.0.0',
      info: {
        title: 'Example API',
        version: '0.1.0',
      },
      paths: {
        '/example/endpoint': {
          get: {
            responses: {
              200: {
                description: 'Response body should be a string',
                content: {
                  'application/json': {
                    schema: {
                      type: 'string',
                    },
                  },
                },
              },
            },
          },
        },
      },
    };
    
    // Load that OpenAPI object into this plugin
    jestOpenAPI(openApiSpec);
    
    // Write your test
    describe('GET /example/endpoint', () => {
      it('should satisfy OpenAPI spec', async () => {
        // Get an HTTP response from your server (e.g. using axios)
        const res = await axios.get('http://localhost:3000/example/endpoint');
    
        expect(res.status).toEqual(200);
    
        // Assert that the HTTP response satisfies the OpenAPI spec
        expect(res).toSatisfyApiSpec();
      });
    });

    3. From a web endpoint:

    // Import this plugin
    const jestOpenAPI = require('jest-openapi');
    
    // Write your test
    describe('GET /example/endpoint', () => {
      // Load your OpenAPI spec from a web endpoint
      before(async () => {
        const axios = require('axios');
        const response = await axios.get('url/to/openapi/spec');
        const openApiSpec = response.data; // e.g. { openapi: '3.0.0', <etc> };
        jestOpenAPI(openApiSpec);
      });
    
      it('should satisfy OpenAPI spec', async () => {
        // Get an HTTP response from your server (e.g. using axios)
        const res = await axios.get('http://localhost:3000/example/endpoint');
    
        expect(res.status).toEqual(200);
    
        // Assert that the HTTP response satisfies the OpenAPI spec
        expect(res).toSatisfyApiSpec();
      });
    });

    Using this plugin in a TypeScript project

    Installation

    You don't need to npm install --save-dev @types/jest-openapi because we bundle our TypeScript Definition file into this package.

    Importing

    1. Make sure your tsconfig.json includes:
    {
      "compilerOptions": {
        esModuleInterop: true,
      }
    }
    1. Import like this:
    import jestOpenAPI from 'jest-openapi';

    Install

    npm i jest-openapi

    DownloadsWeekly Downloads

    90,502

    Version

    0.13.0

    License

    MIT

    Unpacked Size

    23.9 kB

    Total Files

    8

    Last publish

    Collaborators

    • avatar