UNPKG

rest-assured-ts

Version:
520 lines (515 loc) 24 kB
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; import { assert, expect } from "chai"; import { DataTable } from "@cucumber/cucumber"; import { unset } from "lodash"; import loadJsonFile from "load-json-file"; const jsonPath = require('jsonpath'); /** * This method is used to display JSON response in an easy-to-read format * @param {object} json - JSON response */ export function prettyPrintJSON(json) { return JSON.stringify(json, null, " "); } /** * This method is used for the negative validation of JSON response after making REST call * Json response should not contain json path parameter or values that are passed from feature file (DataTable) or Map * Where sending input as JSON Response and DataTable or Map * Where DataTable is a 2D array , sending row and columns as key value pair * This will internally refer invalidJsonPathWithRegularExpressionForMap by passing JSON path(responseBody) * invalidJsonPathWithRegularExpressionForMap: It validates JSON response with DataTable values * @param {object} responseBody - json response after making REST call * @param {DataTable | Map<string, any>} jsonKeyValues - Send Json response path parameter and values as a Cucumber DataTable or Map * @returns {void} */ export function validateJsonResponseNotIncludes(responseBody, jsonKeyValues) { let responseMap = new Map(); if (jsonKeyValues instanceof DataTable) { const readFeatureDataTable = jsonKeyValues.rows(); for (const [key, value] of readFeatureDataTable) { if (readFeatureDataTable.hasOwnProperty(key)) { console.log(() => `Key is: ${key} Value is: ${value}`); responseMap.set(key, value); } } } else { responseMap = jsonKeyValues; } invalidJsonPathWithRegularExpressionForMap(responseBody, responseMap); } export function invalidJsonPathWithRegularExpressionForMap(responseBody, datableFieldsInMap) { for (const [actualPath, expectedValue] of datableFieldsInMap) { const queryResult = jsonPath.query(responseBody, "$.." + actualPath); console.log(() => `Json query result is: ${queryResult}`); if (queryResult.length === 0) { expect(queryResult, `${queryResult} equals to ${expectedValue} OR ${actualPath} is present in response`) .to.be.empty; console.log(() => `${actualPath} is not present in response`); } else if (queryResult.toString().includes(",")) { const queryResultValue = queryResult.toString().split(","); assert(queryResultValue.indexOf(expectedValue) === -1, `==> Actual Json Response: ${queryResult} ==> Below expected json response is not included either json path or value: Json path: ${actualPath} OR Value: ${expectedValue}`); } else { assert(queryResult.some((x) => x.toString() !== expectedValue.toString()), `==> Actual Json Response: ${queryResult} ==> Below expected json response is not included either json path or value: Json path: ${actualPath} OR Value: ${expectedValue}`); } } } export function validJsonPathWithRegularExpressionForMap(responseBody, responsemap) { for (const [actualPath, expectedValue] of responsemap) { const queryResult = jsonPath.query(responseBody, "$.." + actualPath); console.log(() => `Json query result is: ${queryResult}`); console.log(() => `Json expected value is json query result is: ${expectedValue}`); if (expectedValue.includes(";")) { expectedValue.split(";").forEach((value) => { assert(queryResult.some((val) => val === value), `==> Actual Json Response: ${queryResult} ==> Below expected json response is not included either json path or value: Json path: ${actualPath} OR Value: ${expectedValue}`); }); } else { assert(queryResult.some((x) => x.toString() === expectedValue.toString()), `==> Actual Json Response: ${queryResult} ==> Below expected json response is not included either json path or value: Json path: ${actualPath} OR Value: ${expectedValue}`); } } } export function replaceJsonPathFollowedByParentIndex(responseBody, parentnode, value) { let parentNode = ""; const paths = jsonPath.paths(responseBody, "$.." + parentnode); for (const index in paths) { if (paths.hasOwnProperty(index)) { const jsonpath = jsonPath.stringify(paths[index]); const patharray = jsonpath.split("."); const jsonvalue = jsonPath.value(responseBody, jsonpath.replace("$", "$.")); console.log(() => `Parent node Json value is: ${jsonvalue}`); if (jsonvalue != null && jsonvalue.toString() === value.toString()) { parentNode = patharray[patharray.length - 2]; console.log(() => `Parent node is: ${parentNode}`); return parentNode; } } } return parentNode; } /** * This method is used for validating JSON response followed by parent node index after making http request * Where sending input as JSON Response and DataTable or Map * Where DataTable is 2D array , sending row and columns as key value pair * Constructing Map out of DataTable which is defined in feature file * Constructed Map will contain json node(key) and value pair * Json response should contain json key and values that are passed from feature file (DataTable) * validateJsonMapFollowedByParentIndex: It validates map values with JSON response followed by parent node * followed by responseBody JSON path and parent index. * @param {string} parentNode - parent node * @param {object} responseBody - response body * @param {DataTable | Map<string, any> } responseFields - json response key(path parameter) and value as Map or DataTable * @returns {void} */ export function validateJsonResponseFollowedByParentIndex(parentNode, responseBody, jsonKeyValues /*reading column values from feature file */) { let responseMap = new Map(); if (jsonKeyValues instanceof DataTable) { const readFeatureDataTable = jsonKeyValues.rows(); for (const [key, value] of readFeatureDataTable) { console.log(() => `Key is: ${key} and Value is: ${value}`); responseMap.set(key, value); } } else { responseMap = jsonKeyValues; } validateJsonKeyValuePairFollowedByParentIndex(parentNode, responseBody, responseMap); } export function validateJsonKeyValuePairFollowedByParentIndex(parentKey, responseBody, responseMap /*reading column values from feature file */ ) { let replacewithParentNode = ""; let replaceNode = ""; for (let [actualPath, expectedValue] of responseMap) { if (actualPath.includes(parentKey)) { const actualparentNode = actualPath.split("."); replaceNode = actualparentNode[actualparentNode.length - 2]; replacewithParentNode = replaceJsonPathFollowedByParentIndex(responseBody, parentKey, expectedValue); } console.log(() => `Replace node: ${replaceNode}`); actualPath = actualPath.replace(replaceNode, replacewithParentNode); console.log(() => `Actual path: ${actualPath}`); const queryResult = jsonPath.query(responseBody, "$.." + actualPath); if (expectedValue.toString().includes(";")) { expectedValue.toString().split(";").forEach((value) => { console.log(() => `Query result value is: ${value}`); assert.isTrue(queryResult.some((res) => res === value), `${actualPath} or ${value} is not present in response`); console.log(() => `${actualPath} or ${value} is present in response`); }); } else { assert.strictEqual(queryResult.toString(), expectedValue.toString(), `${actualPath} or ${expectedValue} is not present in response`); console.log(() => `${actualPath} or ${expectedValue} is present in response`); } } } /** * This method is used to read the JSON file from the path specified * @param {string} jsonfilepath - JSON file path */ export function readJson(jsonfilepath) { return __awaiter(this, void 0, void 0, function* () { return loadJsonFile(jsonfilepath); }); } /** * This method is used to read the JSON file from the specified path to create a JSON object * @param {string} jsonfilepath - JSON file path */ export function readJsonToObject(jsonfilepath) { return __awaiter(this, void 0, void 0, function* () { const jsonFileAsObject = yield readJson(jsonfilepath); return jsonFileAsObject; }); } /** * This method is used to read the JSON file from the specified path to create a JSON string * @param {string} jsonfilepath - JSON file path */ export function readJsonToString(jsonfilepath) { return __awaiter(this, void 0, void 0, function* () { const jsonFileAsObject = yield readJson(jsonfilepath); const jsonstr = JSON.stringify(jsonFileAsObject); return jsonstr; }); } /** * This method is used to find the parent node by name * @param {object} jsonData - JSON data * @param {string} nodeName - name of the node */ export function findNodeByName(jsonData, nodeName) { return __awaiter(this, void 0, void 0, function* () { const paths = jsonPath.paths(jsonData, "$.." + nodeName); let nodes = []; for (const index in paths) { if (paths.hasOwnProperty(index)) { nodes.push(jsonPath.stringify(paths[index])); } } return nodes; }); } /** * This method is used to POST request parameters from the DataTable that are specified in the input json file * These request parameters will replace for input json file object. * Where input json file just template for request parameters * @param {string} jsonFilepath - JSON file path * @param {DataTable | Map<string, any>} jsonKeyValuePair - response fields */ export function sendRequestBodyAsFile(jsonFilepath, jsonKeyValuePair /*reading column values from feature file or map */ ) { return __awaiter(this, void 0, void 0, function* () { let responseMap = new Map(); if (jsonKeyValuePair instanceof DataTable) { const readFeatureDataTable = jsonKeyValuePair.rows(); for (const [key, value] of readFeatureDataTable) { console.log(() => `Key is: ${key} and Value is ${value}`); responseMap.set(key, value); } } else { responseMap = jsonKeyValuePair; } return sendRequestParametersFromMap(jsonFilepath, responseMap); }); } /** * This method is used to POST request parameters from the DataTable that are specified in the input json file * These request parameters will replace for input json file object. * Where input json file just template for request parameters * Note: Need to provide exact json path to replace node values * @param {string} jsonFilepath - JSON file path * @param {DataTable} responseFields - response fields */ export function sendRequestBodyAsJsonFile(jsonFilepath, jsonKeyValuePair /*reading column values from feature file */ ) { return __awaiter(this, void 0, void 0, function* () { let responsemap = new Map(); if (jsonKeyValuePair instanceof DataTable) { const readFeatureDataTable = jsonKeyValuePair.rows(); for (const [key, value] of readFeatureDataTable) { console.log(() => `Key is: ${key} and Value is ${value}`); responsemap.set(key, value); } } else { responsemap = jsonKeyValuePair; } return replaceExactJsonFileNodeValues(jsonFilepath, responsemap); }); } /** * This method is used to send request json key value pair from the DataTable as Map specified in the input json file * These request parameters will replace for input json file object. * Where input json file just template for request parameters * @param {string} jsonFilepath - JSON file path * @param {Map<string, any>} dataTableFieldsInMap - data table fields Map */ export function sendRequestParametersFromMap(jsonFilepath, dataTableFieldsInMap /*reading column values from feature file */ ) { return __awaiter(this, void 0, void 0, function* () { const jsonFileObject = yield readJsonToObject(jsonFilepath); for (const [key, expectedValue] of dataTableFieldsInMap) { jsonPath.apply(jsonFileObject, "$.." + key, (value) => { value = expectedValue; console.log(value); return value; }); } return JSON.stringify(jsonFileObject); }); } /** * This method is used to find the parent node value by node name * @param {object} jsonData - JSON data * @param {string} nodename - name of the node */ export function findNodeValue(jsonData, nodeName) { return __awaiter(this, void 0, void 0, function* () { const paths = jsonPath.paths(jsonData, "$.." + nodeName); const arrayOfNodeValues = []; for (const index in paths) { if (paths.hasOwnProperty(index)) { const pathExpression = jsonPath.stringify(paths[index]).replace("$.", "$.."); const nodeValues = jsonPath.query(jsonData, pathExpression); arrayOfNodeValues.push(...nodeValues); } } return arrayOfNodeValues; }); } /** * This method is used for validation of JSON response after making http request by giving JSON path * returns the table as a 2-D array, without the first row * where first row from datatable using it as column headers. * validJsonPathWithRegularExpressionForMap: It validates JSON response passed as key and value pair * after making service(REST) call, where key is JSON node(path) name and value is JSON node(path) * value with the responseBody JSON path. * @param {object} jsoneResponse - json response body as an object * @param {DataTable | Map<string, string>} jsonResponseKeyValuePair - send json path and corrosponding value as in the form of DataTable or Map * @returns {void} */ export function validateJsonResponse(jsonResponse, jsonResponseKeyValuePair /*reading column values from feature file */ ) { if (jsonResponseKeyValuePair instanceof DataTable) { const readFeatureDataTable = jsonResponseKeyValuePair.rows(); const responseMap = new Map(); for (let [key, value] of readFeatureDataTable) { responseMap.set(key, value); } console.log(() => `readFeatureDataTable : ${JSON.stringify(responseMap)}`); validJsonPathWithRegularExpressionForMap(jsonResponse, responseMap); } else { validJsonPathWithRegularExpressionForMap(jsonResponse, jsonResponseKeyValuePair); } } /** * This method is used to validate json response objects * These input json response file converting as json object. * Where internally calls deepCompareOfJsonObjects method to validate two json objects * @param {string} jsonResponseFilepath - JSON Response as Input File * @param {object} actualJsonResponseObject - Getting json response after making REST call * @returns {Promise<void>} - returns nothing */ export function validateJsonResponseFile(jsonResponseFilepath, actualJsonResponseObject, jsonkeyValue) { return __awaiter(this, void 0, void 0, function* () { const jsonfileobject = yield readJsonToObject(jsonResponseFilepath); if (jsonkeyValue !== null && jsonkeyValue instanceof Map) { const expectedResponseObject = yield createJsonResponseObjectFromMap(jsonResponseFilepath, jsonkeyValue); deepCompareOfJsonObjects(expectedResponseObject, actualJsonResponseObject); } else if (jsonkeyValue !== null && jsonkeyValue instanceof DataTable) { const readFeatureDataTable = jsonkeyValue.rows(); const responseMap = new Map(); for (let [key, value] of readFeatureDataTable) { responseMap.set(key, value); } console.log(() => `readFeatureDataTable : ${JSON.stringify(responseMap)}`); const expectedResponseObject = yield createJsonResponseObjectFromMap(jsonResponseFilepath, responseMap); deepCompareOfJsonObjects(expectedResponseObject, actualJsonResponseObject); } else { deepCompareOfJsonObjects(jsonfileobject, actualJsonResponseObject); } }); } /** * This method is used to read response file in json format as well parameters as Map * Where values of Map needs to be replaced in the input json file object * Where input response json file just template for request parameters * @param {string} jsonResponseFilepath - JSON file path * @param {Map<string, string>} dataTableFieldsInMap - data table fields Map * @returns {object} - Returns Json object */ export function createJsonResponseObjectFromMap(jsonResponseFilepath, dataTableFieldsInMap /*reading column values from feature file */ ) { return __awaiter(this, void 0, void 0, function* () { const jsonfileObject = yield readJsonToObject(jsonResponseFilepath); for (const [key, expectedValue] of dataTableFieldsInMap) { jsonPath.apply(jsonfileObject, "$.." + key, (value) => { value = expectedValue; console.log(() => `${value}`); return value; }); } return jsonfileObject; }); } /** * This method is used to compare of two json objects by every Key * Which gives exactly Key that fails for particular test * Where passing two json objects as inputs * @param {object} expectedJsonObject - First json object * @param {object} actualJsonObject - second json object that needs to be compared * @returns {void} - Returns Json object */ export function deepCompareOfJsonObjects(actualJsonObject, expectedJsonObject) { if (Object.keys(actualJsonObject).length === Object.keys(expectedJsonObject).length) { iterateNestedObjects(actualJsonObject, expectedJsonObject); iterateNestedObjects(expectedJsonObject, actualJsonObject); } else { //Validating when expectedJsonObject keys length is less or greater than actualJsonObject keys expect(JSON.stringify(actualJsonObject)).to.be.equals(JSON.stringify(expectedJsonObject)); } } const iterateNestedObjects = (expectedobj, actualobj) => { Object.keys(expectedobj).forEach((key) => { // @ts-ignore if (typeof expectedobj[key] === "object" && expectedobj[key] !== null) { // @ts-ignore iterateNestedObjects(expectedobj[key], actualobj[key]); } else { // @ts-ignore console.log(() => `expected json parameter value: ${expectedobj[key]} actual json parameter value: ${actualobj[key]}`); // @ts-ignore expect(expectedobj[key]).to.be.equals(actualobj[key], `Json parameter value not found for Key ${key}`); } }); }; function convertObjectToString(value) { return (value === null) ? "" : value.toString(); } /** * This method is used to replace required json path parameter values on the json request or response object * Note: Need to provide exact json path to replace node values * Where input json file just template for json path parameters * @param {object} jsonObject - JSON request/response object * @param {Map<string, string>} dataTableFieldsInMap - dataTable fields reading from the feature file * and sending it as Map */ export function replaceExactJsonNodeValues(jsonObject, dataTableFieldsInMap) { return __awaiter(this, void 0, void 0, function* () { for (const [key, expectedValue] of dataTableFieldsInMap) { jsonPath.apply(jsonObject, "$." + key, (value) => { value = expectedValue; console.log(value); return value; }); } return JSON.stringify(jsonObject); }); } export function replaceExactJsonFileNodeValues(jsonFilePath, dataTableFieldsInMap) { return __awaiter(this, void 0, void 0, function* () { const jsonFileAsObject = yield readJson(jsonFilePath); for (const [key, expectedValue] of dataTableFieldsInMap) { jsonPath.apply(jsonFileAsObject, "$." + key, (value) => { value = expectedValue; console.log(value); return value; }); } return JSON.stringify(jsonFileAsObject); }); } /** * This method is used to exclude Json Path parameters(keys) from request body or response body * Note: Need to provide exact json path to replace node values * @param {string | object} requestBody - request body sending it as string or JSON object * @param {DataTable | Map<string, string> | string[]} dataTableFieldsInMap - dataTable fields reading from the feature file * and sending it as Map or string array * Note: |key1| {exclude_path_parameter}| * key1 is path parameter value is {exclude_path_parameter} in the dataTable or Map */ export function excludeJsonPathParameters(requestBody, jsonKeyValues) { return __awaiter(this, void 0, void 0, function* () { const jsonObject = (typeof requestBody === "string") ? JSON.parse(requestBody) : requestBody; if (jsonKeyValues instanceof DataTable) { const readData = jsonKeyValues.rows(); for (const [key, value] of readData) { if (value.toString().includes("{exclude_path_parameter}")) { unset(jsonObject, key); } } } else if (jsonKeyValues instanceof Map) { for (const [key, value] of jsonKeyValues) { if (value.toString().includes("{exclude_path_parameter}")) { unset(jsonObject, key); } } } else { for (const key of jsonKeyValues) { unset(jsonObject, key); } } return JSON.stringify(jsonObject); }); } /** * This method is used to validate response body whether json or not * Note: Other than json means, response could be xml, normal string or html etc * @param {any} responseBody - response body after making http(Rest) call * @returns {boolean} - Returns true if it is valid json otherwise false */ export function isValidJson(responseBody) { return __awaiter(this, void 0, void 0, function* () { try { JSON.parse(responseBody); return true; } catch (error) { return false; } }); }