just-api
Version:
Specification based API test framework for HTTP APIs (REST, GraphQL)
850 lines (688 loc) • 36.3 kB
JavaScript
Object.defineProperty(exports, "__esModule", {
value: true
});
var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }();
var _request = require('./request');
var _request2 = _interopRequireDefault(_request);
var _fs = require('fs');
var _fs2 = _interopRequireDefault(_fs);
var _path = require('path');
var _path2 = _interopRequireDefault(_path);
var _utils = require('./utils');
var _errors = require('./errors');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
const url = require('url');
const format = require('string-template');
const validateObject = require('jsonschema').validate;
const jsonPath = require('jsonpath');
const Cookie = require('request-cookies').Cookie;
class Spec {
constructor(data, suite) {
let type = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'test';
let dependencyOptions = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
this.suite = suite;
this.data = data;
this.assignName();
this.userContext = {};
this.setInitialContext();
this.type = type;
this.dependencyOpts = dependencyOptions;
this.requests = [];
this.result = {
suiteName: this.suite.name,
name: this.data.name,
status: null,
file: this.suite.file,
duration: 0,
startTime: new Date(),
endTime: null,
steps: [],
context: '',
error: null
};
}
setInitialContext() {
this.userContext.name = this.name;
}
assignName() {
if (this.isLoopSpec()) {
this.name = `${this.data.name} - loop iteration ${parseInt(this.data.loopData.index) + 1}`;
} else {
this.name = this.data.name;
}
}
getLoopItem() {
return this.data.loopData;
}
isLoopSpec() {
return this.data.loopSpec;
}
async init() {
return await this.run();
}
setEndTime() {
this.result.endTime = new Date();
}
setDuration() {
if (!this.result.endTime) {
this.setEndTime();
}
this.result.duration = this.result.endTime.getTime() - this.result.startTime.getTime();
this.duration = this.result.duration;
}
async run() {
if (this.type === 'test') {
return await this.runAsTest();
} else {
return this.runAsDependency();
}
}
async runAsTest() {
var startTime = new Date();
if (this.suite.hooks.before_each) {
await this.runHook('before each', this.suite.hooks.before_each);
}
if (this.data.before_test) {
await this.runHook('before test', this.data.before_test);
}
let testContext = Object.assign({}, this.userContext);
delete testContext.method;
let reqOptions = await this.buildRequestDetails(testContext);
let response = await this.processRequest(reqOptions);
try {
await this.validateResponse(response);
} catch (err) {
if (this.data.retry) {
let retriesResult = await this.processRetries(reqOptions);
response = retriesResult.response;
if (retriesResult.error === null) {
this.result.status = 'pass';
} else {
this.result.status = 'fail';
this.result.error = retriesResult.error;
let error = retriesResult.error;
error.message = `${error.message} \n request: ${response._req.method.toUpperCase()} ${response._req.href}`;
throw error;
}
} else {
this.result.status = 'fail';
this.result.error = err;
err.message = `${err.message} \n request: ${response._req.method.toUpperCase()} ${response._req.href}`;
throw err;
}
}
if (this.data.after_test) {
await this.runHook('after test', this.data.after_test, { response: response });
}
if (this.suite.hooks.after_each) {
await this.runHook('after each', this.suite.hooks.after_each, { response: response });
}
this.setEndTime();
this.setDuration();
this.result.error = null;
this.result.status = 'pass';
return this.result;
}
async processRetries(reqOptions) {
const retryInfo = this.data.retry;
let attempts = (0, _utils.isNumber)(retryInfo.count) ? parseInt(retryInfo.count) : 1;
let waitTimeBeforeEachAttempt = (0, _utils.isNumber)(retryInfo.wait_before_each) ? parseInt(retryInfo.wait_before_each) : 100;
let currentAttempts = 0;
while (currentAttempts <= attempts) {
await (0, _utils.wait)(waitTimeBeforeEachAttempt);
currentAttempts += 1;
let response;
try {
response = await this.processRequest(reqOptions);
await this.validateResponse(response);
return { error: null, response: response };
} catch (err) {
if (currentAttempts >= attempts) {
return { error: err, response: response };
}
}
}
}
async runAsDependency() {
const dependencyOptions = this.dependencyOpts;
delete dependencyOptions.method;
let reqOptions = await this.buildRequestDetails(dependencyOptions);
const response = await this.processRequest(reqOptions);
if (dependencyOptions.validateResponse) {
await this.validateResponse(response);
return response._response;
} else {
return response._response;
}
}
async buildRequestDetails(opts) {
let _reqOptions = {};
try {
_reqOptions.baseUrl = this.buildBaseURL(opts);
let subPath = this.buildPath(opts);
if (subPath) {
_reqOptions.url = subPath;
} else {
_reqOptions.url = _reqOptions.baseUrl;
delete _reqOptions.baseUrl;
}
_reqOptions.qs = this.buildQueryParams(opts);
_reqOptions.headers = this.buildHeaders(opts);
_reqOptions.cookiesData = this.buildCookies(opts);
_reqOptions.timeout = this.getTimeout(opts);
_reqOptions.method = this.data.request.method.toLowerCase();
} catch (err) {
let RequestBuilderError = (0, _errors.customError)('RequestBuilderError');
throw new RequestBuilderError(` ${err.name} ${err.message}`);
}
if (['patch', 'post', 'put'].indexOf(_reqOptions.method) !== -1) {
try {
let bodyOptions = this.buildRequestBody(opts, _reqOptions.headers, _reqOptions.method);
_reqOptions = Object.assign(_reqOptions, bodyOptions);
} catch (err) {
if (_errors.errorTypes.indexOf(err.name) !== -1) {
throw err;
} else {
let RequestBodyBuilderError = (0, _errors.customError)('RequestBodyBuilderError');
throw new RequestBodyBuilderError(` ${err.name} ${err.message}`);
}
}
}
this.addAdditionalRequestOptions(_reqOptions);
return _reqOptions;
}
async processRequest(opts) {
let _req = new _request2.default(opts, this);
return _req.send();
}
getTimeout(opts) {
return opts.read_timeout || this.data.request.read_timeout || this.suite.targetConfiguration.read_timeout;
}
async runHook(type, hookData, opts) {
try {
const data = hookData;
const self = this;
let _context = {
suite: this.suite.userContext,
runSpec: this.suite.runDependencySpec,
test: this.userContext,
_sctx: self.suite
};
if (this.isLoopSpec()) _context.loopItem = this.getLoopItem().value;
if (type === 'after test' || type === 'after each') {
_context.response = opts.response._response;
}
if (typeof data !== 'object') {
throw Error(`Invalid ${type} hook schema`);
}
let InvalidYAMLSuiteSchemaError = (0, _errors.customError)('InvalidYAMLSuiteSchemaError');
if (data.run_type === 'inline') {
if (data.inline) {
let inlineFunction = data.inline.function;
await (0, _utils.runInlineFunction)(inlineFunction, _context);
} else {
throw new InvalidYAMLSuiteSchemaError(`Test ${type} hook inline function definition is not specified`);
}
} else if (data.run_type === 'module') {
if (data.module) {
let modulePath = this.suite.resolveFile(data.module.module_path);
const module = (0, _utils.assertFileValidity)(modulePath, 'Test ${type} hook module');
const customModule = (0, _utils.loadModule)(module);
await (0, _utils.runModuleFunction)(customModule, data.module.function_name, _context);
} else {
throw new InvalidYAMLSuiteSchemaError(`Test ${type} hook module function definition is not specified`);
}
} else {
throw new InvalidYAMLSuiteSchemaError(`Test ${type} hook run type should be inline or module`);
}
} catch (err) {
let errorType;
if (type === 'before each') {
errorType = (0, _errors.customError)('BeforeEachHookError');
} else if (type === 'after each') {
errorType = (0, _errors.customError)('AfterEachHookError');
} else if (type === 'before test') {
errorType = (0, _errors.customError)('BeforeTestHookError');
} else if (type === 'after test') {
errorType = (0, _errors.customError)('AfterTestHookError');
} else {
throw new Error(`Unknown hook ${type}`);
}
throw new errorType(`${err.name || 'Error'} - ${err.message || err}`);
}
}
async validateResponse(response) {
const code = this.data.response.status_code;
if (code) {
this._validateStatus(response, code);
}
const expectedHeaders = this.data.response.headers;
if (expectedHeaders) {
this._validateHeaders(response, expectedHeaders);
}
const cookies = this.data.response.cookies;
if (cookies) {
this._validateCookies(response, cookies);
}
const jsonSchemaInfo = this.data.response.json_schema;
if (jsonSchemaInfo) {
this._validateJSONSchema(response, jsonSchemaInfo);
}
const jsonData = this.data.response.json_data;
if (jsonData) {
this._validateJSONData(response, jsonData);
}
if (this.data.response.custom_validator) {
await this.runCustomResponseValidator(response);
}
return true;
}
async runCustomResponseValidator(response) {
const data = this.data.response.custom_validator;
const dependencySuite = this.dependencyOpts.outerDependency ? this.dependencyOpts.outerDependencySuite : this.suite;
let _context = { response: response._response };
if (this.isLoopSpec()) _context.loopItem = this.getLoopItem().value;
let InvalidYAMLSuiteSchemaError = (0, _errors.customError)('InvalidYAMLSuiteSchemaError');
let CustomResponseValidationError = (0, _errors.customError)('CustomResponseValidationError');
try {
if (data.run_type === 'inline') {
if (data.inline) {
let inlineFunction = data.inline.function;
await (0, _utils.runInlineFunction)(inlineFunction, _context);
} else {
throw new InvalidYAMLSuiteSchemaError(`Custom validator inline function definition is not specified`);
}
} else if (data.run_type === 'module') {
if (data.module) {
let modulePath = dependencySuite.resolveFile(data.module.module_path);
const module = (0, _utils.assertFileValidity)(modulePath, 'custom validation module');
const customModule = (0, _utils.loadModule)(module);
await (0, _utils.runModuleFunction)(customModule, data.module.function_name, _context);
} else {
throw new InvalidYAMLSuiteSchemaError(`Custom validator module function definition is not specified`);
}
} else {
throw new InvalidYAMLSuiteSchemaError(`Custom validator run type should be inline or module`);
}
} catch (err) {
if (err.name === 'CustomResponseValidationError') {
throw err;
} else {
throw new CustomResponseValidationError(`${err.name || 'Error'} occurred in custom response validation \n ${err.message || err}`);
}
}
}
buildBaseURL(additionalOptions) {
let options;
if (additionalOptions.outerDependency) {
options = Object.assign({}, additionalOptions.outerDependencySuite.targetConfiguration, this.data.request, additionalOptions);
} else {
options = Object.assign({}, this.suite.targetConfiguration, this.data.request, additionalOptions);
}
return url.format({
protocol: options.scheme,
hostname: options.host,
port: options.port,
pathname: options.base_path
});
}
buildPath(additionalOptions) {
let path = additionalOptions.path || this.data.request.path || '';
if (path.length === 0) return '';
let defaultPathParams = {};
const specParams = this.data.request.path_params;
if (specParams) {
for (let item of specParams) {
defaultPathParams[item['name']] = item['value'];
}
}
let customPathParams = additionalOptions.path_params || {};
const params = Object.assign({}, defaultPathParams, customPathParams);
return format(path, params);
}
buildQueryParams(additionalOptions) {
let defaultParams = {};
const specParams = this.data.request.query_params;
if (specParams) {
for (let item of specParams) {
defaultParams[item['name']] = item['value'];
}
}
let customParams = additionalOptions.query_params || {};
return Object.assign({}, defaultParams, customParams);
}
buildHeaders(additionalOptions) {
let defaultHeaders = {};
const specHeaders = this.data.request.headers;
if (specHeaders) {
for (let item of specHeaders) {
defaultHeaders[item['name']] = item['value'];
}
}
let customHeaders = additionalOptions.headers || {};
let commonSuiteHeaders = this.data.ignore_suite_headers ? {} : additionalOptions.outerDependency ? additionalOptions.outerDependencySuite.commonHeaders : this.suite.commonHeaders;
return Object.assign({}, commonSuiteHeaders, defaultHeaders, customHeaders);
}
buildCookies(additionalOptions) {
let defaultCookies = {};
const specCookies = this.data.request.cookies;
if (specCookies) {
for (let item of specCookies) {
defaultCookies[item['name']] = item['value'];
}
}
let customCookies = additionalOptions.cookies || {};
return Object.assign({}, defaultCookies, customCookies);
}
addAdditionalRequestOptions(reqOptions) {
const supportedOptions = ['followRedirect', 'followAllRedirects', 'followOriginalHttpMethod', 'encoding', 'gzip'];
const options = this.data.request.additional_options;
if (options) {
for (let _ref of Object.entries(options)) {
var _ref2 = _slicedToArray(_ref, 2);
let key = _ref2[0];
let value = _ref2[1];
if (supportedOptions.indexOf(key) !== -1) {
reqOptions[key] = value;
}
}
}
}
buildRequestBody(additionalOptions, headers, method) {
let bodyData = {};
let requestContentType = headers['content-type'];
let RequestBodyNotFoundError = (0, _errors.customError)('RequestBodyNotFoundError');
let InvalidRequestSpecificationError = (0, _errors.customError)('InvalidRequestSpecificationError');
let InvalidRequestHeaderError = (0, _errors.customError)('InvalidRequestHeaderError');
let RequestBodyBuilderError = (0, _errors.customError)('RequestBodyBuilderError');
const payload = additionalOptions.payload || this.data.request.payload;
const dependencySuite = additionalOptions.outerDependency ? additionalOptions.outerDependencySuite : this.suite;
if (requestContentType && requestContentType.length > 1) {
let expectedBodyFields = ['body', 'form', 'form_data'];
if (!payload) {
throw new RequestBodyNotFoundError(`request content-type is ${requestContentType}, but request body is not found`);
}
if (typeof payload !== 'object') {
throw new RequestBodyNotFoundError(`request content-type is ${requestContentType}, invalid specification for request body. \n Provide request body as one of ${expectedBodyFields} in payload `);
}
let reqKeys = Object.keys(payload);
let providedFields = reqKeys.filter(key => expectedBodyFields.indexOf(key) !== -1);
if (providedFields.length < 1) {
throw new RequestBodyNotFoundError(`Request method is ${method}, but request specification does not have any expected body fields. \n Provide request body as one of ${expectedBodyFields}`);
}
if (providedFields.length > 1) {
throw new InvalidRequestSpecificationError(`request method is ${method}, and request specification contains more than one of expected body fields. Provide one of ${expectedBodyFields}`);
}
let providedBodyField = providedFields[0];
if (providedBodyField === 'body') {
let givenBody = payload.body;
if (givenBody.type === 'binary') {
let file = dependencySuite.resolveFile(payload.body.content);
try {
let fileExistsAndFile = _fs2.default.lstatSync(file).isFile();
if (fileExistsAndFile) {
bodyData.body = _fs2.default.createReadStream(file);
} else {
throw new RequestBodyBuilderError(`${file} is not a file, Provide a valid file path to be sent as body content`);
}
} catch (e) {
if (e.code == 'ENOENT') {
throw new RequestBodyBuilderError(`ENOENT file at '${file}' does not exist, Provide a valid file path to be sent as body content`);
} else {
throw e;
}
}
} else if (givenBody.type === 'text') {
if (typeof givenBody.content === 'string' || typeof givenBody.content === 'number') {
bodyData.body = givenBody.content.toString();
} else {
throw new InvalidRequestSpecificationError(`Payload type is given as text, but content provided is not a string or number`);
}
} else if (givenBody.type === 'json') {
if (typeof givenBody.content === 'string' || typeof givenBody.content === 'number') {
bodyData.body = givenBody.content;
} else if (typeof givenBody.content === 'object') {
if (requestContentType === 'application/json') {
bodyData.body = JSON.stringify(givenBody.content);
} else {
throw new InvalidRequestSpecificationError(`Request body is an object but content-type header value is not application/json`);
}
} else {
try {
bodyData.body = JSON.stringify(givenBody.content);
} catch (error) {
throw new RequestBodyBuilderError(`${error.name} Unable to dump the body content as json \n ${error.message}`);
}
}
} else {
throw new InvalidRequestSpecificationError(`body type should be one of binary, json or text`);
}
}
if (providedBodyField === 'form') {
if (requestContentType !== 'application/x-www-form-urlencoded') {
throw new InvalidRequestHeaderError(`Request body is provided as form but request Content-Type is ${requestContentType}. It should be application/x-www-form-urlencoded`);
}
bodyData.form = payload.form;
}
if (providedBodyField === 'form_data') {
let formData = {};
let giveFormData = payload.form_data;
if (requestContentType !== 'multipart/form-data') {
throw new InvalidRequestHeaderError(`Request body is provided as formData but request Content-Type is ${requestContentType}. It should be multipart/form-data`);
}
for (let formParam of giveFormData) {
if (formParam.type === 'file') {
let file = dependencySuite.resolveFile(formParam.content);
try {
let fileExistsAndFile = _fs2.default.lstatSync(file).isFile();
if (fileExistsAndFile) {
let paramData = {};
paramData.value = _fs2.default.createReadStream(file);
paramData.options = formParam.options;
formData[formParam.name] = paramData;
} else {
throw new RequestBodyBuilderError(` '${file}' is not a file, Provide a valid path for content of form body`);
}
} catch (e) {
if (e.code == 'ENOENT') {
throw new RequestBodyBuilderError(`ENOENT file at '${file}' does not exist, Provide a valid path for content of form body`);
} else {
throw e;
}
}
} else if (formParam.type === 'text') {
let paramData = {};
if (typeof formParam.content === 'string' || typeof formParam.content === 'number') {
paramData.value = formParam.content.toString();
paramData.options = formParam.options;
formData[formParam.name] = paramData;
} else {
throw new InvalidRequestSpecificationError(`Multipart form field type is given as text, but content provided is not a string or number`);
}
} else if (formParam.type === 'json') {
let paramData = {};
if (typeof formParam.content === 'string' || typeof formParam.content === 'number') {
paramData.value = formParam.content;
paramData.options = formParam.options;
formData[formParam.name] = paramData;
} else if (typeof formParam.content === 'object') {
paramData.value = JSON.stringify(formParam.content);
paramData.options = formParam.options;
formData[formParam.name] = paramData;
} else {
try {
paramData.value = JSON.stringify(formParam.content);
} catch (error) {
throw new RequestBodyBuilderError(`${error.name} Unable to dump the body content as json \n ${error.message}`);
}
paramData.options = formParam.options;
formData[formParam.name] = paramData;
}
} else {
throw new InvalidRequestSpecificationError(`body type should be one of binary, json or text`);
}
}
bodyData.formData = formData;
}
} else if (payload && !requestContentType) {
throw new InvalidRequestHeaderError(`Request method is ${method},request body is provided but Content-Type header is not provided`);
} else {
return bodyData;
}
return bodyData;
}
_validateStatus(response, code) {
if (code !== response._response.statusCode) {
let ResponseStatusCodeDidNotMatchError = (0, _errors.customError)('ResponseStatusCodeDidNotMatchError');
throw new ResponseStatusCodeDidNotMatchError(`Expected status code: ${code}, Actual status code: ${response._response.statusCode}`);
}
return true;
}
_validateHeaders(response, expectedHeaders) {
let headers = {};
let ResponseHeaderValueDidNotMatchError = (0, _errors.customError)('ResponseHeaderValueDidNotMatchError');
for (let item of expectedHeaders) {
headers[item['name'].toLowerCase()] = item['value'];
}
const actualHeaders = response._response.headers;
for (let headerKey in headers) {
let expectedHeaderValue = headers[headerKey];
let actualHeaderValue = actualHeaders[headerKey];
if (typeof actualHeaderValue === 'undefined') {
throw new ResponseHeaderValueDidNotMatchError(`Expected value for header: ${headerKey} is ${expectedHeaderValue}, Actual value: [couldn't find it in response headers]`);
}
if (expectedHeaderValue.constructor.name === 'RegExp') {
const result = expectedHeaderValue.test(actualHeaderValue.toString());
if (!result) {
throw new ResponseHeaderValueDidNotMatchError(`Header value did not match with expected Regex. Expected value for header: ${headerKey} is to match RegExp ${expectedHeaderValue}, Actual value: ${actualHeaderValue}`);
}
} else {
if (expectedHeaderValue.toString() !== actualHeaderValue.toString()) {
throw new ResponseHeaderValueDidNotMatchError(`Expected value for header: ${headerKey} is ${expectedHeaderValue}, Actual value: ${actualHeaderValue}`);
}
}
}
return true;
}
_validateCookies(response, expectedCookies) {
let cookies = {};
let ResponseCookieValueDidNotMatchError = (0, _errors.customError)('ResponseCookieValueDidNotMatchError');
for (let item of expectedCookies) {
cookies[item['name']] = { value: item['value'] };
}
let rawCookies = response._response.headers['set-cookie'];
let actualCookies = {};
for (let idx in rawCookies) {
let cookie = new Cookie(rawCookies[idx]);
actualCookies[cookie.key] = {
value: cookie.value,
expires: cookie.expires
};
}
for (let item in cookies) {
let expectedCookieDetails = cookies[item];
let actualCookieDetails = actualCookies[item];
if (typeof actualCookieDetails === 'undefined') {
throw new ResponseCookieValueDidNotMatchError(`Expected value for Cookie: ${item} is ${expectedCookieDetails.value}, Actual value: [couldn't find it in response cookies]`);
}
if (expectedCookieDetails.value.constructor.name === 'RegExp') {
const result = expectedCookieDetails.value.test(actualCookieDetails.value.toString());
if (!result) {
throw new ResponseCookieValueDidNotMatchError(`Cookie value did not match with expected Regex. Expected value for cookie: ${item} is to match RegExp ${expectedCookieDetails.value}, Actual value: ${actualCookieDetails.value}`);
}
} else {
if (expectedCookieDetails.value.toString() !== actualCookieDetails.value.toString()) {
throw new ResponseCookieValueDidNotMatchError(`Expected value for cookie: ${item} is ${expectedCookieDetails.value}, Actual value: ${actualCookieDetails.value}`);
}
}
}
return true;
}
_validateJSONData(response, jsonData) {
let jsonBody;
let JSONBodyParseError = (0, _errors.customError)('JSONBodyParseError');
let ResponseJSONDataMismatchError = (0, _errors.customError)('ResponseJSONDataMismatchError');
try {
jsonBody = JSON.parse(response._response.body);
} catch (err) {
throw new JSONBodyParseError(`${err.name} Error occurred while parsing the body as json \n ${err.message}`);
}
for (let eachJsonData of jsonData) {
const values = jsonPath.query(jsonBody, eachJsonData.path);
if (!values) {
throw new ResponseJSONDataMismatchError(`JSON Path evaluation did not return any matching value, json path: ${eachJsonData.path}`);
}
if (eachJsonData.value === null) {
if (values[0] !== eachJsonData.value) {
throw new ResponseJSONDataMismatchError(`JSON path evaluated value did not match with expected value (null), json path: ${eachJsonData.path}, Actual value: ${values[0]}, Expected value: ${eachJsonData.value}`);
}
} else if ((0, _utils.isNumber)(eachJsonData.value) || eachJsonData.value.constructor.name === 'String') {
if (values[0] !== eachJsonData.value) {
throw new ResponseJSONDataMismatchError(`JSON path evaluated value did not match with expected value, json path: ${eachJsonData.path}, Actual value: ${values[0]}, Expected value: ${eachJsonData.value}`);
}
} else if (eachJsonData.value.constructor.name === 'RegExp') {
const result = eachJsonData.value.test(values[0]);
if (!result) {
throw new ResponseJSONDataMismatchError(`JSON path evaluated value did not match the expected Regexp, json path: ${eachJsonData.path}, Regexp: ${eachJsonData.value}, Actual value: ${values[0]}`);
}
} else if (eachJsonData.value.constructor.name === 'Array') {
if (!(0, _utils.equals)(values[0], eachJsonData.value)) {
throw new ResponseJSONDataMismatchError(`JSON path evaluated value did not match with expected value, json path: ${eachJsonData.path}, Actual value: ${JSON.stringify(values[0])}, Expected value: ${JSON.stringify(eachJsonData.value)}`);
}
} else if (eachJsonData.value.constructor.name === 'Object') {
if (!(0, _utils.equals)(values[0], eachJsonData.value)) {
throw new ResponseJSONDataMismatchError(`JSON path evaluated value did not match with expected value, json path: ${eachJsonData.path}, Actual value: ${JSON.stringify(values[0])}, Expected value: ${JSON.stringify(eachJsonData.value)}`);
}
} else if (eachJsonData.value.constructor.name === 'Boolean') {
if (values[0] !== eachJsonData.value) {
throw new ResponseJSONDataMismatchError(`JSON path evaluated value did not match with expected Boolean value, json path: ${eachJsonData.path}, Actual value: ${values[0]}, Expected value: ${eachJsonData.value}`);
}
} else {
throw new Error(`Unknown json data value type, only Array, Object, RegExp, Number, Boolean & String are allowed`);
}
}
return true;
}
_validateJSONSchema(response, jsonSchemaInfo) {
let InvalidSpecificationSchemaError = (0, _errors.customError)('InvalidSpecificationSchemaError');
let ResponseJSONSchemaValidationError = (0, _errors.customError)('ResponseJSONSchemaValidationError');
let expectedSchema;
const dependencySuite = this.dependencyOpts.outerDependency ? this.dependencyOpts.outerDependencySuite : this.suite;
try {
if (jsonSchemaInfo.type === 'inline') {
try {
expectedSchema = JSON.parse(jsonSchemaInfo['$ref']);
} catch (e) {
throw new ResponseJSONSchemaValidationError(`${e.name} occurred while parsing the inline input schema \n ${e.message} \n Input schema \n ${jsonSchemaInfo['$ref']}`);
}
} else if (jsonSchemaInfo.type === 'file') {
const schemaFile = dependencySuite.resolveFile(jsonSchemaInfo['$ref']);
const fileData = _fs2.default.readFileSync(schemaFile, 'utf8');
try {
expectedSchema = JSON.parse(fileData);
} catch (e) {
throw new ResponseJSONSchemaValidationError(`${e.name} occurred while parsing the input schema in '${schemaFile}' \n ${e.message} \n Input schema: \n ${fileData}`);
}
} else {
throw new InvalidSpecificationSchemaError(`Response json schema type should be inline or file`);
}
const schemaValidation = validateObject(JSON.parse(response._response.body), expectedSchema);
if (schemaValidation.errors.length >= 1) {
let errors = [];
for (let error of schemaValidation.errors) {
errors.push(`Response json schema validation failed for property - ${error.property}, message: ${error.message}`);
}
throw new ResponseJSONSchemaValidationError(errors.join('\n'));
}
} catch (err) {
if (err.name === 'ResponseJSONSchemaValidationError') {
throw err;
} else {
throw new ResponseJSONSchemaValidationError(`${err.name} occurred during response json schema validation \n ${err.message}`);
}
}
}
}
exports.default = Spec;
module.exports = exports['default'];
;