Chai OpenAPI 响应验证器

downloads npm build status style codecov included contributions welcome

使用 Chai 断言 HTTP 响应是否满足 OpenAPI 规范。

问题 😕

如果服务器的行为与您的 API 文档不匹配,则需要更正服务器、文档或两者。越早知道越好。

解决方案 😄

此插件允许您自动测试服务器的行为和文档是否匹配。它扩展了 Chai 断言库 以支持用于记录 REST API 的 OpenAPI 标准。在您的 JavaScript 测试中,您可以简单地断言 expect(responseObject).to.satisfyApiSpec

功能

  • 根据您的 OpenAPI 规范验证 HTTP 响应的状态和主体 (参见示例)
  • 验证对象是否符合您 OpenAPI 规范中定义的模式 (参见示例)
  • 在您的测试中仅加载一次 OpenAPI 规范(从文件路径或对象加载)
  • 支持 OpenAPI 23
  • 支持 YAML 和 JSON 格式的 OpenAPI 规范
  • 支持 $ref 在响应定义中(即 $ref: '#/definitions/ComponentType/ComponentName')
  • 如果您的 OpenAPI 规范无效,会通知您
  • 支持来自 axiosrequest-promisesupertestsuperagentchai-http 的响应
  • Mocha 和其他测试运行器中使用

贡献 ✨

如果您来这里帮忙贡献 - 感谢!查看 贡献 文档以开始。

安装

npm

npm install --save-dev chai-openapi-response-validator

yarn

yarn add --dev chai-openapi-response-validator

导入

ES6 / TypeScript

import chaiResponseValidator from 'chai-openapi-response-validator';

CommonJS / JavaScript

const chaiResponseValidator = require('chai-openapi-response-validator').default;

用法

在 API 测试中,根据您的 OpenAPI 规范验证 HTTP 响应的状态和主体

1. 写一个测试

// Set up Chai
import chai from 'chai';
const expect = chai.expect;

// Import this plugin
import chaiResponseValidator from 'chai-openapi-response-validator';

// Load an OpenAPI file (YAML or JSON) into this plugin
chai.use(chaiResponseValidator('path/to/openapi.yml'));

// Write your test (e.g. using Mocha)
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).to.equal(200);

    // Assert that the HTTP response satisfies the OpenAPI spec
    expect(res).to.satisfyApiSpec;
  });
});

2. 编写 OpenAPI 规范(并保存到 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. 运行您的测试以验证您的服务器的响应是否符合您的 OpenAPI 规范

如果响应状态和主体满足 openapi.yml,则断言通过
// Response includes:
{
  status: 200,
  body: {
    stringProperty: 'string',
    integerProperty: 123,
  },
};
如果响应主体无效,则断言失败
// Response includes:
{
  status: 200,
  body: {
    stringProperty: 'string',
    integerProperty: 'invalid (should be an integer)',
  },
};
测试失败的输出
AssertionError: expected res to satisfy API spec

expected res to satisfy the '200' response defined for endpoint 'GET /example/endpoint' in your API spec
res did not satisfy it because: integerProperty should be integer

res 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'
        }
      }
    }
  },
}

在单元测试中,验证对象是否符合您 OpenAPI 规范中定义的模式

1. 写一个测试

// Set up Chai
import chai from 'chai';
const expect = chai.expect;

// Import this plugin and the function you want to test
import chaiResponseValidator from 'chai-openapi-response-validator';
import { functionToTest } from 'path/to/your/code';

// Load an OpenAPI file (YAML or JSON) into this plugin
chai.use(chaiResponseValidator('path/to/openapi.yml'));

// Write your test (e.g. using Mocha)
describe('functionToTest()', () => {
  it('should satisfy OpenAPI spec', async () => {
    // Assert that the function returns a value satisfying a schema defined in your OpenAPI spec
    expect(functionToTest()).to.satisfySchemaInApiSpec('ExampleSchemaObject');
  });
});

2. 编写 OpenAPI 规范(并保存到 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. 运行您的测试以验证您的对象是否符合您的 OpenAPI 规范

如果对象满足模式 ExampleSchemaObject,则断言通过
// object includes:
{
  stringProperty: 'string',
  integerProperty: 123,
};
如果对象不满足模式 ExampleSchemaObject,则断言失败
// object includes:
{
  stringProperty: 123,
  integerProperty: 123,
};
测试失败的输出
AssertionError: expected object to satisfy schema 'ExampleSchemaObject' defined in 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'
    }
  }
}

加载您的 OpenAPI 规范(3 种不同的方式)

1. 从绝对文件路径 (参见上面)

2. 从对象

// Set up Chai
import chai from 'chai';
const expect = chai.expect;

// Import this plugin
import chaiResponseValidator from 'chai-openapi-response-validator';

// 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
chai.use(chaiResponseValidator(openApiSpec));

// Write your test (e.g. using Mocha)
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).to.equal(200);

    // Assert that the HTTP response satisfies the OpenAPI spec
    expect(res).to.satisfyApiSpec;
  });
});

3. 从 Web 端点

// Set up Chai
import chai from 'chai';
const expect = chai.expect;

// Import this plugin and an HTTP client (e.g. axios)
import chaiResponseValidator from 'chai-openapi-response-validator';
import axios from 'axios';

// Write your test (e.g. using Mocha)
describe('GET /example/endpoint', () => {
  // Load your OpenAPI spec from a web endpoint
  before(async () => {
    const response = await axios.get('url/to/openapi/spec');
    const openApiSpec = response.data; // e.g. { openapi: '3.0.0', <etc> };
    chai.use(chaiResponseValidator(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).to.equal(200);

    // Assert that the HTTP response satisfies the OpenAPI spec
    expect(res).to.satisfyApiSpec;
  });
});