rest-assured-ts
Version:
Test framework for automating rest api & JS & typescript!
520 lines (515 loc) • 24 kB
JavaScript
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;
}
});
}