Skip to content

Commit b1222df

Browse files
authored
Merge pull request #15 from test-results-reporter/14-read-files-using-wildcards
feat: read multiple files
2 parents 664f058 + 780fc96 commit b1222df

File tree

11 files changed

+421
-21
lines changed

11 files changed

+421
-21
lines changed

package-lock.json

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

package.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "test-results-parser",
3-
"version": "0.0.11",
3+
"version": "0.1.0",
44
"description": "Parse test results from JUnit, TestNG, xUnit and many more",
55
"main": "src/index.js",
66
"types": "./src/index.d.ts",
@@ -29,7 +29,9 @@
2929
},
3030
"homepage": "https://github.com/test-results-reporter/parser#readme",
3131
"dependencies": {
32-
"fast-xml-parser": "^3.20.0"
32+
"fast-xml-parser": "^3.20.0",
33+
"globrex": "^0.1.2",
34+
"totalist": "^3.0.0"
3335
},
3436
"devDependencies": {
3537
"mocha": "^10.0.0"

src/helpers/helper.js

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,35 @@
11
const fs = require('fs');
22
const path = require('path');
33
const parser = require('fast-xml-parser');
4+
const { totalist } = require('totalist/sync');
5+
const globrex = require('globrex');
46

57
function getJsonFromXMLFile(filePath) {
68
const cwd = process.cwd();
79
const xml = fs.readFileSync(path.join(cwd, filePath)).toString();
810
return parser.parse(xml, { arrayMode: true, ignoreAttributes: false, parseAttributeValue: true });
911
}
1012

13+
/**
14+
* @param {string} file_path
15+
*/
16+
function getMatchingFilePaths(file_path) {
17+
if (file_path.includes('*')) {
18+
const file_paths = [];
19+
const result = globrex(file_path);
20+
const dir_name = path.dirname(file_path.substring(0, file_path.indexOf('*') + 1));
21+
totalist(dir_name, (name) => {
22+
const current_file_path = `${dir_name}/${name}`;
23+
if (result.regex.test(current_file_path)) {
24+
file_paths.push(current_file_path);
25+
}
26+
});
27+
return file_paths;
28+
}
29+
return [file_path];
30+
}
31+
1132
module.exports = {
12-
getJsonFromXMLFile
33+
getJsonFromXMLFile,
34+
getMatchingFilePaths
1335
}

src/parsers/cucumber.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,9 +92,9 @@ function preprocess(rawjson) {
9292
return formattedResult;
9393
}
9494

95-
function parse(options) {
95+
function parse(file) {
9696
const cwd = process.cwd();
97-
const json = require(path.join(cwd, options.files[0]));
97+
const json = require(path.join(cwd, file));
9898
return getTestResult(json);
9999
}
100100

src/parsers/index.js

Lines changed: 48 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,65 @@ const junit = require('./junit');
33
const xunit = require('./xunit');
44
const mocha = require('./mocha');
55
const cucumber = require('./cucumber');
6+
const TestResult = require('../models/TestResult');
7+
const { getMatchingFilePaths } = require('../helpers/helper');
68

7-
function parse(options) {
8-
switch (options.type) {
9+
/**
10+
* @param {import('../models/TestResult')[]} results
11+
*/
12+
function merge(results) {
13+
const main_result = new TestResult();
14+
for (let i = 0; i < results.length; i++) {
15+
const current_result = results[i];
16+
if (!main_result.name) {
17+
main_result.name = current_result.name;
18+
}
19+
main_result.total = main_result.total + current_result.total;
20+
main_result.passed = main_result.passed + current_result.passed;
21+
main_result.failed = main_result.failed + current_result.failed;
22+
main_result.errors = main_result.errors + current_result.errors;
23+
main_result.skipped = main_result.skipped + current_result.skipped;
24+
main_result.retried = main_result.retried + current_result.retried;
25+
main_result.duration = main_result.duration + current_result.duration;
26+
main_result.suites = main_result.suites.concat(...current_result.suites);
27+
}
28+
main_result.status = results.every(_result => _result.status === 'PASS') ? 'PASS' : 'FAIL';
29+
return main_result;
30+
}
31+
32+
function getParser(type) {
33+
switch (type) {
934
case 'testng':
10-
return testng.parse(options);
35+
return testng;
1136
case 'junit':
12-
return junit.parse(options);
37+
return junit;
1338
case 'xunit':
14-
return xunit.parse(options);
39+
return xunit;
1540
case 'mocha':
16-
return mocha.parse(options);
41+
return mocha;
1742
case 'cucumber':
18-
return cucumber.parse(options);
43+
return cucumber;
1944
default:
2045
throw `UnSupported Result Type - ${options.type}`;
2146
}
2247
}
2348

49+
/**
50+
* @param {import('../index').ParseOptions} options
51+
*/
52+
function parse(options) {
53+
const parser = getParser(options.type);
54+
const results = [];
55+
for (let i = 0; i < options.files.length; i++) {
56+
const matched_files = getMatchingFilePaths(options.files[i]);
57+
for (let j = 0; j < matched_files.length; j++) {
58+
const file = matched_files[j];
59+
results.push(parser.parse(file));
60+
}
61+
}
62+
return merge(results);
63+
}
64+
2465
module.exports = {
2566
parse
2667
}

src/parsers/junit.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,8 @@ function getTestResult(json) {
6060
return result;
6161
}
6262

63-
function parse(options) {
64-
const json = getJsonFromXMLFile(options.files[0]);
63+
function parse(file) {
64+
const json = getJsonFromXMLFile(file);
6565
return getTestResult(json);
6666
}
6767

src/parsers/mocha.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,9 +108,9 @@ function formatMochaJsonReport(rawjson) {
108108
return formattedJson;
109109
}
110110

111-
function parse(options) {
111+
function parse(file) {
112112
const cwd = process.cwd();
113-
const json = require(path.join(cwd, options.files[0]));
113+
const json = require(path.join(cwd, file));
114114
return getTestResult(json);
115115
}
116116

src/parsers/testng.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,9 @@ function getTestSuite(rawSuite) {
7272
return suite;
7373
}
7474

75-
function parse(options) {
75+
function parse(file) {
7676
// TODO - loop through files
77-
const json = getJsonFromXMLFile(options.files[0]);
77+
const json = getJsonFromXMLFile(file);
7878
const result = new TestResult();
7979
const results = json['testng-results'][0];
8080
result.failed = results['@_failed'];

src/parsers/xunit.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,8 @@ function getTestResult(json) {
6868
return result;
6969
}
7070

71-
function parse(options) {
72-
const json = getJsonFromXMLFile(options.files[0]);
71+
function parse(file) {
72+
const json = getJsonFromXMLFile(file);
7373
return getTestResult(json);
7474
}
7575

tests/parser.junit.spec.js

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,4 +210,76 @@ describe('Parser - JUnit', () => {
210210
});
211211
});
212212

213+
it('multiple single suite files', () => {
214+
const result = parse({ type: 'junit', files: ['tests/data/junit/single-suite.xml', 'tests/data/junit/single-suite.xml'] });
215+
assert.deepEqual(result, {
216+
id: '',
217+
name: 'result name',
218+
total: 2,
219+
passed: 0,
220+
failed: 2,
221+
errors: 0,
222+
skipped: 0,
223+
retried: 0,
224+
duration: 20000,
225+
status: 'FAIL',
226+
suites: [
227+
{
228+
id: '',
229+
name: 'suite name',
230+
total: 1,
231+
passed: 0,
232+
failed: 1,
233+
errors: 0,
234+
skipped: 0,
235+
duration: 10000,
236+
status: 'FAIL',
237+
cases: [
238+
{
239+
duration: 10000,
240+
errors: 0,
241+
failed: 0,
242+
failure: "PROGRAM.cbl:2 Use a program name that matches the source file name",
243+
id: "",
244+
name: "Use a program name that matches the source file name",
245+
passed: 0,
246+
skipped: 0,
247+
stack_trace: "",
248+
status: "FAIL",
249+
steps: [],
250+
total: 0
251+
}
252+
]
253+
},
254+
{
255+
id: '',
256+
name: 'suite name',
257+
total: 1,
258+
passed: 0,
259+
failed: 1,
260+
errors: 0,
261+
skipped: 0,
262+
duration: 10000,
263+
status: 'FAIL',
264+
cases: [
265+
{
266+
duration: 10000,
267+
errors: 0,
268+
failed: 0,
269+
failure: "PROGRAM.cbl:2 Use a program name that matches the source file name",
270+
id: "",
271+
name: "Use a program name that matches the source file name",
272+
passed: 0,
273+
skipped: 0,
274+
stack_trace: "",
275+
status: "FAIL",
276+
steps: [],
277+
total: 0
278+
}
279+
]
280+
}
281+
]
282+
});
283+
});
284+
213285
});

0 commit comments

Comments
 (0)