chai-openapi-response-validator
Version:
Use Chai to assert that HTTP responses satisfy an OpenAPI spec
70 lines • 5.73 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const openapi_validator_1 = require("openapi-validator");
const utils_1 = require("../utils");
function default_1(chai, openApiSpec) {
const { Assertion } = chai;
Assertion.addProperty('satisfyApiSpec', function () {
const actualResponse = (0, openapi_validator_1.makeResponse)(this._obj); // eslint-disable-line no-underscore-dangle
const validationError = openApiSpec.validateResponse(actualResponse);
const pass = !validationError;
this.assert(pass, pass
? ''
: getExpectedResToSatisfyApiSpecMsg(actualResponse, openApiSpec, validationError), pass
? getExpectedResNotToSatisfyApiSpecMsg(actualResponse, openApiSpec)
: '', null);
});
}
exports.default = default_1;
function getExpectedResToSatisfyApiSpecMsg(actualResponse, openApiSpec, validationError) {
const hint = 'expected res to satisfy API spec';
const { status, req } = actualResponse;
const { method, path: requestPath } = req;
const unmatchedEndpoint = `${method} ${requestPath}`;
if (validationError.code === openapi_validator_1.ErrorCode.ServerNotFound) {
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
.getServerUrls()
.join(', ')}`);
}
if (validationError.code === openapi_validator_1.ErrorCode.BasePathNotFound) {
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}'`);
}
if (validationError.code === openapi_validator_1.ErrorCode.PathNotFound) {
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(', ')}`);
if ('didUserDefineBasePath' in openApiSpec &&
openApiSpec.didUserDefineBasePath) {
return (0, utils_1.joinWithNewLines)(pathNotFoundErrorMessage, `'${requestPath}' matches basePath \`${openApiSpec.spec.basePath}\` but no <basePath/endpointPath> combinations`);
}
if ('didUserDefineServers' in openApiSpec &&
openApiSpec.didUserDefineServers) {
return (0, utils_1.joinWithNewLines)(pathNotFoundErrorMessage, `'${requestPath}' matches servers ${(0, utils_1.stringify)(openApiSpec.getMatchingServerUrls(requestPath))} but no <server/endpointPath> combinations`);
}
return pathNotFoundErrorMessage;
}
const path = openApiSpec.findOpenApiPathMatchingRequest(req);
const endpoint = `${method} ${path}`;
if (validationError.code === openapi_validator_1.ErrorCode.MethodNotFound) {
const expectedPathItem = openApiSpec.findExpectedPathItem(req);
const expectedRequestOperations = Object.keys(expectedPathItem)
.map((operation) => operation.toUpperCase())
.join(', ');
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}`);
}
if (validationError.code === openapi_validator_1.ErrorCode.StatusNotFound) {
const expectedResponseOperation =
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
openApiSpec.findExpectedResponseOperation(req);
const expectedResponseStatuses = Object.keys(expectedResponseOperation.responses).join(', ');
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}`);
}
// validationError.code === ErrorCode.InvalidBody
const responseDefinition = openApiSpec.findExpectedResponse(actualResponse);
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)}`);
}
function getExpectedResNotToSatisfyApiSpecMsg(actualResponse, openApiSpec) {
const { status, req } = actualResponse;
const responseDefinition = openApiSpec.findExpectedResponse(actualResponse);
const endpoint = `${req.method} ${openApiSpec.findOpenApiPathMatchingRequest(req)}`;
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)}`);
}
//# sourceMappingURL=satisfyApiSpec.js.map