From bb91b9229e0b0709e40918185e7ea036b4d6f241 Mon Sep 17 00:00:00 2001 From: Anudeep Date: Tue, 16 Apr 2024 09:46:53 +0530 Subject: [PATCH] junit and cucumber stack trace (#61) --- package-lock.json | 4 ++-- package.json | 2 +- src/helpers/helper.js | 6 ++++-- src/parsers/cucumber.js | 34 ++++++++++++++++++++++++++-------- src/parsers/junit.js | 7 +++++++ src/parsers/testng.js | 2 +- tests/parser.cucumber.spec.js | 8 ++++---- tests/parser.junit.spec.js | 4 ++++ 8 files changed, 49 insertions(+), 18 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4640450..7cb31e3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "test-results-parser", - "version": "0.1.12", + "version": "0.1.13", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "test-results-parser", - "version": "0.1.12", + "version": "0.1.13", "license": "MIT", "dependencies": { "fast-xml-parser": "^4.3.2", diff --git a/package.json b/package.json index 0ba0605..4b6b595 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "test-results-parser", - "version": "0.1.12", + "version": "0.1.13", "description": "Parse test results from JUnit, TestNG, xUnit, cucumber and many more", "main": "src/index.js", "types": "./src/index.d.ts", diff --git a/src/helpers/helper.js b/src/helpers/helper.js index d0d399d..2cc805f 100644 --- a/src/helpers/helper.js +++ b/src/helpers/helper.js @@ -17,6 +17,8 @@ const FORCED_ARRAY_KEYS = [ "testsuites.testsuite", "testsuites.testsuite.testcase", "testsuites.testsuite.testcase.failure", + "testsuites.testsuite.testcase.error", + "testsuites.testsuite.testcase.system-err", "testsuites.testsuite.testcase.properties.property", "assemblies", "assemblies.assembly", @@ -43,7 +45,7 @@ const configured_parser = new XMLParser({ isArray: (name, jpath, isLeafNode, isAttribute) => { if( FORCED_ARRAY_KEYS.indexOf(jpath) !== -1) { return true; - } + } // handle nunit deep hierarchy else if (jpath.startsWith("test-results") || jpath.startsWith("test-run")) { let parts = jpath.split("."); @@ -74,7 +76,7 @@ function getJsonFromXMLFile(filePath) { } /** - * @param {string} file_path + * @param {string} file_path */ function getMatchingFilePaths(file_path) { if (file_path.includes('*')) { diff --git a/src/parsers/cucumber.js b/src/parsers/cucumber.js index 049a6be..a6325c9 100644 --- a/src/parsers/cucumber.js +++ b/src/parsers/cucumber.js @@ -11,7 +11,7 @@ function getTestCase(rawCase) { setMetaData(rawCase, test_case); if (rawCase.state && rawCase.state === "failed") { test_case.status = 'FAIL'; - test_case.setFailure(rawCase.errorStack); + set_error_and_stack_trace(test_case, rawCase.errorStack); } else { test_case.status = 'PASS'; @@ -20,9 +20,27 @@ function getTestCase(rawCase) { } /** - * - * @param {import('./cucumber.result').CucumberElement} element - * @param {TestCase | TestSuite} test_element + * @param {TestCase} test_case + * @param {string?} message + */ +function set_error_and_stack_trace(test_case, message) { + if (message) { + const stack_trace_start_index = message.indexOf(' at '); + if (stack_trace_start_index) { + const failure = message.slice(0, stack_trace_start_index); + const stack_trace = message.slice(stack_trace_start_index); + test_case.setFailure(failure); + test_case.stack_trace = stack_trace; + } else { + test_case.setFailure(message); + } + } +} + +/** + * + * @param {import('./cucumber.result').CucumberElement} element + * @param {TestCase | TestSuite} test_element */ function setMetaData(element, test_element) { const meta_tags = []; @@ -62,7 +80,7 @@ function getTestSuite(rawSuite) { } /** - * @param {import("./cucumber.result").CucumberJsonResult} json + * @param {import("./cucumber.result").CucumberJsonResult} json */ function getTestResult(json) { const result = new TestResult(); @@ -88,7 +106,7 @@ function getTestResult(json) { /** * Function to format the raw json report - * @param {import("./cucumber.result").CucumberJsonResult} json + * @param {import("./cucumber.result").CucumberJsonResult} json * @returns formatted json object */ function preprocess(json) { @@ -113,7 +131,7 @@ function preprocess(json) { formattedResult.stats.suites = formattedResult.suites.length; for (const statsType of ["tests", "passes", "failures", "errors", "duration"]) { - formattedResult.stats[statsType] = formattedResult.suites.map(testSuite => testSuite[statsType]).reduce((total, currVal) => total + currVal, 0) || 0; + formattedResult.stats[statsType] = formattedResult.suites.map(testSuite => testSuite[statsType]).reduce((total, currVal) => total + currVal, 0) || 0; } return formattedResult; } @@ -121,7 +139,7 @@ function preprocess(json) { function parse(file) { const json = require(resolveFilePath(file)); return getTestResult(json); -} +} module.exports = { parse diff --git a/src/parsers/junit.js b/src/parsers/junit.js index 994df3a..8059d8c 100644 --- a/src/parsers/junit.js +++ b/src/parsers/junit.js @@ -15,6 +15,13 @@ function getTestCase(rawCase, suite_meta) { if (rawCase.failure && rawCase.failure.length > 0) { test_case.status = 'FAIL'; test_case.setFailure(rawCase.failure[0]["@_message"]); + // wdio junit reporter + if (!test_case.failure && rawCase.error && rawCase.error.length > 0) { + test_case.setFailure(rawCase.error[0]["@_message"]); + } + if (rawCase['system-err'] && rawCase['system-err'].length > 0) { + test_case.stack_trace = rawCase['system-err'][0]; + } } else { test_case.status = 'PASS'; } diff --git a/src/parsers/testng.js b/src/parsers/testng.js index ee4efb3..fc91439 100644 --- a/src/parsers/testng.js +++ b/src/parsers/testng.js @@ -163,7 +163,7 @@ function parse(file) { const suite = suites[0]; result.name = suite['@_name']; result.duration = suite['@_duration-ms']; - console.log("No suites with tests found"); + console.warn("No suites with tests found"); } result.status = result.total === result.passed ? 'PASS' : 'FAIL'; return result; diff --git a/tests/parser.cucumber.spec.js b/tests/parser.cucumber.spec.js index b0c41c8..25b5e7b 100644 --- a/tests/parser.cucumber.spec.js +++ b/tests/parser.cucumber.spec.js @@ -3,9 +3,9 @@ const assert = require('assert'); const path = require('path'); describe('Parser - Cucumber Json', () => { - + const testDataPath = "tests/data/cucumber" - + it('single suite with single test', () => { const result = parse({ type: 'cucumber', files: [`${testDataPath}/single-suite-single-test.json`] }); assert.deepEqual(result, { @@ -102,12 +102,12 @@ describe('Parser - Cucumber Json', () => { duration: 2.56, errors: 0, failed: 0, - failure: "AssertionError [ERR_ASSERTION]: 13 == 14\n + expected - actual\n\n -13\n +14\n\n at CustomWorld. (D:\\workspace\\nodejs\\cc-tests\\features\\support\\steps.js:18:12)", + failure: "AssertionError [ERR_ASSERTION]: 13 == 14\n + expected - actual\n\n -13\n +14\n\n", id: "", name: "Addition of two numbers", passed: 0, skipped: 0, - stack_trace: "", + stack_trace: " at CustomWorld. (D:\\workspace\\nodejs\\cc-tests\\features\\support\\steps.js:18:12)", status: "FAIL", meta_data: new Map(), steps: [], diff --git a/tests/parser.junit.spec.js b/tests/parser.junit.spec.js index c9c9e1d..efe8f6a 100644 --- a/tests/parser.junit.spec.js +++ b/tests/parser.junit.spec.js @@ -655,6 +655,10 @@ describe('Parser - JUnit', () => { assert.equal(result.errors, 0); assert.equal(result.duration, 91024); assert.equal(result.status, 'FAIL'); + assert.equal(result.suites[0].cases[1].failure, `Error: element ("//button/span[text()='Continue']") still displayed after 20000ms`); + assert.match(result.suites[0].cases[1].stack_trace, /at file/); + assert.match(result.suites[0].cases[1].stack_trace, /async Element.wrapCommandFn/); + assert.match(result.suites[0].cases[1].stack_trace, /middlewares.js:18:32/); }); }); \ No newline at end of file