test-results-parser
Version:
Parse test results from JUnit, TestNG, xUnit, cucumber and many more
175 lines (159 loc) • 5.23 kB
JavaScript
/*
* Parser for both Mocha Json report and Mochawesome json
*/
const { resolveFilePath } = require('../helpers/helper');
const TestResult = require('../models/TestResult');
const TestSuite = require('../models/TestSuite');
const TestCase = require('../models/TestCase');
function getTestCase(rawCase) {
const test_case = new TestCase();
test_case.name = rawCase["title"];
test_case.duration = rawCase["duration"];
setMetaData(test_case);
if (rawCase["state"] == "pending") {
test_case.status = 'SKIP';
}
else if (rawCase.state && rawCase.state === "failed") {
test_case.status = 'FAIL';
test_case.setFailure(rawCase.err["message"]);
}
else {
test_case.status = 'PASS';
}
return test_case;
}
function getTestSuite(rawSuite) {
flattenTestSuite(rawSuite);
const suite = new TestSuite();
suite.name = rawSuite["title"];
suite.total = rawSuite["tests"].length;
suite.passed = rawSuite["passes"].length;
suite.failed = rawSuite["failures"].length;
suite.duration = rawSuite["duration"];
suite.skipped = rawSuite["pending"].length;
suite.status = suite.total === (suite.passed + suite.skipped) ? 'PASS' : 'FAIL';
setMetaData(suite);
const raw_test_cases = rawSuite.tests;
if (raw_test_cases) {
for (let i = 0; i < raw_test_cases.length; i++) {
suite.cases.push(getTestCase(raw_test_cases[i]));
}
}
return suite;
}
/**
* Function to format the mocha raw json report
* @param {import("./mocha.result").MochaJsonData} raw_json
*/
function getTestResult(raw_json) {
const result = new TestResult();
const { stats, results } = formatMochaJsonReport(raw_json);
/** @type {import('./mocha.result').MochaResult} */
const formattedResult = results[0] || {};
const suites = formattedResult["suites"] || [];
result.name = formattedResult["title"] || "";
result.total = stats["tests"];
result.passed = stats["passes"];
result.failed = stats["failures"];
const errors = formattedResult["errors"];
if (errors) {
result.errors = errors;
}
const skipped = stats["pending"];
if (skipped) {
result.skipped = skipped;
}
result.duration = stats["duration"] || 0;
if (suites.length > 0) {
for (let i = 0; i < suites.length; i++) {
result.suites.push(getTestSuite(suites[i]));
}
}
result.status = (result.total - result.skipped) === result.passed ? 'PASS' : 'FAIL';
return result;
}
/**
* Function to format the mocha raw json report
* @param {import("./mocha.result").MochaJsonData} raw_json
* @returns formatted json object
*/
function formatMochaJsonReport(raw_json) {
if (raw_json.hasOwnProperty('meta')) {
return raw_json
}
const formattedJson = { stats: raw_json.stats, results: [] };
const suites = [];
raw_json.failures.forEach(test => test.state = "failed");
raw_json.passes.forEach(test => test.state = "passed");
raw_json.pending.forEach(test => {
test.state = "pending";
test.duration = 0;
});
if (raw_json.hasOwnProperty('skipped')) {
raw_json.skipped.forEach(test => {
test.state = "pending";
test.duration = 0;
});
raw_json.pending.concat(raw_json.skipped);
}
const rawTests = [...raw_json.passes, ...raw_json.failures, ...raw_json.pending];
const testSuites = [...new Set(rawTests.map(test => test.fullTitle.split(' ' + test.title)[0]))];
for (const testSuite of testSuites) {
const suite = {
title: testSuite,
tests: rawTests.filter(test => test.fullTitle.startsWith(testSuite))
}
suite.passes = suite.tests.filter(test => test.state === "passed");
suite.failures = suite.tests.filter(test => test.state === "failed");
suite.pending = suite.tests.filter(test => test.state === "pending");
suite.duration = suite.tests.map(test => test.duration).reduce((total, currVal) => total + currVal, 0);
suite.fullFile = suite.tests[0].file || "";
suites.push(suite);
}
formattedJson.results.push({ suites: suites });
return formattedJson;
}
/**
*
* @param {import("./mocha.result").MochaSuite} suite
*/
function flattenTestSuite(suite) {
if (!suite.suites) {
return;
}
for (const child_suite of suite.suites) {
flattenTestSuite(child_suite);
suite.tests = suite.tests.concat(child_suite.tests);
suite.passes = suite.passes.concat(child_suite.passes);
suite.failures = suite.failures.concat(child_suite.failures);
suite.pending = suite.pending.concat(child_suite.pending);
suite.skipped = suite.skipped.concat(child_suite.skipped);
suite.duration += child_suite.duration;
}
}
/**
*
* @param {TestCase | TestSuite} test_element
*/
function setMetaData(test_element) {
const regexp = /([\@\#][^\s]*)/gm; // match @tag or #tag
const matches = [...test_element.name.matchAll(regexp)];
if (matches.length > 0) {
for (const match of matches) {
const rawTag = match[0];
if (rawTag.includes("=")) {
const [name, value] = rawTag.substring(1).split("=");
test_element.metadata[name] = value;
} else {
test_element.tags.push(rawTag);
}
}
}
}
function parse(file) {
const json = require(resolveFilePath(file));
return getTestResult(json);
}
module.exports = {
parse
}