Skip to content

Commit

Permalink
updating code
Browse files Browse the repository at this point in the history
  • Loading branch information
agracio committed Nov 13, 2024
1 parent 273edff commit e0bf1b3
Show file tree
Hide file tree
Showing 14 changed files with 321 additions and 326 deletions.
13 changes: 2 additions & 11 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ jobs:
name: test-${{ matrix.os }}
strategy:
matrix:
os: [macos-13, macos-latest, ubuntu-latest]
os: [macos-latest, ubuntu-latest]
steps:
- name: Checkout code
uses: actions/checkout@v4
Expand All @@ -41,7 +41,7 @@ jobs:
cache-name: cache-node-modules
with:
path: node_modules
key: ${{ matrix.os }}${{ hashFiles('package-lock.json') }}
key: ${{ matrix.os }}-${{ hashFiles('package-lock.json') }}

- name: npm install
run: npm i
Expand All @@ -58,12 +58,3 @@ jobs:
# test-results.xml
# mochawesome.json
#
# - name: Test Report
# uses: phoenix-actions/test-reporting@v15
# if: success()
# with:
# name: test-results-${{ matrix.os }}-node-${{ matrix.node }}
# fail-on-error: true
# path: mochawesome.json # Path to test results
# reporter: mochawesome-json

16 changes: 10 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,13 @@ https://github.com/adamgruber/mochawesome
### Conversion process

- All test reports except JUnit are first converted to JUnit format using XSLT.
- Set `junit` option to `true` if you want to review JUnit conversion results.
- TRX files undergo additional processing to enhance JUnit output.
- Set `junit` option to `true` to get JUnit conversion results.

### All test types

- Converts <skipped> test messages to Mochawesome test context values.
- Converts <properties>, <system-out> and <system-err> to Mochawesome context values.
- Converts <failure> and <error> elements to Mochawesome error stack.
- Test suites are displayed in alphabetical order by `file` and `classname` attributes.
- Tests suites without any tests are excluded from Mochawesome and JUnit.
Expand All @@ -52,7 +54,7 @@ https://github.com/adamgruber/mochawesome
### JUnit

- Converts `testcase` **<properties>**, **<system-out>** and **<system-err>** elements to Mochawesome test context.
- Nested tests and test suites currently not supported.
- Nested test suites currently not supported.

### NUnit

Expand All @@ -74,8 +76,9 @@ https://github.com/adamgruber/mochawesome
- Converts `Output/ErrorInfo/StackTrace` to JUnit **<failure>** stack trace.
- Converts `Output/StdErr` to JUnit **<system-err>**.
- Converts `Output/StdOut` to JUnit **<system-out>**.
- Tests are ordered by name in Mochawesome.
- Does not resolve test suite times in JUnit output.
- Test suites are split into multiple **<testsuite>** elements by test classname.
- Tests are ordered by name.
- Test suit times are not 100% accurate - displayed as a sum() of all test times.

### Usage

