UNPKG

@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
"use strict"; 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')); } }, };