Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: meta-data at test suite level #41

Merged
merged 1 commit into from
Nov 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "test-results-parser",
"version": "0.1.5",
"version": "0.1.6",
"description": "Parse test results from JUnit, TestNG, xUnit, cucumber and many more",
"main": "src/index.js",
"types": "./src/index.d.ts",
Expand All @@ -22,7 +22,8 @@
"result",
"automation",
"mocha",
"cucumber"
"cucumber",
"nUnit"
],
"author": "Anudeep <[email protected]>",
"license": "MIT",
Expand Down
1 change: 1 addition & 0 deletions src/models/TestSuite.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ declare class TestSuite {
skipped: number;
duration: number;
status: string;
meta_data: Map<string,string>;
cases: TestCase[];
}

Expand Down
1 change: 1 addition & 0 deletions src/models/TestSuite.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ class TestSuite {
this.skipped = 0;
this.duration = 0;
this.status = 'NA';
this.meta_data = new Map();
this.cases = [];
}

Expand Down
50 changes: 32 additions & 18 deletions src/parsers/cucumber.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,7 @@ function getTestCase(rawCase) {
const test_case = new TestCase();
test_case.name = rawCase["name"];
test_case.duration = rawCase["duration"];
if (rawCase.tags && rawCase.tags.length > 0) {
const tagsArray = rawCase.tags;
let tags = [];
let rawTags = [];
for (let i = 0; i < tagsArray.length; i++) {
let rawTagName = tagsArray[i]["name"];
let tag = rawTagName.substring(1).split("=");
let tagName = tag[0];
test_case.meta_data.set(tagName, tag[1] ?? "")
tags.push(tagName);
rawTags.push(rawTagName);
}
test_case.meta_data.set("tags", tags.join(","));
test_case.meta_data.set("tagsRaw", rawTags.join(","));
}
setMetaData(rawCase, test_case);
if (rawCase.state && rawCase.state === "failed") {
test_case.status = 'FAIL';
test_case.setFailure(rawCase.errorStack);
Expand All @@ -33,6 +19,30 @@ function getTestCase(rawCase) {
return test_case;
}

/**
*
* @param {import('./cucumber.result').CucumberElement} element
* @param {TestCase | TestSuite} test_element
*/
function setMetaData(element, test_element) {
const meta_tags = [];
const meta_raw_tags = [];
const tags = element.tags;
if (tags && tags.length > 0) {
for (const tag of tags) {
const [name, value] = tag["name"].substring(1).split("=");
if (value) {
test_element.meta_data.set(name, value);
} else {
meta_tags.push(name);
meta_raw_tags.push(tag["name"]);
}
}
test_element.meta_data.set("tags", meta_tags.join(","));
test_element.meta_data.set("tagsRaw", meta_raw_tags.join(","));
}
}

function getTestSuite(rawSuite) {
const suite = new TestSuite();
suite.name = rawSuite["name"];
Expand All @@ -41,6 +51,7 @@ function getTestSuite(rawSuite) {
suite.failed = rawSuite["failures"];
suite.duration = rawSuite["duration"];
suite.status = suite.total === suite.passed ? 'PASS' : 'FAIL';
setMetaData(rawSuite, suite);
const raw_test_cases = rawSuite.elements;
if (raw_test_cases) {
for (let i = 0; i < raw_test_cases.length; i++) {
Expand All @@ -50,6 +61,9 @@ function getTestSuite(rawSuite) {
return suite;
}

/**
* @param {import("./cucumber.result").CucumberJsonResult} json
*/
function getTestResult(json) {
const result = new TestResult();
const { stats, suites } = preprocess(json);
Expand All @@ -74,13 +88,13 @@ function getTestResult(json) {

/**
* Function to format the raw json report
* @param {*} rawjson
* @param {import("./cucumber.result").CucumberJsonResult} json
* @returns formatted json object
*/
function preprocess(rawjson) {
function preprocess(json) {
const formattedResult = { stats: {}, suites: [] };

rawjson.forEach(testSuite => {
json.forEach(testSuite => {
testSuite.elements.forEach(testCase => {
testCase.state = testCase.steps.every(step => step.result.status === "passed") ? "passed" : "failed";
testCase.duration = testCase.steps.map(step => step.result.duration).reduce((total, currVal) => total + currVal, 0) / 1000000;
Expand Down
55 changes: 55 additions & 0 deletions src/parsers/cucumber.result.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
export type CucumberResult = {
status: string;
duration: number;
};

export type CucumberMatch = {
location: string;
};

export type CucumberArgument = {
arguments: any[];
keyword: string;
line: number;
name: string;
match: CucumberMatch;
result: CucumberResult;
};

export type CucumberStep = {
arguments: any[];
keyword: string;
line: number;
name: string;
match: CucumberMatch;
result: CucumberResult;
};

export type CucumberTag = {
name: string;
line: number;
};

export type CucumberElement = {
description: string;
id: string;
keyword: string;
line: number;
name: string;
steps: CucumberStep[];
tags: CucumberTag[];
type: string;
};

export type CucumberFeature = {
description: string;
elements: CucumberElement[];
id: string;
line: number;
keyword: string;
name: string;
tags: CucumberTag[];
uri: string;
};

export type CucumberJsonResult = CucumberFeature[];
41 changes: 23 additions & 18 deletions src/parsers/junit.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,11 @@ const TestResult = require('../models/TestResult');
const TestSuite = require('../models/TestSuite');
const TestCase = require('../models/TestCase');

function getTestCase(rawCase, suiteProperties) {
function getTestCase(rawCase) {
const test_case = new TestCase();
test_case.name = rawCase["@_name"];
test_case.duration = rawCase["@_time"] * 1000;
for (let [key,value] of suiteProperties) {
test_case.meta_data.set(key, value);
}
if (rawCase.properties && rawCase.properties.property.length > 0) {
const raw_properties = rawCase.properties.property;
for (let i = 0; i < raw_properties.length; i++) {
test_case.meta_data.set(raw_properties[i]["@_name"], raw_properties[i]["@_value"]);
}
}
setMetaData(rawCase.properties, test_case);
if (rawCase.failure && rawCase.failure.length > 0) {
test_case.status = 'FAIL';
test_case.setFailure(rawCase.failure[0]["@_message"]);
Expand All @@ -43,22 +35,30 @@ function getTestSuite(rawSuite) {
suite.passed = suite.total - suite.failed - suite.errors;
suite.duration = rawSuite["@_time"] * 1000;
suite.status = suite.total === suite.passed ? 'PASS' : 'FAIL';
const properties = new Map();
if (rawSuite.properties && rawSuite.properties.property.length > 0) {
const raw_properties = rawSuite.properties.property;
for (let i = 0; i < raw_properties.length; i++) {
properties.set(raw_properties[i]["@_name"], raw_properties[i]["@_value"])
}
}
setMetaData(rawSuite.properties, suite);
const raw_test_cases = rawSuite.testcase;
if (raw_test_cases) {
for (let i = 0; i < raw_test_cases.length; i++) {
suite.cases.push(getTestCase(raw_test_cases[i], properties));
suite.cases.push(getTestCase(raw_test_cases[i]));
}
}
return suite;
}

/**
*
* @param {import('./junit.result').JUnitProperties} properties
* @param {TestCase | TestSuite} test_element
*/
function setMetaData(properties, test_element) {
if (properties && properties.property.length > 0) {
const raw_properties = properties.property;
for (const raw_property of raw_properties) {
test_element.meta_data.set(raw_property["@_name"], raw_property["@_value"]);
}
}
}

/**
* @param {TestResult} result
*/
Expand Down Expand Up @@ -89,6 +89,11 @@ function setAggregateResults(result) {
}
}

/**
*
* @param {import('./junit.result').JUnitResultJson} json
* @returns
*/
function getTestResult(json) {
const result = new TestResult();
const rawResult = json["testsuites"][0];
Expand Down
51 changes: 51 additions & 0 deletions src/parsers/junit.result.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
export type JUnitProperty = {
'@_name': string;
'@_value': string;
}

export type JUnitProperties = {
property: JUnitProperty[];
}

export type JUnitFailure = {
'#text': string;
'@_message': string;
'@_type': string;
}

export type JUnitTestCase = {
properties?: JUnitProperties;
failure?: JUnitFailure[];
'@_id': string;
'@_name': string;
'@_time': number;
}

export type TestSuite = {
properties?: JUnitProperties;
testcase: JUnitTestCase[];
'@_id': string;
'@_name': string;
'@_tests': number;
'@_failures': number;
'@_time': number;
}

export type JUnitResult = {
testsuite: JUnitTestSuite[];
'@_id': string;
'@_name': string;
'@_tests': number;
'@_failures': number;
'@_errors': string;
'@_time': number;
}

export type JUnitResultJson = {
'?xml': {
'@_version': number;
'@_encoding': string;
};
testsuites: JUnitResult[];
}

Loading
Loading