Expand Down Expand Up @@ -112,14 +115,15 @@ convert(options).then(() => console.log(`Report created: ${options.reportDir}/${
- `testFile` - relative or absolute path to input test file.
- `testType` - type of test report, not case-sensitive.
- `reportDir` - will be created if path does not exist.
- `skippedAsPending` - Mocha always reports skipped tests as pending and this is default behaviour of converter. Set to `false` to display tests as skipped.
- `skippedAsPending` - Mocha always reports skipped tests as pending and this is default behaviour of converter.
Set to `false` to display tests as skipped.

#### Supported `testType` options.

| `testType` | File Type |
|:-----------|:------------------|
| JUnit | JUnit |
| NUnit | NUnit 3.0+ XML |
| NUnit | NUnit 3+ XML |
| xUnit | xUnit.net v2+ XML |
| TRX | Visual Studio TRX |

Expand Down
122 changes: 61 additions & 61 deletions src/junit.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,60 @@ let skippedTests = 0;
let failedTests = 0;
let suites = [];

function parseTrx(){
/**
* @param {ConverterOptions} options
* @param {any} json
* @returns {any}
*/
function parseTrx(options, json){

json.testsuites[0].testsuite[0].testcase = _.sortBy(json.testsuites[0].testsuite[0].testcase, ['classname' ,'name']);

let classnames = _.map(json.testsuites[0].testsuite[0].testcase, 'classname')
.filter((value, index, array) => array.indexOf(value) === index);

classnames = _.sortBy(classnames, [function(o) { return o; }]);

let time = _.sumBy(json.testsuites[0].testsuite, suite => _.sumBy(suite.testcase, function(testCase) { return Number(testCase.time); }));

json.testsuites[0].time = time;
json.testsuites[0].testsuite[0].time = time;

if(classnames.length > 1){

let testSuites = [];
classnames.forEach((classname) => {

let testcases = _.filter(json.testsuites[0].testsuite[0].testcase, { 'classname': classname});
let time = _.sumBy(testcases, function(testCase) { return Number(testCase.time); });
const failures = testcases.filter((testCase) => testCase.status === 'Failed').length;
const skipped = testcases.filter((testCase) => testCase.status === 'Skipped').length;

testSuites.push(
{
name: classname,
tests: `${testcases.length}`,
failures: `${failures}`,
skipped: `${skipped}`,
time: `${time}`,
testcase: testcases,
}
);
});

json.testsuites[0].testsuite = testSuites;
}

else{
json.testsuites[0].testsuite[0].time = time;
json.testsuites[0].testsuite[0].name = json.testsuites[0].testsuite[0].testcase[0].classname;
}

if(options.junit){
fs.writeFileSync(path.join(options.reportDir, options.junitReportFilename), xmlFormat(parser.toXml(json), {forceSelfClosingEmptyTag: true}), 'utf8');
}

return json;
}

/**
Expand Down Expand Up @@ -42,8 +94,11 @@ function parseXml(options, xml){
json.testsuites = [{testsuite: json.testsuite}];
delete json['testsuite'];
}
else{
throw `\nCould not find valid <testsuites> or <testsuite> element in converted ${options.testFile}`;
if(json && json.testsuites && json.testsuites.length && json.testsuites.length === 0){
console.log('No test suites found, skipping Mochawesome file creation.');
}
else if(!json || !json.testsuites || !json.testsuites.length){
throw `\nCould not find valid <testsuites> or <testsuite> root element in converted ${options.testFile}`;
}
}

Expand All @@ -52,17 +107,8 @@ function parseXml(options, xml){
fs.writeFileSync(path.join(options.reportDir, fileName), JSON.stringify(json, null, 2), 'utf8');
}

// if(options.saveIntermediateFiles){
// let jsonString = JSON.stringify(json, null, 2).replaceAll('&#xD;', '').replaceAll('&#xA;', '');
//
// json = JSON.parse(jsonString);
// let fileName = `${path.parse(options.testFile).name}-converted.xml`;
// fs.writeFileSync(path.join(options.reportDir, fileName), xmlFormat(parser.toXml(json), {forceSelfClosingEmptyTag: true}), 'utf8');
//
// }

if(!json.testsuites[0].testsuite){
throw `\nNo <testsuite> elements in <testsuites> element in converted ${options.testFile}`;
if(!json.testsuites[0].testsuite || !json.testsuites[0].testsuite.length || json.testsuites[0].testsuite.length ===0){
console.log('No test suites found, skipping Mochawesome file creation.');
}

// sort test suites
Expand All @@ -78,53 +124,7 @@ function parseXml(options, xml){
}

if(options.testType === 'trx' && json.testsuites[0].testsuite[0].testcase.length !== 0){

json.testsuites[0].testsuite[0].testcase = _.sortBy(json.testsuites[0].testsuite[0].testcase, ['name']);

let classnames = _.map(json.testsuites[0].testsuite[0].testcase, 'classname')
.filter((value, index, array) => array.indexOf(value) === index);

classnames = _.sortBy(classnames, [function(o) { return o; }]);

let time = _.sumBy(json.testsuites[0].testsuite, suite => _.sumBy(suite.testcase, function(testCase) { return Number(testCase.time); }));

json.testsuites[0].time = time;
json.testsuites[0].testsuite[0].time = time;

if(classnames.length > 1){

let testSuites = [];
classnames.forEach((classname) => {

let testcases = _.filter(json.testsuites[0].testsuite[0].testcase, { 'classname': classname});
let time = _.sumBy(testcases, function(testCase) { return Number(testCase.time); });
const failures = testcases.filter((testCase) => testCase.status === 'Failed').length;
const skipped = testcases.filter((testCase) => testCase.status === 'Skipped').length;

testSuites.push(
{
name: classname,
tests: `${testcases.length}`,
failures: `${failures}`,
skipped: `${skipped}`,
time: `${time}`,
testcase: testcases,
}
);
});

json.testsuites[0].testsuite = testSuites;
}

else{
json.testsuites[0].testsuite[0].time = time;
json.testsuites[0].testsuite[0].name = json.testsuites[0].testsuite[0].testcase[0].classname;

}

if(options.junit){
fs.writeFileSync(path.join(options.reportDir, options.junitReportFilename), xmlFormat(parser.toXml(json), {forceSelfClosingEmptyTag: true}), 'utf8');
}
json = parseTrx(options, json);
}

return json.testsuites[0];
Expand Down
4 changes: 2 additions & 2 deletions src/trx-junit.xslt
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="message" select="replace(vs:Output/vs:ErrorInfo/vs:Message, '&#xD;', '')"/>
<xsl:variable name="stacktrace" select="replace(vs:Output/vs:ErrorInfo/vs:StackTrace, '&#xD;', '')"/>
<xsl:variable name="message" select="replace(replace(vs:Output/vs:ErrorInfo/vs:Message, '&amp;', ''), '#xD;', '') "/>
<xsl:variable name="stacktrace" select="replace(replace(vs:Output/vs:ErrorInfo/vs:StackTrace, '&amp;', ''), '#xD;', '') "/>
<xsl:variable name="stderr" select="vs:Output/vs:StdErr"/>
<xsl:variable name="stdout" select="vs:Output/vs:StdOut"/>
<xsl:for-each select="//vs:UnitTest">
Expand Down
2 changes: 1 addition & 1 deletion tests/converter.trx.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const describe = require('@jest/globals').describe;
const setup = require('./setup');
const converter = require('../src/converter');

describe.only("TRX converter tests", () => {
describe("TRX converter tests", () => {

beforeAll(() => {
setup.removeTempDir();
Expand Down
38 changes: 19 additions & 19 deletions tests/data/result/trx-mstest-datadriven-mochawesome.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
},
"results": [
{
"uuid": "ca4e8d53-07a4-4095-9467-f3fe651b7647",
"uuid": "d5e11b20-37c0-443a-9b20-5328702a0e82",
"title": "",
"fullFile": "",
"file": "",
Expand All @@ -25,7 +25,7 @@
"tests": [],
"suites": [
{
"uuid": "933cb7c7-61ec-45c3-9498-876edcdf2f3f",
"uuid": "d7132400-d019-4ae5-9742-d7704fe5111a",
"title": "MsTestSample.DataDriven",
"file": "",
"beforeHooks": [],
Expand All @@ -44,11 +44,11 @@
"code": null,
"err": {
"message": "Assert.Fail failed. Failing for demo purposes",
"estack": "at MsTestSample.DataDriven.Failing_test() in D:\\Work-Git\\github\\Mini\\trx2junit\\samples\\MsTestSample\\DataDriven.cs:line 25\n",
"estack": "at MsTestSample.DataDriven.Failing_test() in D:\\Work-Git\\github\\Mini\\trx2junit\\samples\\MsTestSample\\DataDriven.cs:line 25",
"diff": null
},
"uuid": "bdbafc09-acba-42dc-87ad-b6b3a1cac70c",
"parentUUID": "933cb7c7-61ec-45c3-9498-876edcdf2f3f",
"uuid": "67131c07-9855-486e-b448-a02ab66d59bc",
"parentUUID": "d7132400-d019-4ae5-9742-d7704fe5111a",
"isHook": false,
"skipped": false
},
Expand All @@ -64,8 +64,8 @@
"context": null,
"code": null,
"err": {},
"uuid": "fce746fd-7f78-4efb-967b-27ba7e7256c0",
"parentUUID": "933cb7c7-61ec-45c3-9498-876edcdf2f3f",
"uuid": "09b49361-a256-4295-bf86-17cec2e6ab4a",
"parentUUID": "d7132400-d019-4ae5-9742-d7704fe5111a",
"isHook": false,
"skipped": false
},
Expand All @@ -81,8 +81,8 @@
"context": null,
"code": null,
"err": {},
"uuid": "a126d245-fcd5-491f-b6d5-d3c709f95105",
"parentUUID": "933cb7c7-61ec-45c3-9498-876edcdf2f3f",
"uuid": "15171883-7cb1-4819-9fce-d7a714d65b36",
"parentUUID": "d7132400-d019-4ae5-9742-d7704fe5111a",
"isHook": false,
"skipped": false
},
Expand All @@ -99,11 +99,11 @@
"code": null,
"err": {
"message": "Assert.Fail failed. Failing for demo purposes",
"estack": "at MsTestSample.DataDriven.Two_pass_one_fails(Int32 arg) in D:\\Work-Git\\github\\Mini\\trx2junit\\samples\\MsTestSample\\DataDriven.cs:line 16\n",
"estack": "at MsTestSample.DataDriven.Two_pass_one_fails(Int32 arg) in D:\\Work-Git\\github\\Mini\\trx2junit\\samples\\MsTestSample\\DataDriven.cs:line 16",
"diff": null
},
"uuid": "478a767f-f510-47d3-a2bb-7c77bbf0e3fc",
"parentUUID": "933cb7c7-61ec-45c3-9498-876edcdf2f3f",
"uuid": "e2a746b5-7384-4601-afbf-dcd08c88441a",
"parentUUID": "d7132400-d019-4ae5-9742-d7704fe5111a",
"isHook": false,
"skipped": false
},
Expand All @@ -119,21 +119,21 @@
"context": null,
"code": null,
"err": {},
"uuid": "c3949b19-32b3-4092-89fd-18e4e5ac9254",
"parentUUID": "933cb7c7-61ec-45c3-9498-876edcdf2f3f",
"uuid": "f011c430-db85-4cae-b771-27c116259e9e",
"parentUUID": "d7132400-d019-4ae5-9742-d7704fe5111a",
"isHook": false,
"skipped": false
}
],
"suites": [],
"passes": [
"fce746fd-7f78-4efb-967b-27ba7e7256c0",
"a126d245-fcd5-491f-b6d5-d3c709f95105",
"c3949b19-32b3-4092-89fd-18e4e5ac9254"
"09b49361-a256-4295-bf86-17cec2e6ab4a",
"15171883-7cb1-4819-9fce-d7a714d65b36",
"f011c430-db85-4cae-b771-27c116259e9e"
],
"failures": [
"bdbafc09-acba-42dc-87ad-b6b3a1cac70c",
"478a767f-f510-47d3-a2bb-7c77bbf0e3fc"
"67131c07-9855-486e-b448-a02ab66d59bc",
"e2a746b5-7384-4601-afbf-dcd08c88441a"
],
"pending": [],
"skipped": [],
Expand Down
Loading

0 comments on commit e0bf1b3

Please sign in to comment.