@dbouckaert/zephyr-scale-reporter
Version:
ZH, or zephyr helpers is a Node JS framework that implements test suites with Zephyr scale for Jira. It uses a soft-assert function to absorb failing assertions and translate them to a true/false value.
462 lines (461 loc) • 16.6 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.softAssert = exports.createNewTestrun = exports.updateTestResult = exports.getAllTestcases = exports.init = void 0;
/* eslint-disable @typescript-eslint/no-unused-expressions */
/* eslint-disable no-console */
const supertest_1 = __importDefault(require("supertest"));
const chai_1 = require("chai");
const variables_interface_1 = require("./interfaces/variables.interface");
/**
* This function checks the value of all the keys in an object, if the value is **undefined** an error is logged.
* @param {object} obj the object to check
* @param {string} msg the name of the function calling this (used for error logging)
*/
const validateObjectValues = (obj, msg) => {
const paramsUndefined = Object.values(obj).includes(undefined);
if (paramsUndefined) {
console.log(obj);
throw new Error(`ERROR: [${msg}] one, or more, parameter(s) value is UNDEFINED`);
}
};
/**
* This function makes a HTTP call to get an array with all the projects
* @param zephyrConfig
* @returns
*/
const getProjects = async (zephyrConfig) => (0, supertest_1.default)(zephyrConfig.zephyrURL)
.get('/rest/tests/1.0/project')
.auth(zephyrConfig.zephyrUser, zephyrConfig.zephyrPass)
.expect(200);
/**
* This function loops over the array returned from getProjects and looks for a certain name, then returns the ID.
* @param {ZephyrConfig} zephyrConfig
*/
const getProjectsId = async (zephyrConfig) => {
const projectsResponse = await getProjects(zephyrConfig);
return projectsResponse.body.find((project) => project.name === zephyrConfig.zephyrProjectName)?.id;
};
/**
* This function makes a HTTP call to lookup a specific jira user
* @param zephyrConfig
* @returns
*/
const getJiraUser = async (zephyrConfig) => (0, supertest_1.default)(zephyrConfig.zephyrURL)
.get(`/rest/api/2/user?username=${zephyrConfig.jiraUsername}`)
.auth(zephyrConfig.zephyrUser, zephyrConfig.zephyrPass)
.expect(200);
/**
* This function returns the Key from any jira user object.
* @param {ZephyrConfig} zephyrConfig
*/
const getJiraUserId = async (zephyrConfig) => {
if (process.env.jiraUser === 'Jenkins') {
return zephyrConfig.defaultJiraId;
}
else {
const jiraUsersResponse = await getJiraUser(zephyrConfig);
return jiraUsersResponse.body.key;
}
};
const getEnvironments = async (zephyrConfig, projectId) => (0, supertest_1.default)(zephyrConfig.zephyrURL)
.get(`/rest/tests/1.0/project/${projectId}/environments`)
.set('jira-project-id', projectId)
.auth(zephyrConfig.zephyrUser, zephyrConfig.zephyrPass);
const getEnvironmentId = async (zephyrConfig, projectId) => {
const environmentResponse = await getEnvironments(zephyrConfig, projectId);
return environmentResponse.body.find((env) => env.name === zephyrConfig.environment)?.id;
};
const variables = variables_interface_1.defaultVariables;
/**
* This function sets a range of variables the Zephyr module uses
* @param {ZephyrConfig} zephyrConfig
*/
async function init(zephyrConfig) {
validateObjectValues(zephyrConfig, 'init');
const projectId = await getProjectsId(zephyrConfig);
variables.url = zephyrConfig.zephyrURL;
variables.username = zephyrConfig.zephyrUser;
variables.folderName = zephyrConfig.zephyrFolderName;
variables.password = zephyrConfig.zephyrPass;
variables.environment = zephyrConfig.environment;
variables.projectName = zephyrConfig.zephyrProjectName;
variables.projectId = projectId;
variables.envId = await getEnvironmentId(zephyrConfig, projectId);
variables.jirauser = zephyrConfig.jiraUsername;
variables.defaultJiraId = zephyrConfig.defaultJiraId;
variables.jiraUserId = await getJiraUserId(zephyrConfig);
}
exports.init = init;
/**
* This function will get all testcases for a certain project and add them to variables.testCasesArray
* @returns {void}
*/
const getAllTestcases = async () => {
await (0, supertest_1.default)(variables.url)
.get(`/rest/tests/1.0/project/${variables.projectId}/testcases`)
.auth(variables.username, variables.password)
.expect(200)
.then((res) => {
variables.testCasesArray = res.body.testCases;
});
};
exports.getAllTestcases = getAllTestcases;
const filterTestcase = async (testcaseFolderName, testcaseName) => {
const filteredTestcase = variables.testCasesArray.find((testcase) => testcaseFolderName === testcase.folder?.name &&
testcaseName === testcase.name);
if (filteredTestcase === undefined) {
console.log(`ERROR: [filterTestcase] No testcase found with name: ${testcaseName}, in folder: ${testcaseFolderName}`);
process.exit(1);
}
return filteredTestcase;
};
/**
* Creating the test result 'entry' in the test run context.
* @param {*} testcaseId
* @returns
*/
const createTestResult = async (testcaseId) => {
let testrun;
const testrunPayload = {
testCaseId: testcaseId,
assignedTo: variables.jiraUserId,
environmentId: variables.envId,
};
const jsonTestRunPayload = JSON.stringify(testrunPayload);
await (0, supertest_1.default)(variables.url)
.post('/rest/tests/1.0/testresult')
.set('content-Length', Buffer.byteLength(jsonTestRunPayload).toString())
.set('content-Type', 'application/json;charset=UTF-8')
.set('jira-project-id', variables.projectId)
.auth(variables.username, variables.password)
.send(jsonTestRunPayload)
.then((res) => {
(0, chai_1.expect)(res.statusCode).eq(201);
testrun = res;
});
return testrun.body.id;
};
/**
* Updating the test result 'entry' with the passed/failed status, based on the 'test run id'
* @param {object} params testrunId, status (passed or failed)
*/
const updateTestResult = async (testResultDetails) => {
const { testRunId, testStatus } = testResultDetails;
const now = new Date();
const jsonDate = now.toJSON();
let status;
validateObjectValues(testResultDetails, 'updateTestResult');
switch (testStatus) {
case true:
status = 10166; // todo hardcoded: need method for these
break;
case false:
status = 10167;
console.log('> WARNING: test restult status = "failed"');
break;
default:
status = 10167;
console.log('> WARNING: test restult status = "default(failed)"');
break;
}
const payload = [
{
id: testRunId,
testResultStatusId: status,
userKey: variables.jiraUserId,
executionDate: jsonDate,
actualStartDate: jsonDate,
},
];
const jsonPayload = JSON.stringify(payload);
await (0, supertest_1.default)(variables.url)
.put('/rest/tests/1.0/testresult')
.auth(variables.username, variables.password)
.set('content-Length', Buffer.byteLength(jsonPayload).toString())
.set('content-Type', 'application/json;charset=UTF-8')
.set('jira-project-id', variables.projectId)
.send(jsonPayload)
.then((res) => {
(0, chai_1.expect)(res.statusCode).eq(200);
});
};
exports.updateTestResult = updateTestResult;
/**
* This function creates a new test run and resturns the testrun ID
* @param {string} testcaseFolderName name of the folder the testcase is in
* @param {string} testcaseName name of the testcase
* @returns {number} testrun ID
*/
const createNewTestrun = async (testcaseFolderName, testcaseName) => {
// searching for the correct test case (using the test name and folder name).
const filteredTestcase = await filterTestcase(testcaseFolderName, testcaseName);
// create test run & collect testrun ID.
const testrunId = await createTestResult(filteredTestcase.id);
return testrunId;
};
exports.createNewTestrun = createNewTestrun;
/**
* Assert and capture errors.
* While a normal failing assert would stop the code from running, the soft-assert can continue
* And throws errors only if .assertAll() is called.
*/
exports.softAssert = {
failedAsserts: [],
equals(value, condition) {
if (value === undefined || condition === undefined) {
console.log('ERROR [equals] please provide the value and condition arguments');
process.exit(1);
}
let assertPassed = false;
try {
(0, chai_1.expect)(value).equal(condition);
assertPassed = true;
}
catch (error) {
const e = error;
this.failedAsserts.push(e);
}
return assertPassed;
},
notEquals(value, condition) {
if (value === undefined || condition === undefined) {
console.log('ERROR [notEquals] please provide the value and condition arguments');
process.exit(1);
}
let assertPassed = false;
try {
(0, chai_1.expect)(value).not.equal(condition);
assertPassed = true;
}
catch (error) {
const e = error;
this.failedAsserts.push(e);
}
return assertPassed;
},
deepEquals(value, condition) {
if (!value || !condition) {
console.log('ERROR [deepEquals] please provide the value and condition arguments');
process.exit(1);
}
let assertPassed = false;
try {
(0, chai_1.expect)(value).deep.equal(condition);
assertPassed = true;
}
catch (error) {
const e = error;
this.failedAsserts.push(e);
}
return assertPassed;
},
includes(sample, pattern) {
if (sample === undefined || pattern === undefined) {
console.log('ERROR [includes] please provide the sample and pattern arguments');
process.exit(1);
}
let assertPassed = false;
if (Array.isArray(sample) === true && Array.isArray(pattern) === true) {
console.log('sample is object or array');
try {
(0, chai_1.expect)(sample).include.members(pattern);
assertPassed = true;
}
catch (error) {
const e = error;
this.failedAsserts.push(e);
}
}
else {
try {
(0, chai_1.expect)(sample).deep.include(pattern);
assertPassed = true;
}
catch (error) {
const e = error;
this.failedAsserts.push(e);
}
}
return assertPassed;
},
matches(sample, pattern) {
if (sample === undefined || pattern === undefined) {
console.log('ERROR [matches] please provide the sample and pattern arguments');
process.exit(1);
}
let assertPassed = false;
if (Array.isArray(sample) === true && Array.isArray(pattern) === true) {
console.log('ERROR [matches] Arrays are not supported');
}
else {
try {
(0, chai_1.expect)(sample).match(pattern);
assertPassed = true;
}
catch (error) {
const e = error;
this.failedAsserts.push(e);
}
}
return assertPassed;
},
notIncludes(sample, pattern) {
if (sample === undefined || pattern === undefined) {
console.log('ERROR [notIncludes] please provide the sample and pattern arguments');
process.exit(1);
}
let assertPassed = false;
if (Array.isArray(sample) === true && Array.isArray(pattern) === true) {
console.log('sample is object or array');
try {
(0, chai_1.expect)(sample).not.include.members(pattern);
assertPassed = true;
}
catch (error) {
const e = error;
this.failedAsserts.push(e);
}
}
else {
try {
(0, chai_1.expect)(sample).not.deep.include(pattern);
assertPassed = true;
}
catch (error) {
const e = error;
this.failedAsserts.push(e);
}
}
return assertPassed;
},
isUndefined(value) {
let assertPassed = false;
try {
(0, chai_1.expect)(value).equal(undefined);
assertPassed = true;
}
catch (error) {
const e = error;
this.failedAsserts.push(e);
}
return assertPassed;
},
isNull(value) {
let assertPassed = false;
try {
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
(0, chai_1.expect)(value).to.be.null;
assertPassed = true;
}
catch (error) {
const e = error;
this.failedAsserts.push(e);
}
return assertPassed;
},
/**
* @param {object} params object & array
* @returns true or false
*/
objectHasAllKeys(obj, arrayWithKeys) {
if (!obj || !arrayWithKeys) {
console.log('ERROR [objectHasAllKeys] please provide the sample and pattern arguments');
process.exit(1);
}
if (Array.isArray(arrayWithKeys) !== true) {
console.log('please pass an array as the arguments for "arrayWithKeys"');
process.exit(1);
}
if (typeof obj !== 'object' || Array.isArray(obj) === true) {
console.log('ERROR: [objectHasAllKeys] argument type of argument "obj" is not an object');
process.exit(1);
}
let assertPassed;
try {
(0, chai_1.expect)(obj).to.have.all.keys(arrayWithKeys);
assertPassed = true;
}
catch (error) {
const e = error;
this.failedAsserts.push(e);
assertPassed = false;
}
return assertPassed;
},
isEmptyObject(obj) {
let assertPassed = false;
if (!obj || typeof obj !== 'object' || Array.isArray(obj) === true) {
console.log('WARNING [isEmptyObject] "obj" argument is not an object!');
}
try {
(0, chai_1.expect)(Object.keys(obj)).lengthOf(0);
assertPassed = true;
}
catch (error) {
const e = error;
this.failedAsserts.push(e);
}
return assertPassed;
},
/**
* Usefull to check e.g. if a propterty in an object has a value
*/
hasLength(value) {
let assertPassed = false;
if (!value) {
console.log('ERROR [hasLength] please pass an argument');
process.exit(1);
}
if (typeof value === 'string' || typeof value === 'object') {
try {
(0, chai_1.expect)(value).not.be.empty;
assertPassed = true;
}
catch (error) {
const e = error;
this.failedAsserts.push(e);
}
}
if (typeof value === 'number') {
try {
(0, chai_1.expect)(value).not.be.null;
}
catch (error) {
const e = error;
this.failedAsserts.push(e);
assertPassed = false;
}
}
return assertPassed;
},
isOneOf(arr, value) {
let assertPassed = false;
if (!value) {
console.log('ERROR [isOneOf] please pass an argument');
process.exit(1);
}
try {
(0, chai_1.expect)(value).to.be.oneOf(arr);
assertPassed = true;
}
catch (error) {
const e = error;
this.failedAsserts.push(e);
}
return assertPassed;
},
/**
* Use this function at the end of a test to check if any of the soft-asserts failed.
* Thow an assert.fail if any errors were captured.
*/
assertAll: async function assertAll() {
if (this.failedAsserts.length > 0) {
const copyOfFailedAsserts = [...this.failedAsserts];
this.failedAsserts.length = 0;
chai_1.assert.fail(copyOfFailedAsserts.join(', \n'));
}
},
};