Skip to content

Commit 51887a2

Browse files
authored
feat: meta-data at test suite level (#41)
1 parent 67f113f commit 51887a2

17 files changed

+460
-249
lines changed

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "test-results-parser",
3-
"version": "0.1.5",
3+
"version": "0.1.6",
44
"description": "Parse test results from JUnit, TestNG, xUnit, cucumber and many more",
55
"main": "src/index.js",
66
"types": "./src/index.d.ts",
@@ -22,7 +22,8 @@
2222
"result",
2323
"automation",
2424
"mocha",
25-
"cucumber"
25+
"cucumber",
26+
"nUnit"
2627
],
2728
"author": "Anudeep <[email protected]>",
2829
"license": "MIT",

src/models/TestSuite.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ declare class TestSuite {
99
skipped: number;
1010
duration: number;
1111
status: string;
12+
meta_data: Map<string,string>;
1213
cases: TestCase[];
1314
}
1415

src/models/TestSuite.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ class TestSuite {
1010
this.skipped = 0;
1111
this.duration = 0;
1212
this.status = 'NA';
13+
this.meta_data = new Map();
1314
this.cases = [];
1415
}
1516

src/parsers/cucumber.js

Lines changed: 32 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,7 @@ function getTestCase(rawCase) {
88
const test_case = new TestCase();
99
test_case.name = rawCase["name"];
1010
test_case.duration = rawCase["duration"];
11-
if (rawCase.tags && rawCase.tags.length > 0) {
12-
const tagsArray = rawCase.tags;
13-
let tags = [];
14-
let rawTags = [];
15-
for (let i = 0; i < tagsArray.length; i++) {
16-
let rawTagName = tagsArray[i]["name"];
17-
let tag = rawTagName.substring(1).split("=");
18-
let tagName = tag[0];
19-
test_case.meta_data.set(tagName, tag[1] ?? "")
20-
tags.push(tagName);
21-
rawTags.push(rawTagName);
22-
}
23-
test_case.meta_data.set("tags", tags.join(","));
24-
test_case.meta_data.set("tagsRaw", rawTags.join(","));
25-
}
11+
setMetaData(rawCase, test_case);
2612
if (rawCase.state && rawCase.state === "failed") {
2713
test_case.status = 'FAIL';
2814
test_case.setFailure(rawCase.errorStack);
@@ -33,6 +19,30 @@ function getTestCase(rawCase) {
3319
return test_case;
3420
}
3521

22+
/**
23+
*
24+
* @param {import('./cucumber.result').CucumberElement} element
25+
* @param {TestCase | TestSuite} test_element
26+
*/
27+
function setMetaData(element, test_element) {
28+
const meta_tags = [];
29+
const meta_raw_tags = [];
30+
const tags = element.tags;
31+
if (tags && tags.length > 0) {
32+
for (const tag of tags) {
33+
const [name, value] = tag["name"].substring(1).split("=");
34+
if (value) {
35+
test_element.meta_data.set(name, value);
36+
} else {
37+
meta_tags.push(name);
38+
meta_raw_tags.push(tag["name"]);
39+
}
40+
}
41+
test_element.meta_data.set("tags", meta_tags.join(","));
42+
test_element.meta_data.set("tagsRaw", meta_raw_tags.join(","));
43+
}
44+
}
45+
3646
function getTestSuite(rawSuite) {
3747
const suite = new TestSuite();
3848
suite.name = rawSuite["name"];
@@ -41,6 +51,7 @@ function getTestSuite(rawSuite) {
4151
suite.failed = rawSuite["failures"];
4252
suite.duration = rawSuite["duration"];
4353
suite.status = suite.total === suite.passed ? 'PASS' : 'FAIL';
54+
setMetaData(rawSuite, suite);
4455
const raw_test_cases = rawSuite.elements;
4556
if (raw_test_cases) {
4657
for (let i = 0; i < raw_test_cases.length; i++) {
@@ -50,6 +61,9 @@ function getTestSuite(rawSuite) {
5061
return suite;
5162
}
5263

64+
/**
65+
* @param {import("./cucumber.result").CucumberJsonResult} json
66+
*/
5367
function getTestResult(json) {
5468
const result = new TestResult();
5569
const { stats, suites } = preprocess(json);
@@ -74,13 +88,13 @@ function getTestResult(json) {
7488

7589
/**
7690
* Function to format the raw json report
77-
* @param {*} rawjson
91+
* @param {import("./cucumber.result").CucumberJsonResult} json
7892
* @returns formatted json object
7993
*/
80-
function preprocess(rawjson) {
94+
function preprocess(json) {
8195
const formattedResult = { stats: {}, suites: [] };
8296

83-
rawjson.forEach(testSuite => {
97+
json.forEach(testSuite => {
8498
testSuite.elements.forEach(testCase => {
8599
testCase.state = testCase.steps.every(step => step.result.status === "passed") ? "passed" : "failed";
86100
testCase.duration = testCase.steps.map(step => step.result.duration).reduce((total, currVal) => total + currVal, 0) / 1000000;

src/parsers/cucumber.result.d.ts

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
export type CucumberResult = {
2+
status: string;
3+
duration: number;
4+
};
5+
6+
export type CucumberMatch = {
7+
location: string;
8+
};
9+
10+
export type CucumberArgument = {
11+
arguments: any[];
12+
keyword: string;
13+
line: number;
14+
name: string;
15+
match: CucumberMatch;
16+
result: CucumberResult;
17+
};
18+
19+
export type CucumberStep = {
20+
arguments: any[];
21+
keyword: string;
22+
line: number;
23+
name: string;
24+
match: CucumberMatch;
25+
result: CucumberResult;
26+
};
27+
28+
export type CucumberTag = {
29+
name: string;
30+
line: number;
31+
};
32+
33+
export type CucumberElement = {
34+
description: string;
35+
id: string;
36+
keyword: string;
37+
line: number;
38+
name: string;
39+
steps: CucumberStep[];
40+
tags: CucumberTag[];
41+
type: string;
42+
};
43+
44+
export type CucumberFeature = {
45+
description: string;
46+
elements: CucumberElement[];
47+
id: string;
48+
line: number;
49+
keyword: string;
50+
name: string;
51+
tags: CucumberTag[];
52+
uri: string;
53+
};
54+
55+
export type CucumberJsonResult = CucumberFeature[];

src/parsers/junit.js

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,11 @@ const TestResult = require('../models/TestResult');
44
const TestSuite = require('../models/TestSuite');
55
const TestCase = require('../models/TestCase');
66

7-
function getTestCase(rawCase, suiteProperties) {
7+
function getTestCase(rawCase) {
88
const test_case = new TestCase();
99
test_case.name = rawCase["@_name"];
1010
test_case.duration = rawCase["@_time"] * 1000;
11-
for (let [key,value] of suiteProperties) {
12-
test_case.meta_data.set(key, value);
13-
}
14-
if (rawCase.properties && rawCase.properties.property.length > 0) {
15-
const raw_properties = rawCase.properties.property;
16-
for (let i = 0; i < raw_properties.length; i++) {
17-
test_case.meta_data.set(raw_properties[i]["@_name"], raw_properties[i]["@_value"]);
18-
}
19-
}
11+
setMetaData(rawCase.properties, test_case);
2012
if (rawCase.failure && rawCase.failure.length > 0) {
2113
test_case.status = 'FAIL';
2214
test_case.setFailure(rawCase.failure[0]["@_message"]);
@@ -43,22 +35,30 @@ function getTestSuite(rawSuite) {
4335
suite.passed = suite.total - suite.failed - suite.errors;
4436
suite.duration = rawSuite["@_time"] * 1000;
4537
suite.status = suite.total === suite.passed ? 'PASS' : 'FAIL';
46-
const properties = new Map();
47-
if (rawSuite.properties && rawSuite.properties.property.length > 0) {
48-
const raw_properties = rawSuite.properties.property;
49-
for (let i = 0; i < raw_properties.length; i++) {
50-
properties.set(raw_properties[i]["@_name"], raw_properties[i]["@_value"])
51-
}
52-
}
38+
setMetaData(rawSuite.properties, suite);
5339
const raw_test_cases = rawSuite.testcase;
5440
if (raw_test_cases) {
5541
for (let i = 0; i < raw_test_cases.length; i++) {
56-
suite.cases.push(getTestCase(raw_test_cases[i], properties));
42+
suite.cases.push(getTestCase(raw_test_cases[i]));
5743
}
5844
}
5945
return suite;
6046
}
6147

48+
/**
49+
*
50+
* @param {import('./junit.result').JUnitProperties} properties
51+
* @param {TestCase | TestSuite} test_element
52+
*/
53+
function setMetaData(properties, test_element) {
54+
if (properties && properties.property.length > 0) {
55+
const raw_properties = properties.property;
56+
for (const raw_property of raw_properties) {
57+
test_element.meta_data.set(raw_property["@_name"], raw_property["@_value"]);
58+
}
59+
}
60+
}
61+
6262
/**
6363
* @param {TestResult} result
6464
*/
@@ -89,6 +89,11 @@ function setAggregateResults(result) {
8989
}
9090
}
9191

92+
/**
93+
*
94+
* @param {import('./junit.result').JUnitResultJson} json
95+
* @returns
96+
*/
9297
function getTestResult(json) {
9398
const result = new TestResult();
9499
const rawResult = json["testsuites"][0];

src/parsers/junit.result.d.ts

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
export type JUnitProperty = {
2+
'@_name': string;
3+
'@_value': string;
4+
}
5+
6+
export type JUnitProperties = {
7+
property: JUnitProperty[];
8+
}
9+
10+
export type JUnitFailure = {
11+
'#text': string;
12+
'@_message': string;
13+
'@_type': string;
14+
}
15+
16+
export type JUnitTestCase = {
17+
properties?: JUnitProperties;
18+
failure?: JUnitFailure[];
19+
'@_id': string;
20+
'@_name': string;
21+
'@_time': number;
22+
}
23+
24+
export type TestSuite = {
25+
properties?: JUnitProperties;
26+
testcase: JUnitTestCase[];
27+
'@_id': string;
28+
'@_name': string;
29+
'@_tests': number;
30+
'@_failures': number;
31+
'@_time': number;
32+
}
33+
34+
export type JUnitResult = {
35+
testsuite: JUnitTestSuite[];
36+
'@_id': string;
37+
'@_name': string;
38+
'@_tests': number;
39+
'@_failures': number;
40+
'@_errors': string;
41+
'@_time': number;
42+
}
43+
44+
export type JUnitResultJson = {
45+
'?xml': {
46+
'@_version': number;
47+
'@_encoding': string;
48+
};
49+
testsuites: JUnitResult[];
50+
}
51+

0 commit comments

Comments
 (0)