UNPKG

newman-reporter-digyrunner

Version:

A custom Newman reporter that pushes test execution data to Digy4

440 lines (369 loc) 16.4 kB
const { v4: uuidv4 } = require("uuid"); const dotenv = require('dotenv'); dotenv.config(); module.exports = function (newman, options, collectionRunOptions) { let testResultsSummary; let envObject; //console.log('=== DEBUG INFO ==='); //console.log('options:', JSON.stringify(options, null, 2)); //console.log('collectionRunOptions keys:', Object.keys(collectionRunOptions)); //console.log('collectionRunOptions.environment:', JSON.stringify(collectionRunOptions.environment, null, 2)); if (collectionRunOptions.collection) { console.log('Collection has environment?', !!collectionRunOptions.collection.environment); } const safe = (v, d='') => (v == null ? d : String(v).trim()); function _getResultSummaryId() { return envObject.projectName + "#" + envObject.teamName + "#" + envObject.buildId; } function _getTimeDifferenceInMs() { return testResultsSummary.endTime - testResultsSummary.startTime; } function _getTotalCount() { return testResultsSummary.passedCount + testResultsSummary.failedCount + testResultsSummary.skippedCount; } async function sendResult(test) { const response = await validateUser() const sessionId = uuidv4() if (!response.valid) { return false } const resultPayload = { id: _getResultSummaryId(), teamName: envObject.teamName, hubUrl: envObject.hubUrl, hubId: envObject.hubId, testResult: test.testResult, projectName: envObject.projectName, buildId: envObject.buildId, startTime: test.startTime, endTime: test.endTime, durationMs: _getTimeDifferenceInMs(), testCaseName: test.testCaseName, testResultMessage: test.testResultMessage, resultSummaryStartTime: testResultsSummary.startTime, browserName: envObject.browserName, browserVersion: envObject.browserVersion, eventSessionIds: [], scriptErrors: "", capabilities: JSON.stringify(envObject), sessionId: sessionId, resultSummaryId: _getResultSummaryId(), deviceName: "N/A", deviceVersion: "N/A", moduleName: envObject.moduleName, tester: envObject.tester, ba: envObject.ba, developer: envObject.developer, suiteName: envObject.suiteName, environment: envObject.environment, testType: envObject.testType, cloudFarm: envObject.cloudFarm, framework: envObject.framework, apiRequestResponseLogs: [], tenantId: response.tenantId, lob: envObject.lob, application: envObject.application, release: envObject.release, pipelineId: envObject.pipelineId, requirementId: envObject.requirementId, tags: envObject.tags, commitId: envObject.commitId } //console.log('Result Payload:', JSON.stringify(resultPayload, null, 2)); const payload = { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(resultPayload) }; try { const response = await fetch(envObject.resultsUrl, payload) if (!response.ok) { const text = await response.text().catch(() => "no error message") console.log(`Failed to send: ${test.testCaseName}, Response: ${response.status}, StatusText: ${response.statusText}, Error: ${text}`) return false } console.log(`Successful sending: ${test.testCaseName}`) return true }catch(error) { console.error(`Error sending ${test.testCaseName}: ${error.message}`) return false } } async function sendResultsSummary(status) { console.log('=== SENDING RESULTS SUMMARY ==='); console.log('Status:', status); const response = await validateUser() console.log(response) if (!response.valid) { console.error("Error in validating user/project") return; } const resultSummaryPayload = { _id: envObject._id, buildId: envObject.buildId, hubId: envObject.hubId, hubUrl: envObject.hubUrl, resultsSummaryId: _getResultSummaryId(), projectName: envObject.projectName, teamName: envObject.teamName, suiteName: envObject.suiteName, appVersion: envObject.appVersion, browserName: envObject.browserName, browserVersion: envObject.browserVersion, deviceName: "N/A", deviceVersion: "N/A", passedCount: testResultsSummary.passedCount, skippedCount: testResultsSummary.skippedCount, failedCount: testResultsSummary.failedCount, errorCount: 0, totalCount: testResultsSummary.totalCount, startTime: testResultsSummary.startTime, endTime: testResultsSummary.endTime, durationMs: _getTimeDifferenceInMs(), status: status, framework: envObject.framework, environment: envObject.environment, moduleName: envObject.moduleName, ba: envObject.ba, developer: envObject.developer, testType: envObject.testType, cloudFarm: envObject.cloudFarm, tenantId: envObject.tenantId, lob: envObject.lob, application: envObject.application, release: envObject.release, pipelineId: envObject.pipelineId, requirementId: envObject.requirementId, tags: envObject.tags, commitId: envObject.commitId, tenantId: response.tenantId }; //console.log('Result Summary Payload:', JSON.stringify(resultSummaryPayload, null, 2)); const payload = { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(resultSummaryPayload) }; try { const url = envObject.resultsSummaryUrl; //console.log('Target URL:', url); if (!url) { console.error('❌ No results summary URL configured in RESULTS_SUMMARY_URL environment variable'); return false; } //console.log('Making HTTP request...'); const response = await fetch(url, payload) const data = await response.json() //console.log('Response: ', JSON.stringify(data, null, 2)) return true } catch (error) { console.error("❌ Error sending results:", error.message); console.error("❌ Full error:", error); return false; } } async function validateUser() { try { const headers = { "Content-Type": "application/json" } const request = { client_id: envObject.clientId, client_secret: envObject.clientSecret }; const projectPlanUrl = envObject.projectPlanUrl const projectName = envObject.projectName const response = await fetch(projectPlanUrl, { method: 'POST', headers: headers, body: JSON.stringify(request) }); console.log(`Digy4: Project validation endpoint status code : ` + response.status); const responseJson = await response.json() if (!responseJson.body) { console.error('Digy4: User is NOT authenticated/authorized. Reporting to Digy Dashboard will be skipped.'); return { valid: false }; } if (responseJson.error.toString() === "true") { console.error('Digy4: User is NOT authorized. Reporting to Digy Dashboard will be skipped.'); return { valid: false }; } if (responseJson.body.projects.some(project => project.name.toLowerCase() === projectName.toLowerCase())) { if (responseJson.body.testcase_plan_count <= responseJson.body.testcase_current_count) { console.error('Digy4: Execution slots are not available or subscription ended. Reporting to Digy Dashboard will be skipped.'); return { valid: false }; } return { valid: true, tenantId: responseJson.body.organization_id }; } console.error('Digy4: Project name does not exist. Reporting to Digy Dashboard will be skipped.'); return { valid: false }; }catch(error) { console.error("Error occured in validateUser: ", error) return { valid: false } } } function envSummary() { return { _id: uuidv4(), hubId: safe(process.env.DIGY4_HUB_ID, 'localhost'), hubUrl: safe(process.env.DIGY4_HUB_URL, 'http://localhost'), projectName: safe(process.env.DIGY4_APPLICATION_NAME, safe(process.env.PROJECT_NAME)), teamName: safe(process.env.DIGY4_TEAM_NAME, 'NA'), buildId: safe(process.env.DIGY4_BUILD_ID, 'AUTO-' + uuidv4()), suiteName: safe(process.env.DIGY4_SUITE_NAME), appVersion: safe(process.env.DIGY4_APP_VERSION, 'NA'), browserName: safe(process.env.DIGY4_BROWSER_NAME, 'NA'), browserVersion: safe(process.env.DIGY4_BROWSER_VERSION, 'NA'), framework: safe(process.env.DIGY4_FRAMEWORK, 'Newman/Postman'), environment: safe(process.env.DIGY4_ENVIRONMENT, 'TEST'), moduleName: safe(process.env.DIGY4_MODULE_NAME, 'NA'), tester: safe(process.env.DIGY4_TESTER, 'NA'), ba: safe(process.env.DIGY4_BA, 'NA'), developer: safe(process.env.DIGY4_DEVELOPER, 'NA'), testType: safe(process.env.DIGY4_TEST_TYPE, 'API'), cloudFarm: safe(process.env.DIGY4_CLOUD_FARM, 'LOCAL'), clientId: safe(process.env.DIGY4_CLIENT_ID), clientSecret: safe(process.env.DIGY4_CLIENT_SECRET), application: safe(process.env.DIGY4_APPLICATION), release: safe(process.env.DIGY4_RELEASE), resultsSummaryUrl: safe(process.env.DIGY4_RESULTS_SUMMARY_URL), resultsUrl: safe(process.env.DIGY4_RESULTS_URL), projectPlanUrl: safe(process.env.DIGY4_PROJECT_PLAN_URL), }; } newman.on('start', async function (err, args) { //console.log('In start') console.log('Digy4 Newman Reporter: Starting...'); envObject = envSummary() //console.log(JSON.stringify(envObject)) testResultsSummary = { totalCount: 0, passedCount: 0, skippedCount: 0, failedCount: 0, errorCount: 0, startTime: Date.now(), endTime: null, }; }); newman.on('beforeDone', async function(err, o) { //console.log(`Execution: ${JSON.stringify(o, null, 2)}`); const sessionId = uuidv4() if (err) { console.error('Error in beforeDone:', err); return; } if (!o.summary || !o.summary.run || !o.summary.run.executions) { console.error('Missing required summary data'); return; } const executions = o.summary.run.executions; testResultsSummary.startTime = o.summary.run.timings?.started || testResultsSummary.startTime; testResultsSummary.endTime = o.summary.run.timings?.completed || Date.now(); const allTestCases = executions.map(execution => { //console.log(`Execution: ${JSON.stringify(execution, null, 2)}`); const executionId = execution.cursor?.ref || 'unknown'; const { assertions = [], request = {}, response = {} } = execution; const method = request.method || 'UNKNOWN'; const url = Array.isArray(request.url?.path) ? request.url.path.join("/") : 'unknown-url'; if (assertions.length > 0) { return assertions.map(assertion => { let testResult; let resultMessage; if (assertion.skipped) { testResult = "SKIPPED"; resultMessage = "Execution Skipped"; testResultsSummary.skippedCount++; } else if (assertion?.error !== undefined) { testResult = "FAIL"; const errorInfo = { ...assertion.error, method: method, url: url, executionId: executionId }; resultMessage = JSON.stringify(errorInfo, null, 2); testResultsSummary.failedCount++; } else { testResult = "PASS"; resultMessage = "Executed Successfully"; testResultsSummary.passedCount++; } return { testCaseName: execution.item.name + ':' + assertion.assertion, testResult, testResultMessage: resultMessage, startTime: testResultsSummary.startTime, endTime: testResultsSummary.endTime, }; }); } else { // Handle executions with no assertions testResultsSummary.skippedCount++; return [{ testResult: "NO_ASSERTIONS", resultMessage: "No assertions found for this request", teamName: envObject.teamName, method, url, executionId }]; } }).flat(); § const counts = o.summary.run.stats.assertions; testResultsSummary.totalCount = counts.total; testResultsSummary.failedCount = counts.failed; testResultsSummary.skippedCount = counts.pending; testResultsSummary.passedCount = counts.total - (counts.failed + counts.pending); console.log('Test Results Summary:', testResultsSummary); console.log(`Total Tests: ${testResultsSummary.totalCount}, Passed: ${testResultsSummary.passedCount}, Failed: ${testResultsSummary.failedCount}, Skipped: ${testResultsSummary.skippedCount}`); //console.log(`All Testcases: ${JSON.stringify(allTestCases, null, 2)}`) // Batch req // const promises = allTestCases.map((test) => { // return sendResult(test, sessionId) // }) let promises = []; for (const test of allTestCases){ //const response = await sendResult(test) promises.push(sendResult(test)) //console.log(response) } try { await Promise.all(promises); console.log('Digy4 Newman Reporter: Sending results summary...'); const success = await sendResultsSummary('Completed') if (success) { console.log('Digy4 Newman Reporter success sending result....') }else{ console.error('Digy4 Newman Reporter failed sending result....') } }catch(error) { console.error('Digy4 Newman Reporter failed sending result....') console.error("Error: ", error) } }); newman.on('done', async function(err, o) { if (err) { console.error('Newman execution error:', err); return; } //console.log('In done') }); }