@ehuelsmann/chai-openapi-response-validator 0.15.0 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,15 +1,19 @@
1
1
  # Chai OpenAPI Response Validator
2
2
 
3
+ > **Notice:** Support for responses from [`request`](https://github.com/request/request#deprecated) and [`request-promise`](https://github.com/request/request-promise#deprecated) has been removed because both upstream projects are deprecated.
4
+
3
5
  [![downloads](https://img.shields.io/npm/dm/@ehuelsmann%2Fchai-openapi-response-validator)](https://www.npmjs.com/package/@ehuelsmann/chai-openapi-response-validator)
4
6
  [![npm](https://img.shields.io/npm/v/@ehuelsmann%2Fchai-openapi-response-validator.svg)](https://www.npmjs.com/package/@ehuelsmann/chai-openapi-response-validator)
5
- ![build status](https://github.com/openapi-library/OpenAPIValidators/actions/workflows/ci.yml/badge.svg)
7
+ ![build status](https://github.com/ehuelsmann/OpenAPIValidators/actions/workflows/ci.yml/badge.svg)
6
8
  ![style](https://img.shields.io/badge/code%20style-airbnb-ff5a5f.svg)
7
- [![codecov](https://codecov.io/gh/openapi-library/OpenAPIValidators/branch/master/graph/badge.svg)](https://codecov.io/gh/openapi-library/OpenAPIValidators)
8
- [![included](https://badgen.net/npm/types/@ehuelsmann%2Fchai-openapi-response-validator)](https://github.com/openapi-library/OpenAPIValidators/blob/master/packages/chai-openapi-response-validator/lib/index.ts)
9
- [![contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat)](https://github.com/openapi-library/OpenAPIValidators/blob/master/CONTRIBUTING.md)
9
+ [![codecov](https://codecov.io/gh/ehuelsmann/OpenAPIValidators/branch/master/graph/badge.svg)](https://codecov.io/gh/ehuelsmann/OpenAPIValidators)
10
+ [![included](https://badgen.net/npm/types/@ehuelsmann%2Fchai-openapi-response-validator)](https://github.com/ehuelsmann/OpenAPIValidators/blob/master/packages/chai-openapi-response-validator/lib/index.ts)
11
+ [![contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat)](https://github.com/ehuelsmann/OpenAPIValidators/blob/master/CONTRIBUTING.md)
10
12
 
11
13
  Use Chai to assert that HTTP responses satisfy an OpenAPI spec.
12
14
 
15
+ **Note** This project is a fork from the [openapi-library](https://github.com/openapi-library) project because that project is not maintained at the moment. This project contains updates and security fixes, but ideally will be merged back into that project, as soon as it's maintained again.
16
+
13
17
  ## Problem 😕
14
18
 
15
19
  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.
@@ -27,12 +31,12 @@ Features:
27
31
  - Supports OpenAPI specs in YAML and JSON formats
28
32
  - Supports `$ref` in response definitions (i.e. `$ref: '#/definitions/ComponentType/ComponentName'`)
29
33
  - Informs you if your OpenAPI spec is invalid
30
- - Supports responses from `axios`, `request-promise`, `supertest`, `superagent`, and `chai-http`
34
+ - Supports responses from `axios`, `supertest`, `superagent`, and `chai-http`
31
35
  - Use in [Mocha](#usage) and other test runners
32
36
 
33
37
  ## Contributing ✨
34
38
 
35
- If you've come here to help contribute - thanks! Take a look at the [contributing](https://github.com/openapi-library/OpenAPIValidators/blob/master/CONTRIBUTING.md) docs to get started.
39
+ If you've come here to help contribute - thanks! Take a look at the [contributing](https://github.com/ehuelsmann/OpenAPIValidators/blob/master/CONTRIBUTING.md) docs to get started.
36
40
 
37
41
  ## Installation
38
42
 
@@ -50,7 +54,9 @@ yarn add --dev @ehuelsmann/chai-openapi-response-validator
50
54
 
51
55
  ## Importing
52
56
 
53
- ES6 / TypeScript
57
+ This package ships with both **ESM** (preferred) and **CommonJS** builds, so it works in any environment.
58
+
59
+ ESM / TypeScript
54
60
 
55
61
  ```typescript
56
62
  import chaiResponseValidator from '@ehuelsmann/chai-openapi-response-validator';
@@ -0,0 +1,21 @@
1
+ import { OpenAPISpecObject } from '@ehuelsmann/openapi-validator';
2
+
3
+ declare global {
4
+ namespace Chai {
5
+ interface Assertion {
6
+ /**
7
+ * Check the HTTP response object satisfies a response defined in your OpenAPI spec.
8
+ * [See usage example](https://github.com/openapi-library/OpenAPIValidators/tree/master/packages/chai-openapi-response-validator#in-api-tests-validate-the-status-and-body-of-http-responses-against-your-openapi-spec)
9
+ */
10
+ satisfyApiSpec: Assertion;
11
+ /**
12
+ * Check the object satisfies a schema defined in your OpenAPI spec.
13
+ * [See usage example](https://github.com/openapi-library/OpenAPIValidators/tree/master/packages/chai-openapi-response-validator#in-unit-tests-validate-objects-against-schemas-defined-in-your-openapi-spec)
14
+ */
15
+ satisfySchemaInApiSpec(schemaName: string): Assertion;
16
+ }
17
+ }
18
+ }
19
+ declare function export_default(filepathOrObject: string | OpenAPISpecObject): Chai.ChaiPlugin;
20
+
21
+ export { export_default as default };
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { OpenAPISpecObject } from '@ehuelsmann/openapi-validator';
2
+
2
3
  declare global {
3
4
  namespace Chai {
4
5
  interface Assertion {
@@ -15,5 +16,6 @@ declare global {
15
16
  }
16
17
  }
17
18
  }
18
- export default function (filepathOrObject: string | OpenAPISpecObject): Chai.ChaiPlugin;
19
- //# sourceMappingURL=index.d.ts.map
19
+ declare function export_default(filepathOrObject: string | OpenAPISpecObject): Chai.ChaiPlugin;
20
+
21
+ export { export_default as default };
package/dist/index.js CHANGED
@@ -1,17 +1,206 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
4
9
  };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.default = default_1;
7
- const openapi_validator_1 = require("@ehuelsmann/openapi-validator");
8
- const satisfyApiSpec_1 = __importDefault(require("./assertions/satisfyApiSpec"));
9
- const satisfySchemaInApiSpec_1 = __importDefault(require("./assertions/satisfySchemaInApiSpec"));
10
- function default_1(filepathOrObject) {
11
- const openApiSpec = (0, openapi_validator_1.makeApiSpec)(filepathOrObject);
12
- return function (chai) {
13
- (0, satisfyApiSpec_1.default)(chai, openApiSpec);
14
- (0, satisfySchemaInApiSpec_1.default)(chai, openApiSpec);
15
- };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // lib/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ default: () => index_default
24
+ });
25
+ module.exports = __toCommonJS(index_exports);
26
+ var import_openapi_validator2 = require("@ehuelsmann/openapi-validator");
27
+
28
+ // lib/assertions/satisfyApiSpec.ts
29
+ var import_openapi_validator = require("@ehuelsmann/openapi-validator");
30
+
31
+ // lib/utils.ts
32
+ var import_util = require("util");
33
+ var stringify = (obj) => (0, import_util.inspect)(obj, { showHidden: false, depth: null });
34
+ var joinWithNewLines = (...lines) => lines.join("\n\n");
35
+
36
+ // lib/assertions/satisfyApiSpec.ts
37
+ function satisfyApiSpec_default(chai, openApiSpec) {
38
+ const { Assertion } = chai;
39
+ Assertion.addProperty("satisfyApiSpec", function() {
40
+ const actualResponse = (0, import_openapi_validator.makeResponse)(this._obj);
41
+ const validationError = openApiSpec.validateResponse(actualResponse);
42
+ const pass = !validationError;
43
+ this.assert(
44
+ pass,
45
+ pass ? "" : getExpectedResToSatisfyApiSpecMsg(
46
+ actualResponse,
47
+ openApiSpec,
48
+ validationError
49
+ ),
50
+ pass ? getExpectedResNotToSatisfyApiSpecMsg(actualResponse, openApiSpec) : "",
51
+ null
52
+ );
53
+ });
54
+ }
55
+ function getExpectedResToSatisfyApiSpecMsg(actualResponse, openApiSpec, validationError) {
56
+ const hint = "expected res to satisfy API spec";
57
+ const { status, req } = actualResponse;
58
+ const { method, path: requestPath } = req;
59
+ const unmatchedEndpoint = `${method} ${requestPath}`;
60
+ if (validationError.code === import_openapi_validator.ErrorCode.ServerNotFound) {
61
+ return joinWithNewLines(
62
+ hint,
63
+ `expected res to satisfy a '${status}' response defined for endpoint '${unmatchedEndpoint}' in your API spec`,
64
+ `res had request path '${requestPath}', but your API spec has no matching servers`,
65
+ `Servers found in API spec: ${openApiSpec.getServerUrls().join(", ")}`
66
+ );
67
+ }
68
+ if (validationError.code === import_openapi_validator.ErrorCode.BasePathNotFound) {
69
+ return joinWithNewLines(
70
+ hint,
71
+ `expected res to satisfy a '${status}' response defined for endpoint '${unmatchedEndpoint}' in your API spec`,
72
+ `res had request path '${requestPath}', but your API spec has basePath '${openApiSpec.spec.basePath}'`
73
+ );
74
+ }
75
+ if (validationError.code === import_openapi_validator.ErrorCode.PathNotFound) {
76
+ const pathNotFoundErrorMessage = joinWithNewLines(
77
+ hint,
78
+ `expected res to satisfy a '${status}' response defined for endpoint '${unmatchedEndpoint}' in your API spec`,
79
+ `res had request path '${requestPath}', but your API spec has no matching path`,
80
+ `Paths found in API spec: ${openApiSpec.paths().join(", ")}`
81
+ );
82
+ if ("didUserDefineBasePath" in openApiSpec && openApiSpec.didUserDefineBasePath) {
83
+ return joinWithNewLines(
84
+ pathNotFoundErrorMessage,
85
+ `'${requestPath}' matches basePath \`${openApiSpec.spec.basePath}\` but no <basePath/endpointPath> combinations`
86
+ );
87
+ }
88
+ if ("didUserDefineServers" in openApiSpec && openApiSpec.didUserDefineServers) {
89
+ return joinWithNewLines(
90
+ pathNotFoundErrorMessage,
91
+ `'${requestPath}' matches servers ${stringify(
92
+ openApiSpec.getMatchingServerUrls(requestPath)
93
+ )} but no <server/endpointPath> combinations`
94
+ );
95
+ }
96
+ return pathNotFoundErrorMessage;
97
+ }
98
+ const path = openApiSpec.findOpenApiPathMatchingRequest(req);
99
+ const endpoint = `${method} ${path}`;
100
+ if (validationError.code === import_openapi_validator.ErrorCode.MethodNotFound) {
101
+ const expectedPathItem = openApiSpec.findExpectedPathItem(req);
102
+ const expectedRequestOperations = Object.keys(expectedPathItem).map((operation) => operation.toUpperCase()).join(", ");
103
+ return joinWithNewLines(
104
+ hint,
105
+ `expected res to satisfy a '${status}' response defined for endpoint '${endpoint}' in your API spec`,
106
+ `res had request method '${method}', but your API spec has no '${method}' operation defined for path '${path}'`,
107
+ `Request operations found for path '${path}' in API spec: ${expectedRequestOperations}`
108
+ );
109
+ }
110
+ if (validationError.code === import_openapi_validator.ErrorCode.StatusNotFound) {
111
+ const expectedResponseOperation = (
112
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
113
+ openApiSpec.findExpectedResponseOperation(req)
114
+ );
115
+ const expectedResponseStatuses = Object.keys(
116
+ expectedResponseOperation.responses
117
+ ).join(", ");
118
+ return joinWithNewLines(
119
+ hint,
120
+ `expected res to satisfy a '${status}' response defined for endpoint '${endpoint}' in your API spec`,
121
+ `res had status '${status}', but your API spec has no '${status}' response defined for endpoint '${endpoint}'`,
122
+ `Response statuses found for endpoint '${endpoint}' in API spec: ${expectedResponseStatuses}`
123
+ );
124
+ }
125
+ const responseDefinition = openApiSpec.findExpectedResponse(actualResponse);
126
+ return joinWithNewLines(
127
+ hint,
128
+ `expected res to satisfy the '${status}' response defined for endpoint '${endpoint}' in your API spec`,
129
+ `res did not satisfy it because: ${validationError}`,
130
+ `res contained: ${actualResponse.toString()}`,
131
+ `The '${status}' response defined for endpoint '${endpoint}' in API spec: ${stringify(
132
+ responseDefinition
133
+ )}`
134
+ );
135
+ }
136
+ function getExpectedResNotToSatisfyApiSpecMsg(actualResponse, openApiSpec) {
137
+ const { status, req } = actualResponse;
138
+ const responseDefinition = openApiSpec.findExpectedResponse(actualResponse);
139
+ const endpoint = `${req.method} ${openApiSpec.findOpenApiPathMatchingRequest(
140
+ req
141
+ )}`;
142
+ return joinWithNewLines(
143
+ `expected res not to satisfy API spec`,
144
+ `expected res not to satisfy the '${status}' response defined for endpoint '${endpoint}' in your API spec`,
145
+ `res contained: ${actualResponse.toString()}`,
146
+ `The '${status}' response defined for endpoint '${endpoint}' in API spec: ${stringify(
147
+ responseDefinition
148
+ )}`
149
+ );
150
+ }
151
+
152
+ // lib/assertions/satisfySchemaInApiSpec.ts
153
+ function satisfySchemaInApiSpec_default(chai, openApiSpec) {
154
+ const { Assertion, AssertionError } = chai;
155
+ Assertion.addMethod("satisfySchemaInApiSpec", function(schemaName) {
156
+ const actualObject = this._obj;
157
+ const schema = openApiSpec.getSchemaObject(schemaName);
158
+ if (!schema) {
159
+ throw new AssertionError(
160
+ "The argument to satisfySchemaInApiSpec must match a schema in your API spec"
161
+ );
162
+ }
163
+ const validationError = openApiSpec.validateObject(actualObject, schema);
164
+ const pass = !validationError;
165
+ this.assert(
166
+ pass,
167
+ pass ? "" : getExpectReceivedToSatisfySchemaInApiSpecMsg(
168
+ actualObject,
169
+ schemaName,
170
+ schema,
171
+ validationError
172
+ ),
173
+ getExpectReceivedNotToSatisfySchemaInApiSpecMsg(
174
+ actualObject,
175
+ schemaName,
176
+ schema
177
+ ),
178
+ null
179
+ );
180
+ });
181
+ }
182
+ function getExpectReceivedToSatisfySchemaInApiSpecMsg(received, schemaName, schema, validationError) {
183
+ return joinWithNewLines(
184
+ `expected object to satisfy the '${schemaName}' schema defined in your API spec`,
185
+ `object did not satisfy it because: ${validationError}`,
186
+ `object was: ${stringify(received)}`,
187
+ `The '${schemaName}' schema in API spec: ${stringify(schema)}`
188
+ );
189
+ }
190
+ function getExpectReceivedNotToSatisfySchemaInApiSpecMsg(received, schemaName, schema) {
191
+ return joinWithNewLines(
192
+ `expected object not to satisfy the '${schemaName}' schema defined in your API spec`,
193
+ `object was: ${stringify(received)}`,
194
+ `The '${schemaName}' schema in API spec: ${stringify(schema)}`
195
+ );
196
+ }
197
+
198
+ // lib/index.ts
199
+ function index_default(filepathOrObject) {
200
+ const openApiSpec = (0, import_openapi_validator2.makeApiSpec)(filepathOrObject);
201
+ return function(chai) {
202
+ satisfyApiSpec_default(chai, openApiSpec);
203
+ satisfySchemaInApiSpec_default(chai, openApiSpec);
204
+ };
16
205
  }
17
206
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../lib/index.ts"],"names":[],"mappings":";;;;;AAsBA,4BAQC;AA9BD,qEAA+E;AAC/E,iFAAyD;AACzD,iGAAyE;AAoBzE,mBACE,gBAA4C;IAE5C,MAAM,WAAW,GAAG,IAAA,+BAAW,EAAC,gBAAgB,CAAC,CAAC;IAClD,OAAO,UAAU,IAAI;QACnB,IAAA,wBAAc,EAAC,IAAI,EAAE,WAAW,CAAC,CAAC;QAClC,IAAA,gCAAsB,EAAC,IAAI,EAAE,WAAW,CAAC,CAAC;IAC5C,CAAC,CAAC;AACJ,CAAC"}
1
+ {"version":3,"sources":["../lib/index.ts","../lib/assertions/satisfyApiSpec.ts","../lib/utils.ts","../lib/assertions/satisfySchemaInApiSpec.ts"],"sourcesContent":["import { makeApiSpec, OpenAPISpecObject } from '@ehuelsmann/openapi-validator';\nimport satisfyApiSpec from './assertions/satisfyApiSpec';\nimport satisfySchemaInApiSpec from './assertions/satisfySchemaInApiSpec';\n\ndeclare global {\n // eslint-disable-next-line @typescript-eslint/no-namespace\n namespace Chai {\n interface Assertion {\n /**\n * Check the HTTP response object satisfies a response defined in your OpenAPI spec.\n * [See usage example](https://github.com/openapi-library/OpenAPIValidators/tree/master/packages/chai-openapi-response-validator#in-api-tests-validate-the-status-and-body-of-http-responses-against-your-openapi-spec)\n */\n satisfyApiSpec: Assertion;\n /**\n * Check the object satisfies a schema defined in your OpenAPI spec.\n * [See usage example](https://github.com/openapi-library/OpenAPIValidators/tree/master/packages/chai-openapi-response-validator#in-unit-tests-validate-objects-against-schemas-defined-in-your-openapi-spec)\n */\n satisfySchemaInApiSpec(schemaName: string): Assertion;\n }\n }\n}\n\nexport default function (\n filepathOrObject: string | OpenAPISpecObject,\n): Chai.ChaiPlugin {\n const openApiSpec = makeApiSpec(filepathOrObject);\n return function (chai) {\n satisfyApiSpec(chai, openApiSpec);\n satisfySchemaInApiSpec(chai, openApiSpec);\n };\n}\n","import {\n ActualResponse,\n ErrorCode,\n makeResponse,\n OpenApi2Spec,\n OpenApi3Spec,\n OpenApiSpec,\n ValidationError,\n} from '@ehuelsmann/openapi-validator';\nimport { joinWithNewLines, stringify } from '../utils';\n\nexport default function (\n chai: Chai.ChaiStatic,\n openApiSpec: OpenApiSpec,\n): void {\n const { Assertion } = chai;\n\n Assertion.addProperty('satisfyApiSpec', function () {\n const actualResponse = makeResponse(this._obj); // eslint-disable-line no-underscore-dangle\n\n const validationError = openApiSpec.validateResponse(actualResponse);\n const pass = !validationError;\n this.assert(\n pass,\n pass\n ? ''\n : getExpectedResToSatisfyApiSpecMsg(\n actualResponse,\n openApiSpec,\n validationError,\n ),\n pass\n ? getExpectedResNotToSatisfyApiSpecMsg(actualResponse, openApiSpec)\n : '',\n null,\n );\n });\n}\n\nfunction getExpectedResToSatisfyApiSpecMsg(\n actualResponse: ActualResponse,\n openApiSpec: OpenApiSpec,\n validationError: ValidationError,\n): string {\n const hint = 'expected res to satisfy API spec';\n\n const { status, req } = actualResponse;\n const { method, path: requestPath } = req;\n const unmatchedEndpoint = `${method} ${requestPath}`;\n\n if (validationError.code === ErrorCode.ServerNotFound) {\n return joinWithNewLines(\n hint,\n `expected res to satisfy a '${status}' response defined for endpoint '${unmatchedEndpoint}' in your API spec`,\n `res had request path '${requestPath}', but your API spec has no matching servers`,\n `Servers found in API spec: ${(openApiSpec as OpenApi3Spec)\n .getServerUrls()\n .join(', ')}`,\n );\n }\n\n if (validationError.code === ErrorCode.BasePathNotFound) {\n return joinWithNewLines(\n hint,\n `expected res to satisfy a '${status}' response defined for endpoint '${unmatchedEndpoint}' in your API spec`,\n `res had request path '${requestPath}', but your API spec has basePath '${\n (openApiSpec as OpenApi2Spec).spec.basePath\n }'`,\n );\n }\n\n if (validationError.code === ErrorCode.PathNotFound) {\n const pathNotFoundErrorMessage = joinWithNewLines(\n hint,\n `expected res to satisfy a '${status}' response defined for endpoint '${unmatchedEndpoint}' in your API spec`,\n `res had request path '${requestPath}', but your API spec has no matching path`,\n `Paths found in API spec: ${openApiSpec.paths().join(', ')}`,\n );\n\n if (\n 'didUserDefineBasePath' in openApiSpec &&\n openApiSpec.didUserDefineBasePath\n ) {\n return joinWithNewLines(\n pathNotFoundErrorMessage,\n `'${requestPath}' matches basePath \\`${openApiSpec.spec.basePath}\\` but no <basePath/endpointPath> combinations`,\n );\n }\n\n if (\n 'didUserDefineServers' in openApiSpec &&\n openApiSpec.didUserDefineServers\n ) {\n return joinWithNewLines(\n pathNotFoundErrorMessage,\n `'${requestPath}' matches servers ${stringify(\n openApiSpec.getMatchingServerUrls(requestPath),\n )} but no <server/endpointPath> combinations`,\n );\n }\n return pathNotFoundErrorMessage;\n }\n\n const path = openApiSpec.findOpenApiPathMatchingRequest(req);\n const endpoint = `${method} ${path}`;\n\n if (validationError.code === ErrorCode.MethodNotFound) {\n const expectedPathItem = openApiSpec.findExpectedPathItem(req);\n const expectedRequestOperations = Object.keys(expectedPathItem)\n .map((operation) => operation.toUpperCase())\n .join(', ');\n return joinWithNewLines(\n hint,\n `expected res to satisfy a '${status}' response defined for endpoint '${endpoint}' in your API spec`,\n `res had request method '${method}', but your API spec has no '${method}' operation defined for path '${path}'`,\n `Request operations found for path '${path}' in API spec: ${expectedRequestOperations}`,\n );\n }\n\n if (validationError.code === ErrorCode.StatusNotFound) {\n const expectedResponseOperation =\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n openApiSpec.findExpectedResponseOperation(req)!;\n const expectedResponseStatuses = Object.keys(\n expectedResponseOperation.responses,\n ).join(', ');\n return joinWithNewLines(\n hint,\n `expected res to satisfy a '${status}' response defined for endpoint '${endpoint}' in your API spec`,\n `res had status '${status}', but your API spec has no '${status}' response defined for endpoint '${endpoint}'`,\n `Response statuses found for endpoint '${endpoint}' in API spec: ${expectedResponseStatuses}`,\n );\n }\n\n // validationError.code === ErrorCode.InvalidBody\n const responseDefinition = openApiSpec.findExpectedResponse(actualResponse);\n return joinWithNewLines(\n hint,\n `expected res to satisfy the '${status}' response defined for endpoint '${endpoint}' in your API spec`,\n `res did not satisfy it because: ${validationError}`,\n `res contained: ${actualResponse.toString()}`,\n `The '${status}' response defined for endpoint '${endpoint}' in API spec: ${stringify(\n responseDefinition,\n )}`,\n );\n}\n\nfunction getExpectedResNotToSatisfyApiSpecMsg(\n actualResponse: ActualResponse,\n openApiSpec: OpenApiSpec,\n): string {\n const { status, req } = actualResponse;\n const responseDefinition = openApiSpec.findExpectedResponse(actualResponse);\n const endpoint = `${req.method} ${openApiSpec.findOpenApiPathMatchingRequest(\n req,\n )}`;\n\n return joinWithNewLines(\n `expected res not to satisfy API spec`,\n `expected res not to satisfy the '${status}' response defined for endpoint '${endpoint}' in your API spec`,\n `res contained: ${actualResponse.toString()}`,\n `The '${status}' response defined for endpoint '${endpoint}' in API spec: ${stringify(\n responseDefinition,\n )}`,\n );\n}\n","import { inspect } from 'util';\n\nexport const stringify = (obj: unknown): string =>\n inspect(obj, { showHidden: false, depth: null });\n\nexport const joinWithNewLines = (...lines: string[]): string =>\n lines.join('\\n\\n');\n","import type { OpenApiSpec, Schema, ValidationError } from '@ehuelsmann/openapi-validator';\nimport { stringify, joinWithNewLines } from '../utils';\n\nexport default function (\n chai: Chai.ChaiStatic,\n openApiSpec: OpenApiSpec,\n): void {\n const { Assertion, AssertionError } = chai;\n\n Assertion.addMethod('satisfySchemaInApiSpec', function (schemaName) {\n const actualObject = this._obj; // eslint-disable-line no-underscore-dangle\n\n const schema = openApiSpec.getSchemaObject(schemaName);\n if (!schema) {\n // alert users they are misusing this assertion\n // eslint-disable-next-line @typescript-eslint/no-throw-literal\n throw new AssertionError(\n 'The argument to satisfySchemaInApiSpec must match a schema in your API spec',\n );\n }\n\n const validationError = openApiSpec.validateObject(actualObject, schema);\n const pass = !validationError;\n this.assert(\n pass,\n pass\n ? ''\n : getExpectReceivedToSatisfySchemaInApiSpecMsg(\n actualObject,\n schemaName,\n schema,\n validationError,\n ),\n getExpectReceivedNotToSatisfySchemaInApiSpecMsg(\n actualObject,\n schemaName,\n schema,\n ),\n null,\n );\n });\n}\n\nfunction getExpectReceivedToSatisfySchemaInApiSpecMsg(\n received: unknown,\n schemaName: string,\n schema: Schema,\n validationError: ValidationError,\n) {\n return joinWithNewLines(\n `expected object to satisfy the '${schemaName}' schema defined in your API spec`,\n `object did not satisfy it because: ${validationError}`,\n `object was: ${stringify(received)}`,\n `The '${schemaName}' schema in API spec: ${stringify(schema)}`,\n );\n}\n\nfunction getExpectReceivedNotToSatisfySchemaInApiSpecMsg(\n received: unknown,\n schemaName: string,\n schema: Schema,\n) {\n return joinWithNewLines(\n `expected object not to satisfy the '${schemaName}' schema defined in your API spec`,\n `object was: ${stringify(received)}`,\n `The '${schemaName}' schema in API spec: ${stringify(schema)}`,\n );\n}\n"],"mappings":"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","names":["import_openapi_validator"]}
package/dist/index.mjs ADDED
@@ -0,0 +1,188 @@
1
+ // lib/index.ts
2
+ import { makeApiSpec } from "@ehuelsmann/openapi-validator";
3
+
4
+ // lib/assertions/satisfyApiSpec.ts
5
+ import {
6
+ ErrorCode,
7
+ makeResponse
8
+ } from "@ehuelsmann/openapi-validator";
9
+
10
+ // lib/utils.ts
11
+ import { inspect } from "util";
12
+ var stringify = (obj) => inspect(obj, { showHidden: false, depth: null });
13
+ var joinWithNewLines = (...lines) => lines.join("\n\n");
14
+
15
+ // lib/assertions/satisfyApiSpec.ts
16
+ function satisfyApiSpec_default(chai, openApiSpec) {
17
+ const { Assertion } = chai;
18
+ Assertion.addProperty("satisfyApiSpec", function() {
19
+ const actualResponse = makeResponse(this._obj);
20
+ const validationError = openApiSpec.validateResponse(actualResponse);
21
+ const pass = !validationError;
22
+ this.assert(
23
+ pass,
24
+ pass ? "" : getExpectedResToSatisfyApiSpecMsg(
25
+ actualResponse,
26
+ openApiSpec,
27
+ validationError
28
+ ),
29
+ pass ? getExpectedResNotToSatisfyApiSpecMsg(actualResponse, openApiSpec) : "",
30
+ null
31
+ );
32
+ });
33
+ }
34
+ function getExpectedResToSatisfyApiSpecMsg(actualResponse, openApiSpec, validationError) {
35
+ const hint = "expected res to satisfy API spec";
36
+ const { status, req } = actualResponse;
37
+ const { method, path: requestPath } = req;
38
+ const unmatchedEndpoint = `${method} ${requestPath}`;
39
+ if (validationError.code === ErrorCode.ServerNotFound) {
40
+ return joinWithNewLines(
41
+ hint,
42
+ `expected res to satisfy a '${status}' response defined for endpoint '${unmatchedEndpoint}' in your API spec`,
43
+ `res had request path '${requestPath}', but your API spec has no matching servers`,
44
+ `Servers found in API spec: ${openApiSpec.getServerUrls().join(", ")}`
45
+ );
46
+ }
47
+ if (validationError.code === ErrorCode.BasePathNotFound) {
48
+ return joinWithNewLines(
49
+ hint,
50
+ `expected res to satisfy a '${status}' response defined for endpoint '${unmatchedEndpoint}' in your API spec`,
51
+ `res had request path '${requestPath}', but your API spec has basePath '${openApiSpec.spec.basePath}'`
52
+ );
53
+ }
54
+ if (validationError.code === ErrorCode.PathNotFound) {
55
+ const pathNotFoundErrorMessage = joinWithNewLines(
56
+ hint,
57
+ `expected res to satisfy a '${status}' response defined for endpoint '${unmatchedEndpoint}' in your API spec`,
58
+ `res had request path '${requestPath}', but your API spec has no matching path`,
59
+ `Paths found in API spec: ${openApiSpec.paths().join(", ")}`
60
+ );
61
+ if ("didUserDefineBasePath" in openApiSpec && openApiSpec.didUserDefineBasePath) {
62
+ return joinWithNewLines(
63
+ pathNotFoundErrorMessage,
64
+ `'${requestPath}' matches basePath \`${openApiSpec.spec.basePath}\` but no <basePath/endpointPath> combinations`
65
+ );
66
+ }
67
+ if ("didUserDefineServers" in openApiSpec && openApiSpec.didUserDefineServers) {
68
+ return joinWithNewLines(
69
+ pathNotFoundErrorMessage,
70
+ `'${requestPath}' matches servers ${stringify(
71
+ openApiSpec.getMatchingServerUrls(requestPath)
72
+ )} but no <server/endpointPath> combinations`
73
+ );
74
+ }
75
+ return pathNotFoundErrorMessage;
76
+ }
77
+ const path = openApiSpec.findOpenApiPathMatchingRequest(req);
78
+ const endpoint = `${method} ${path}`;
79
+ if (validationError.code === ErrorCode.MethodNotFound) {
80
+ const expectedPathItem = openApiSpec.findExpectedPathItem(req);
81
+ const expectedRequestOperations = Object.keys(expectedPathItem).map((operation) => operation.toUpperCase()).join(", ");
82
+ return joinWithNewLines(
83
+ hint,
84
+ `expected res to satisfy a '${status}' response defined for endpoint '${endpoint}' in your API spec`,
85
+ `res had request method '${method}', but your API spec has no '${method}' operation defined for path '${path}'`,
86
+ `Request operations found for path '${path}' in API spec: ${expectedRequestOperations}`
87
+ );
88
+ }
89
+ if (validationError.code === ErrorCode.StatusNotFound) {
90
+ const expectedResponseOperation = (
91
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
92
+ openApiSpec.findExpectedResponseOperation(req)
93
+ );
94
+ const expectedResponseStatuses = Object.keys(
95
+ expectedResponseOperation.responses
96
+ ).join(", ");
97
+ return joinWithNewLines(
98
+ hint,
99
+ `expected res to satisfy a '${status}' response defined for endpoint '${endpoint}' in your API spec`,
100
+ `res had status '${status}', but your API spec has no '${status}' response defined for endpoint '${endpoint}'`,
101
+ `Response statuses found for endpoint '${endpoint}' in API spec: ${expectedResponseStatuses}`
102
+ );
103
+ }
104
+ const responseDefinition = openApiSpec.findExpectedResponse(actualResponse);
105
+ return joinWithNewLines(
106
+ hint,
107
+ `expected res to satisfy the '${status}' response defined for endpoint '${endpoint}' in your API spec`,
108
+ `res did not satisfy it because: ${validationError}`,
109
+ `res contained: ${actualResponse.toString()}`,
110
+ `The '${status}' response defined for endpoint '${endpoint}' in API spec: ${stringify(
111
+ responseDefinition
112
+ )}`
113
+ );
114
+ }
115
+ function getExpectedResNotToSatisfyApiSpecMsg(actualResponse, openApiSpec) {
116
+ const { status, req } = actualResponse;
117
+ const responseDefinition = openApiSpec.findExpectedResponse(actualResponse);
118
+ const endpoint = `${req.method} ${openApiSpec.findOpenApiPathMatchingRequest(
119
+ req
120
+ )}`;
121
+ return joinWithNewLines(
122
+ `expected res not to satisfy API spec`,
123
+ `expected res not to satisfy the '${status}' response defined for endpoint '${endpoint}' in your API spec`,
124
+ `res contained: ${actualResponse.toString()}`,
125
+ `The '${status}' response defined for endpoint '${endpoint}' in API spec: ${stringify(
126
+ responseDefinition
127
+ )}`
128
+ );
129
+ }
130
+
131
+ // lib/assertions/satisfySchemaInApiSpec.ts
132
+ function satisfySchemaInApiSpec_default(chai, openApiSpec) {
133
+ const { Assertion, AssertionError } = chai;
134
+ Assertion.addMethod("satisfySchemaInApiSpec", function(schemaName) {
135
+ const actualObject = this._obj;
136
+ const schema = openApiSpec.getSchemaObject(schemaName);
137
+ if (!schema) {
138
+ throw new AssertionError(
139
+ "The argument to satisfySchemaInApiSpec must match a schema in your API spec"
140
+ );
141
+ }
142
+ const validationError = openApiSpec.validateObject(actualObject, schema);
143
+ const pass = !validationError;
144
+ this.assert(
145
+ pass,
146
+ pass ? "" : getExpectReceivedToSatisfySchemaInApiSpecMsg(
147
+ actualObject,
148
+ schemaName,
149
+ schema,
150
+ validationError
151
+ ),
152
+ getExpectReceivedNotToSatisfySchemaInApiSpecMsg(
153
+ actualObject,
154
+ schemaName,
155
+ schema
156
+ ),
157
+ null
158
+ );
159
+ });
160
+ }
161
+ function getExpectReceivedToSatisfySchemaInApiSpecMsg(received, schemaName, schema, validationError) {
162
+ return joinWithNewLines(
163
+ `expected object to satisfy the '${schemaName}' schema defined in your API spec`,
164
+ `object did not satisfy it because: ${validationError}`,
165
+ `object was: ${stringify(received)}`,
166
+ `The '${schemaName}' schema in API spec: ${stringify(schema)}`
167
+ );
168
+ }
169
+ function getExpectReceivedNotToSatisfySchemaInApiSpecMsg(received, schemaName, schema) {
170
+ return joinWithNewLines(
171
+ `expected object not to satisfy the '${schemaName}' schema defined in your API spec`,
172
+ `object was: ${stringify(received)}`,
173
+ `The '${schemaName}' schema in API spec: ${stringify(schema)}`
174
+ );
175
+ }
176
+
177
+ // lib/index.ts
178
+ function index_default(filepathOrObject) {
179
+ const openApiSpec = makeApiSpec(filepathOrObject);
180
+ return function(chai) {
181
+ satisfyApiSpec_default(chai, openApiSpec);
182
+ satisfySchemaInApiSpec_default(chai, openApiSpec);
183
+ };
184
+ }
185
+ export {
186
+ index_default as default
187
+ };
188
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../lib/index.ts","../lib/assertions/satisfyApiSpec.ts","../lib/utils.ts","../lib/assertions/satisfySchemaInApiSpec.ts"],"sourcesContent":["import { makeApiSpec, OpenAPISpecObject } from '@ehuelsmann/openapi-validator';\nimport satisfyApiSpec from './assertions/satisfyApiSpec';\nimport satisfySchemaInApiSpec from './assertions/satisfySchemaInApiSpec';\n\ndeclare global {\n // eslint-disable-next-line @typescript-eslint/no-namespace\n namespace Chai {\n interface Assertion {\n /**\n * Check the HTTP response object satisfies a response defined in your OpenAPI spec.\n * [See usage example](https://github.com/openapi-library/OpenAPIValidators/tree/master/packages/chai-openapi-response-validator#in-api-tests-validate-the-status-and-body-of-http-responses-against-your-openapi-spec)\n */\n satisfyApiSpec: Assertion;\n /**\n * Check the object satisfies a schema defined in your OpenAPI spec.\n * [See usage example](https://github.com/openapi-library/OpenAPIValidators/tree/master/packages/chai-openapi-response-validator#in-unit-tests-validate-objects-against-schemas-defined-in-your-openapi-spec)\n */\n satisfySchemaInApiSpec(schemaName: string): Assertion;\n }\n }\n}\n\nexport default function (\n filepathOrObject: string | OpenAPISpecObject,\n): Chai.ChaiPlugin {\n const openApiSpec = makeApiSpec(filepathOrObject);\n return function (chai) {\n satisfyApiSpec(chai, openApiSpec);\n satisfySchemaInApiSpec(chai, openApiSpec);\n };\n}\n","import {\n ActualResponse,\n ErrorCode,\n makeResponse,\n OpenApi2Spec,\n OpenApi3Spec,\n OpenApiSpec,\n ValidationError,\n} from '@ehuelsmann/openapi-validator';\nimport { joinWithNewLines, stringify } from '../utils';\n\nexport default function (\n chai: Chai.ChaiStatic,\n openApiSpec: OpenApiSpec,\n): void {\n const { Assertion } = chai;\n\n Assertion.addProperty('satisfyApiSpec', function () {\n const actualResponse = makeResponse(this._obj); // eslint-disable-line no-underscore-dangle\n\n const validationError = openApiSpec.validateResponse(actualResponse);\n const pass = !validationError;\n this.assert(\n pass,\n pass\n ? ''\n : getExpectedResToSatisfyApiSpecMsg(\n actualResponse,\n openApiSpec,\n validationError,\n ),\n pass\n ? getExpectedResNotToSatisfyApiSpecMsg(actualResponse, openApiSpec)\n : '',\n null,\n );\n });\n}\n\nfunction getExpectedResToSatisfyApiSpecMsg(\n actualResponse: ActualResponse,\n openApiSpec: OpenApiSpec,\n validationError: ValidationError,\n): string {\n const hint = 'expected res to satisfy API spec';\n\n const { status, req } = actualResponse;\n const { method, path: requestPath } = req;\n const unmatchedEndpoint = `${method} ${requestPath}`;\n\n if (validationError.code === ErrorCode.ServerNotFound) {\n return joinWithNewLines(\n hint,\n `expected res to satisfy a '${status}' response defined for endpoint '${unmatchedEndpoint}' in your API spec`,\n `res had request path '${requestPath}', but your API spec has no matching servers`,\n `Servers found in API spec: ${(openApiSpec as OpenApi3Spec)\n .getServerUrls()\n .join(', ')}`,\n );\n }\n\n if (validationError.code === ErrorCode.BasePathNotFound) {\n return joinWithNewLines(\n hint,\n `expected res to satisfy a '${status}' response defined for endpoint '${unmatchedEndpoint}' in your API spec`,\n `res had request path '${requestPath}', but your API spec has basePath '${\n (openApiSpec as OpenApi2Spec).spec.basePath\n }'`,\n );\n }\n\n if (validationError.code === ErrorCode.PathNotFound) {\n const pathNotFoundErrorMessage = joinWithNewLines(\n hint,\n `expected res to satisfy a '${status}' response defined for endpoint '${unmatchedEndpoint}' in your API spec`,\n `res had request path '${requestPath}', but your API spec has no matching path`,\n `Paths found in API spec: ${openApiSpec.paths().join(', ')}`,\n );\n\n if (\n 'didUserDefineBasePath' in openApiSpec &&\n openApiSpec.didUserDefineBasePath\n ) {\n return joinWithNewLines(\n pathNotFoundErrorMessage,\n `'${requestPath}' matches basePath \\`${openApiSpec.spec.basePath}\\` but no <basePath/endpointPath> combinations`,\n );\n }\n\n if (\n 'didUserDefineServers' in openApiSpec &&\n openApiSpec.didUserDefineServers\n ) {\n return joinWithNewLines(\n pathNotFoundErrorMessage,\n `'${requestPath}' matches servers ${stringify(\n openApiSpec.getMatchingServerUrls(requestPath),\n )} but no <server/endpointPath> combinations`,\n );\n }\n return pathNotFoundErrorMessage;\n }\n\n const path = openApiSpec.findOpenApiPathMatchingRequest(req);\n const endpoint = `${method} ${path}`;\n\n if (validationError.code === ErrorCode.MethodNotFound) {\n const expectedPathItem = openApiSpec.findExpectedPathItem(req);\n const expectedRequestOperations = Object.keys(expectedPathItem)\n .map((operation) => operation.toUpperCase())\n .join(', ');\n return joinWithNewLines(\n hint,\n `expected res to satisfy a '${status}' response defined for endpoint '${endpoint}' in your API spec`,\n `res had request method '${method}', but your API spec has no '${method}' operation defined for path '${path}'`,\n `Request operations found for path '${path}' in API spec: ${expectedRequestOperations}`,\n );\n }\n\n if (validationError.code === ErrorCode.StatusNotFound) {\n const expectedResponseOperation =\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n openApiSpec.findExpectedResponseOperation(req)!;\n const expectedResponseStatuses = Object.keys(\n expectedResponseOperation.responses,\n ).join(', ');\n return joinWithNewLines(\n hint,\n `expected res to satisfy a '${status}' response defined for endpoint '${endpoint}' in your API spec`,\n `res had status '${status}', but your API spec has no '${status}' response defined for endpoint '${endpoint}'`,\n `Response statuses found for endpoint '${endpoint}' in API spec: ${expectedResponseStatuses}`,\n );\n }\n\n // validationError.code === ErrorCode.InvalidBody\n const responseDefinition = openApiSpec.findExpectedResponse(actualResponse);\n return joinWithNewLines(\n hint,\n `expected res to satisfy the '${status}' response defined for endpoint '${endpoint}' in your API spec`,\n `res did not satisfy it because: ${validationError}`,\n `res contained: ${actualResponse.toString()}`,\n `The '${status}' response defined for endpoint '${endpoint}' in API spec: ${stringify(\n responseDefinition,\n )}`,\n );\n}\n\nfunction getExpectedResNotToSatisfyApiSpecMsg(\n actualResponse: ActualResponse,\n openApiSpec: OpenApiSpec,\n): string {\n const { status, req } = actualResponse;\n const responseDefinition = openApiSpec.findExpectedResponse(actualResponse);\n const endpoint = `${req.method} ${openApiSpec.findOpenApiPathMatchingRequest(\n req,\n )}`;\n\n return joinWithNewLines(\n `expected res not to satisfy API spec`,\n `expected res not to satisfy the '${status}' response defined for endpoint '${endpoint}' in your API spec`,\n `res contained: ${actualResponse.toString()}`,\n `The '${status}' response defined for endpoint '${endpoint}' in API spec: ${stringify(\n responseDefinition,\n )}`,\n );\n}\n","import { inspect } from 'util';\n\nexport const stringify = (obj: unknown): string =>\n inspect(obj, { showHidden: false, depth: null });\n\nexport const joinWithNewLines = (...lines: string[]): string =>\n lines.join('\\n\\n');\n","import type { OpenApiSpec, Schema, ValidationError } from '@ehuelsmann/openapi-validator';\nimport { stringify, joinWithNewLines } from '../utils';\n\nexport default function (\n chai: Chai.ChaiStatic,\n openApiSpec: OpenApiSpec,\n): void {\n const { Assertion, AssertionError } = chai;\n\n Assertion.addMethod('satisfySchemaInApiSpec', function (schemaName) {\n const actualObject = this._obj; // eslint-disable-line no-underscore-dangle\n\n const schema = openApiSpec.getSchemaObject(schemaName);\n if (!schema) {\n // alert users they are misusing this assertion\n // eslint-disable-next-line @typescript-eslint/no-throw-literal\n throw new AssertionError(\n 'The argument to satisfySchemaInApiSpec must match a schema in your API spec',\n );\n }\n\n const validationError = openApiSpec.validateObject(actualObject, schema);\n const pass = !validationError;\n this.assert(\n pass,\n pass\n ? ''\n : getExpectReceivedToSatisfySchemaInApiSpecMsg(\n actualObject,\n schemaName,\n schema,\n validationError,\n ),\n getExpectReceivedNotToSatisfySchemaInApiSpecMsg(\n actualObject,\n schemaName,\n schema,\n ),\n null,\n );\n });\n}\n\nfunction getExpectReceivedToSatisfySchemaInApiSpecMsg(\n received: unknown,\n schemaName: string,\n schema: Schema,\n validationError: ValidationError,\n) {\n return joinWithNewLines(\n `expected object to satisfy the '${schemaName}' schema defined in your API spec`,\n `object did not satisfy it because: ${validationError}`,\n `object was: ${stringify(received)}`,\n `The '${schemaName}' schema in API spec: ${stringify(schema)}`,\n );\n}\n\nfunction getExpectReceivedNotToSatisfySchemaInApiSpecMsg(\n received: unknown,\n schemaName: string,\n schema: Schema,\n) {\n return joinWithNewLines(\n `expected object not to satisfy the '${schemaName}' schema defined in your API spec`,\n `object was: ${stringify(received)}`,\n `The '${schemaName}' schema in API spec: ${stringify(schema)}`,\n );\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,9 +1,22 @@
1
1
  {
2
2
  "name": "@ehuelsmann/chai-openapi-response-validator",
3
- "version": "0.15.0",
3
+ "version": "0.16.0",
4
4
  "description": "Use Chai to assert that HTTP responses satisfy an OpenAPI spec",
5
- "main": "dist/index.js",
6
- "types": "dist/index.d.ts",
5
+ "main": "./dist/index.js",
6
+ "module": "./dist/index.mjs",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": {
11
+ "types": "./dist/index.d.mts",
12
+ "default": "./dist/index.mjs"
13
+ },
14
+ "require": {
15
+ "types": "./dist/index.d.ts",
16
+ "default": "./dist/index.js"
17
+ }
18
+ }
19
+ },
7
20
  "scripts": {
8
21
  "clean": "rimraf dist",
9
22
  "clean:openapi-validator": "cd ../openapi-validator && yarn clean",
@@ -11,15 +24,15 @@
11
24
  "format": "prettier --write ../../ --ignore-path ../../.prettierignore",
12
25
  "lint": "tsc --noEmit --project tsconfig.eslint.json && eslint .",
13
26
  "lint:fix": "yarn lint --fix",
14
- "build": "tsc",
15
- "test": "ts-mocha --extension ts --recursive",
27
+ "build": "tsup",
28
+ "test": "mocha --require ts-node/register --extension ts --recursive",
16
29
  "test:watch": "yarn test --watch",
17
30
  "test:coverage": "yarn clean && yarn clean:openapi-validator && yarn build && yarn build:openapi-validator && nyc yarn test && nyc report --reporter=lcov && nyc check-coverage",
18
31
  "test:coverage:browse": "yarn test:coverage; open ../coverage/lcov-report/index.html",
19
32
  "test:ci": "yarn format && yarn lint && yarn test:coverage",
20
33
  "prepack": "yarn build"
21
34
  },
22
- "repository": "https://github.com/openapi-library/OpenAPIValidators/tree/master/packages/chai-openapi-response-validator",
35
+ "repository": "https://github.com/ehuelsmann/OpenAPIValidators/tree/master/packages/chai-openapi-response-validator",
23
36
  "author": "OpenApiChai <openapichai@gmail.com>",
24
37
  "contributors": [
25
38
  "Jonny Spruce <jspruce94@gmail.com>",
@@ -35,9 +48,9 @@
35
48
  "validate"
36
49
  ],
37
50
  "bugs": {
38
- "url": "https://github.com/openapi-library/OpenAPIValidators/issues"
51
+ "url": "https://github.com/ehuelsmann/OpenAPIValidators/issues"
39
52
  },
40
- "homepage": "https://github.com/openapi-library/OpenAPIValidators/tree/master/packages/chai-openapi-response-validator#readme",
53
+ "homepage": "https://github.com/ehuelsmann/OpenAPIValidators/tree/master/packages/chai-openapi-response-validator#readme",
41
54
  "publishConfig": {
42
55
  "access": "public"
43
56
  },
@@ -46,8 +59,7 @@
46
59
  ],
47
60
  "devDependencies": {
48
61
  "@types/chai": "^4.2.15",
49
- "@types/mocha": "^8.2.1",
50
- "@types/request-promise": "^4.1.48",
62
+ "@types/mocha": "^10.0.10",
51
63
  "@types/supertest": "^7.2.0",
52
64
  "axios": "^1.15.0",
53
65
  "chai": "^6.2.2",
@@ -58,15 +70,14 @@
58
70
  "eslint-plugin-mocha": "^8.0.0",
59
71
  "express": "^5.2.1",
60
72
  "fs-extra": "^9.0.1",
61
- "mocha": "^8.2.0",
73
+ "mocha": "^11.7.4",
62
74
  "nyc": "15.1.0",
63
- "request": "^2.88.2",
64
- "request-promise": "^4.2.6",
65
75
  "rimraf": "^3.0.2",
66
76
  "supertest": "^7.2.2",
67
- "ts-mocha": "^8.0.0"
77
+ "ts-node": "^10.9.2",
78
+ "tsup": "^8.5.1"
68
79
  },
69
80
  "dependencies": {
70
- "@ehuelsmann/openapi-validator": "^0.15.0"
81
+ "@ehuelsmann/openapi-validator": "^0.16.0"
71
82
  }
72
83
  }
@@ -1,3 +0,0 @@
1
- import { OpenApiSpec } from '@ehuelsmann/openapi-validator';
2
- export default function (chai: Chai.ChaiStatic, openApiSpec: OpenApiSpec): void;
3
- //# sourceMappingURL=satisfyApiSpec.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"satisfyApiSpec.d.ts","sourceRoot":"","sources":["../../lib/assertions/satisfyApiSpec.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,WAAW,EAEZ,MAAM,+BAA+B,CAAC;AAGvC,MAAM,CAAC,OAAO,WACZ,IAAI,EAAE,IAAI,CAAC,UAAU,EACrB,WAAW,EAAE,WAAW,GACvB,IAAI,CAuBN"}
@@ -1,70 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.default = default_1;
4
- const openapi_validator_1 = require("@ehuelsmann/openapi-validator");
5
- const utils_1 = require("../utils");
6
- function default_1(chai, openApiSpec) {
7
- const { Assertion } = chai;
8
- Assertion.addProperty('satisfyApiSpec', function () {
9
- const actualResponse = (0, openapi_validator_1.makeResponse)(this._obj); // eslint-disable-line no-underscore-dangle
10
- const validationError = openApiSpec.validateResponse(actualResponse);
11
- const pass = !validationError;
12
- this.assert(pass, pass
13
- ? ''
14
- : getExpectedResToSatisfyApiSpecMsg(actualResponse, openApiSpec, validationError), pass
15
- ? getExpectedResNotToSatisfyApiSpecMsg(actualResponse, openApiSpec)
16
- : '', null);
17
- });
18
- }
19
- function getExpectedResToSatisfyApiSpecMsg(actualResponse, openApiSpec, validationError) {
20
- const hint = 'expected res to satisfy API spec';
21
- const { status, req } = actualResponse;
22
- const { method, path: requestPath } = req;
23
- const unmatchedEndpoint = `${method} ${requestPath}`;
24
- if (validationError.code === openapi_validator_1.ErrorCode.ServerNotFound) {
25
- return (0, utils_1.joinWithNewLines)(hint, `expected res to satisfy a '${status}' response defined for endpoint '${unmatchedEndpoint}' in your API spec`, `res had request path '${requestPath}', but your API spec has no matching servers`, `Servers found in API spec: ${openApiSpec
26
- .getServerUrls()
27
- .join(', ')}`);
28
- }
29
- if (validationError.code === openapi_validator_1.ErrorCode.BasePathNotFound) {
30
- return (0, utils_1.joinWithNewLines)(hint, `expected res to satisfy a '${status}' response defined for endpoint '${unmatchedEndpoint}' in your API spec`, `res had request path '${requestPath}', but your API spec has basePath '${openApiSpec.spec.basePath}'`);
31
- }
32
- if (validationError.code === openapi_validator_1.ErrorCode.PathNotFound) {
33
- const pathNotFoundErrorMessage = (0, utils_1.joinWithNewLines)(hint, `expected res to satisfy a '${status}' response defined for endpoint '${unmatchedEndpoint}' in your API spec`, `res had request path '${requestPath}', but your API spec has no matching path`, `Paths found in API spec: ${openApiSpec.paths().join(', ')}`);
34
- if ('didUserDefineBasePath' in openApiSpec &&
35
- openApiSpec.didUserDefineBasePath) {
36
- return (0, utils_1.joinWithNewLines)(pathNotFoundErrorMessage, `'${requestPath}' matches basePath \`${openApiSpec.spec.basePath}\` but no <basePath/endpointPath> combinations`);
37
- }
38
- if ('didUserDefineServers' in openApiSpec &&
39
- openApiSpec.didUserDefineServers) {
40
- return (0, utils_1.joinWithNewLines)(pathNotFoundErrorMessage, `'${requestPath}' matches servers ${(0, utils_1.stringify)(openApiSpec.getMatchingServerUrls(requestPath))} but no <server/endpointPath> combinations`);
41
- }
42
- return pathNotFoundErrorMessage;
43
- }
44
- const path = openApiSpec.findOpenApiPathMatchingRequest(req);
45
- const endpoint = `${method} ${path}`;
46
- if (validationError.code === openapi_validator_1.ErrorCode.MethodNotFound) {
47
- const expectedPathItem = openApiSpec.findExpectedPathItem(req);
48
- const expectedRequestOperations = Object.keys(expectedPathItem)
49
- .map((operation) => operation.toUpperCase())
50
- .join(', ');
51
- return (0, utils_1.joinWithNewLines)(hint, `expected res to satisfy a '${status}' response defined for endpoint '${endpoint}' in your API spec`, `res had request method '${method}', but your API spec has no '${method}' operation defined for path '${path}'`, `Request operations found for path '${path}' in API spec: ${expectedRequestOperations}`);
52
- }
53
- if (validationError.code === openapi_validator_1.ErrorCode.StatusNotFound) {
54
- const expectedResponseOperation =
55
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
56
- openApiSpec.findExpectedResponseOperation(req);
57
- const expectedResponseStatuses = Object.keys(expectedResponseOperation.responses).join(', ');
58
- return (0, utils_1.joinWithNewLines)(hint, `expected res to satisfy a '${status}' response defined for endpoint '${endpoint}' in your API spec`, `res had status '${status}', but your API spec has no '${status}' response defined for endpoint '${endpoint}'`, `Response statuses found for endpoint '${endpoint}' in API spec: ${expectedResponseStatuses}`);
59
- }
60
- // validationError.code === ErrorCode.InvalidBody
61
- const responseDefinition = openApiSpec.findExpectedResponse(actualResponse);
62
- return (0, utils_1.joinWithNewLines)(hint, `expected res to satisfy the '${status}' response defined for endpoint '${endpoint}' in your API spec`, `res did not satisfy it because: ${validationError}`, `res contained: ${actualResponse.toString()}`, `The '${status}' response defined for endpoint '${endpoint}' in API spec: ${(0, utils_1.stringify)(responseDefinition)}`);
63
- }
64
- function getExpectedResNotToSatisfyApiSpecMsg(actualResponse, openApiSpec) {
65
- const { status, req } = actualResponse;
66
- const responseDefinition = openApiSpec.findExpectedResponse(actualResponse);
67
- const endpoint = `${req.method} ${openApiSpec.findOpenApiPathMatchingRequest(req)}`;
68
- return (0, utils_1.joinWithNewLines)(`expected res not to satisfy API spec`, `expected res not to satisfy the '${status}' response defined for endpoint '${endpoint}' in your API spec`, `res contained: ${actualResponse.toString()}`, `The '${status}' response defined for endpoint '${endpoint}' in API spec: ${(0, utils_1.stringify)(responseDefinition)}`);
69
- }
70
- //# sourceMappingURL=satisfyApiSpec.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"satisfyApiSpec.js","sourceRoot":"","sources":["../../lib/assertions/satisfyApiSpec.ts"],"names":[],"mappings":"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"}
@@ -1,3 +0,0 @@
1
- import type { OpenApiSpec } from '@ehuelsmann/openapi-validator';
2
- export default function (chai: Chai.ChaiStatic, openApiSpec: OpenApiSpec): void;
3
- //# sourceMappingURL=satisfySchemaInApiSpec.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"satisfySchemaInApiSpec.d.ts","sourceRoot":"","sources":["../../lib/assertions/satisfySchemaInApiSpec.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAA2B,MAAM,+BAA+B,CAAC;AAG1F,MAAM,CAAC,OAAO,WACZ,IAAI,EAAE,IAAI,CAAC,UAAU,EACrB,WAAW,EAAE,WAAW,GACvB,IAAI,CAmCN"}
@@ -1,28 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.default = default_1;
4
- const utils_1 = require("../utils");
5
- function default_1(chai, openApiSpec) {
6
- const { Assertion, AssertionError } = chai;
7
- Assertion.addMethod('satisfySchemaInApiSpec', function (schemaName) {
8
- const actualObject = this._obj; // eslint-disable-line no-underscore-dangle
9
- const schema = openApiSpec.getSchemaObject(schemaName);
10
- if (!schema) {
11
- // alert users they are misusing this assertion
12
- // eslint-disable-next-line @typescript-eslint/no-throw-literal
13
- throw new AssertionError('The argument to satisfySchemaInApiSpec must match a schema in your API spec');
14
- }
15
- const validationError = openApiSpec.validateObject(actualObject, schema);
16
- const pass = !validationError;
17
- this.assert(pass, pass
18
- ? ''
19
- : getExpectReceivedToSatisfySchemaInApiSpecMsg(actualObject, schemaName, schema, validationError), getExpectReceivedNotToSatisfySchemaInApiSpecMsg(actualObject, schemaName, schema), null);
20
- });
21
- }
22
- function getExpectReceivedToSatisfySchemaInApiSpecMsg(received, schemaName, schema, validationError) {
23
- return (0, utils_1.joinWithNewLines)(`expected object to satisfy the '${schemaName}' schema defined in your API spec`, `object did not satisfy it because: ${validationError}`, `object was: ${(0, utils_1.stringify)(received)}`, `The '${schemaName}' schema in API spec: ${(0, utils_1.stringify)(schema)}`);
24
- }
25
- function getExpectReceivedNotToSatisfySchemaInApiSpecMsg(received, schemaName, schema) {
26
- return (0, utils_1.joinWithNewLines)(`expected object not to satisfy the '${schemaName}' schema defined in your API spec`, `object was: ${(0, utils_1.stringify)(received)}`, `The '${schemaName}' schema in API spec: ${(0, utils_1.stringify)(schema)}`);
27
- }
28
- //# sourceMappingURL=satisfySchemaInApiSpec.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"satisfySchemaInApiSpec.js","sourceRoot":"","sources":["../../lib/assertions/satisfySchemaInApiSpec.ts"],"names":[],"mappings":";;AAGA,4BAsCC;AAxCD,oCAAuD;AAEvD,mBACE,IAAqB,EACrB,WAAwB;IAExB,MAAM,EAAE,SAAS,EAAE,cAAc,EAAE,GAAG,IAAI,CAAC;IAE3C,SAAS,CAAC,SAAS,CAAC,wBAAwB,EAAE,UAAU,UAAU;QAChE,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,2CAA2C;QAE3E,MAAM,MAAM,GAAG,WAAW,CAAC,eAAe,CAAC,UAAU,CAAC,CAAC;QACvD,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,+CAA+C;YAC/C,+DAA+D;YAC/D,MAAM,IAAI,cAAc,CACtB,6EAA6E,CAC9E,CAAC;QACJ,CAAC;QAED,MAAM,eAAe,GAAG,WAAW,CAAC,cAAc,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;QACzE,MAAM,IAAI,GAAG,CAAC,eAAe,CAAC;QAC9B,IAAI,CAAC,MAAM,CACT,IAAI,EACJ,IAAI;YACF,CAAC,CAAC,EAAE;YACJ,CAAC,CAAC,4CAA4C,CAC1C,YAAY,EACZ,UAAU,EACV,MAAM,EACN,eAAe,CAChB,EACL,+CAA+C,CAC7C,YAAY,EACZ,UAAU,EACV,MAAM,CACP,EACD,IAAI,CACL,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,4CAA4C,CACnD,QAAiB,EACjB,UAAkB,EAClB,MAAc,EACd,eAAgC;IAEhC,OAAO,IAAA,wBAAgB,EACrB,mCAAmC,UAAU,mCAAmC,EAChF,sCAAsC,eAAe,EAAE,EACvD,eAAe,IAAA,iBAAS,EAAC,QAAQ,CAAC,EAAE,EACpC,QAAQ,UAAU,yBAAyB,IAAA,iBAAS,EAAC,MAAM,CAAC,EAAE,CAC/D,CAAC;AACJ,CAAC;AAED,SAAS,+CAA+C,CACtD,QAAiB,EACjB,UAAkB,EAClB,MAAc;IAEd,OAAO,IAAA,wBAAgB,EACrB,uCAAuC,UAAU,mCAAmC,EACpF,eAAe,IAAA,iBAAS,EAAC,QAAQ,CAAC,EAAE,EACpC,QAAQ,UAAU,yBAAyB,IAAA,iBAAS,EAAC,MAAM,CAAC,EAAE,CAC/D,CAAC;AACJ,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../lib/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAI/E,OAAO,CAAC,MAAM,CAAC;IAEb,UAAU,IAAI,CAAC;QACb,UAAU,SAAS;YACjB;;;eAGG;YACH,cAAc,EAAE,SAAS,CAAC;YAC1B;;;eAGG;YACH,sBAAsB,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;SACvD;KACF;CACF;AAED,MAAM,CAAC,OAAO,WACZ,gBAAgB,EAAE,MAAM,GAAG,iBAAiB,GAC3C,IAAI,CAAC,UAAU,CAMjB"}
package/dist/utils.d.ts DELETED
@@ -1,3 +0,0 @@
1
- export declare const stringify: (obj: unknown) => string;
2
- export declare const joinWithNewLines: (...lines: string[]) => string;
3
- //# sourceMappingURL=utils.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../lib/utils.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,SAAS,GAAI,KAAK,OAAO,KAAG,MACS,CAAC;AAEnD,eAAO,MAAM,gBAAgB,GAAI,GAAG,OAAO,MAAM,EAAE,KAAG,MAClC,CAAC"}
package/dist/utils.js DELETED
@@ -1,9 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.joinWithNewLines = exports.stringify = void 0;
4
- const util_1 = require("util");
5
- const stringify = (obj) => (0, util_1.inspect)(obj, { showHidden: false, depth: null });
6
- exports.stringify = stringify;
7
- const joinWithNewLines = (...lines) => lines.join('\n\n');
8
- exports.joinWithNewLines = joinWithNewLines;
9
- //# sourceMappingURL=utils.js.map
package/dist/utils.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"utils.js","sourceRoot":"","sources":["../lib/utils.ts"],"names":[],"mappings":";;;AAAA,+BAA+B;AAExB,MAAM,SAAS,GAAG,CAAC,GAAY,EAAU,EAAE,CAChD,IAAA,cAAO,EAAC,GAAG,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;AADtC,QAAA,SAAS,aAC6B;AAE5C,MAAM,gBAAgB,GAAG,CAAC,GAAG,KAAe,EAAU,EAAE,CAC7D,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AADR,QAAA,gBAAgB,oBACR"}