Skip to content

Commit

Permalink
Merge pull request #129 from palmerj3/addPropertiesSupport
Browse files Browse the repository at this point in the history
Add support for test suite properties. Upgrade mkdirp. Drop node < 10 support
  • Loading branch information
palmerj3 committed Jun 20, 2020
2 parents 7f53d6e + d3a2b21 commit 4e21bc3
Show file tree
Hide file tree
Showing 12 changed files with 130 additions and 27 deletions.
8 changes: 3 additions & 5 deletions .travis.yml
@@ -1,12 +1,10 @@
language: node_js
node_js:
- "8"
- "10"
- "12"
- "13"
- "14"
env:
- JEST_VERSION=^22.0.0
- JEST_VERSION=^23.0.0
- JEST_VERSION=^24.0.0
- JEST_VERSION=^24.9.0
- JEST_VERSION=^26.0.0
script:
- npm run test:ci
27 changes: 27 additions & 0 deletions README.md
Expand Up @@ -3,6 +3,8 @@
# jest-junit
A Jest reporter that creates compatible junit xml files

Note: as of jest-junit 11.0.0 NodeJS >= 10.12.0 is required.

## Installation
```shell
yarn add --dev jest-junit
Expand Down Expand Up @@ -217,3 +219,28 @@ renders
</testsuite>
</testsuites>
```

#### Adding custom testsuite properties
New feature as of jest-junit 11.0.0!

Create a file in your project root directory named junitProperties.js:
```js
module.exports = () => {
return {
key: "value"
}
});
```

Will render
```xml
<testsuites name="jest tests">
<testsuite name="addition" tests="1" errors="0" failures="0" skipped="0" timestamp="2017-07-13T09:42:28" time="0.161">
<properties>
<property name="key" value="value" />
</properties>
<testcase classname="addition positive numbers should add up" name="addition positive numbers should add up" time="0.004">
</testcase>
</testsuite>
</testsuites>
```
24 changes: 24 additions & 0 deletions __tests__/__snapshots__/buildJsonResults.test.js.snap
Expand Up @@ -24,6 +24,18 @@ Object {
"timestamp": "2018-02-10T14:52:31",
},
},
Object {
"properties": Array [
Object {
"property": Object {
"_attr": Object {
"name": "best-tester",
"value": "Jason Palmer",
},
},
},
],
},
Object {
"testcase": Array [
Object {
Expand All @@ -50,6 +62,18 @@ Object {
"timestamp": "2018-02-10T14:52:31",
},
},
Object {
"properties": Array [
Object {
"property": Object {
"_attr": Object {
"name": "best-tester",
"value": "Jason Palmer",
},
},
},
],
},
Object {
"testcase": Array [
Object {
Expand Down
23 changes: 12 additions & 11 deletions __tests__/buildJsonResults.test.js
Expand Up @@ -52,7 +52,8 @@ describe('buildJsonResults', () => {
Object.assign({}, constants.DEFAULT_OPTIONS, {
classNameTemplate: "{filename}"
}));
expect(jsonResults.testsuites[1].testsuite[1].testcase[0]._attr.classname).toBe('foo.test.js');

expect(jsonResults.testsuites[1].testsuite[2].testcase[0]._attr.classname).toBe('foo.test.js');
});

it('should support return the function result when classNameTemplate is a function', () => {
Expand All @@ -63,7 +64,7 @@ describe('buildJsonResults', () => {
return 'function called with vars: ' + Object.keys(vars).join(', ');
}
}));
expect(jsonResults.testsuites[1].testsuite[1].testcase[0]._attr.classname)
expect(jsonResults.testsuites[1].testsuite[2].testcase[0]._attr.classname)
.toBe('function called with vars: filepath, filename, classname, title, displayName');
});

Expand All @@ -73,7 +74,7 @@ describe('buildJsonResults', () => {
Object.assign({}, constants.DEFAULT_OPTIONS, {
titleTemplate: "{filepath}"
}));
expect(jsonResults.testsuites[1].testsuite[1].testcase[0]._attr.name).toBe('path/to/test/__tests__/foo.test.js');
expect(jsonResults.testsuites[1].testsuite[2].testcase[0]._attr.name).toBe('path/to/test/__tests__/foo.test.js');
});

it('should return the proper filepath when suiteNameTemplate is "{filepath}" and usePathForSuiteName is "false"', () => {
Expand Down Expand Up @@ -116,7 +117,7 @@ describe('buildJsonResults', () => {
const noFailingTestsReport = require('../__mocks__/no-failing-tests.json');
const jsonResults = buildJsonResults(noFailingTestsReport, '/',
Object.assign({}, constants.DEFAULT_OPTIONS));
expect(jsonResults.testsuites[1].testsuite[1].testcase[0]._attr.classname).toBe('foo baz should bar');
expect(jsonResults.testsuites[1].testsuite[2].testcase[0]._attr.classname).toBe('foo baz should bar');
});

it('should return the proper classname when ancestorSeparator is customized', () => {
Expand All @@ -125,14 +126,14 @@ describe('buildJsonResults', () => {
Object.assign({}, constants.DEFAULT_OPTIONS, {
ancestorSeparator: " › "
}));
expect(jsonResults.testsuites[1].testsuite[1].testcase[0]._attr.classname).toBe('foo › baz should bar');
expect(jsonResults.testsuites[1].testsuite[2].testcase[0]._attr.classname).toBe('foo › baz should bar');
});

it('should parse failure messages for failing tests', () => {
const failingTestsReport = require('../__mocks__/failing-tests.json');
const jsonResults = buildJsonResults(failingTestsReport, '/path/to/test', constants.DEFAULT_OPTIONS);

const failureMsg = jsonResults.testsuites[1].testsuite[1].testcase[1].failure;
const failureMsg = jsonResults.testsuites[1].testsuite[2].testcase[1].failure;

// Make sure no escape codes are there that exist in the mock
expect(failureMsg.includes('\u001b')).toBe(false);
Expand All @@ -158,7 +159,7 @@ describe('buildJsonResults', () => {
it('should not return the file name by default', () => {
const noFailingTestsReport = require('../__mocks__/no-failing-tests.json');
const jsonResults = buildJsonResults(noFailingTestsReport, '/', constants.DEFAULT_OPTIONS);
expect(jsonResults.testsuites[1].testsuite[1].testcase[0]._attr.file).toBe(undefined);
expect(jsonResults.testsuites[1].testsuite[2].testcase[0]._attr.file).toBe(undefined);
});

it('should return the file name when addFileAttribute is "true"', () => {
Expand All @@ -167,7 +168,7 @@ describe('buildJsonResults', () => {
Object.assign({}, constants.DEFAULT_OPTIONS, {
addFileAttribute: "true"
}));
expect(jsonResults.testsuites[1].testsuite[1].testcase[0]._attr.file).toBe('path/to/test/__tests__/foo.test.js');
expect(jsonResults.testsuites[1].testsuite[2].testcase[0]._attr.file).toBe('path/to/test/__tests__/foo.test.js');
});

it('should show output of console if includeConsoleOutput is true', () => {
Expand All @@ -189,7 +190,7 @@ describe('buildJsonResults', () => {

expect(jsonResults.testsuites[1].testsuite[1]['system-out']).not.toBeDefined();
});

it('should show short console output if includeShortConsoleOutput is true', () => {
const reportWithShortConsoleOutput = require('../__mocks__/test-with-console-output.json');
const jsonResults = buildJsonResults(reportWithShortConsoleOutput, '/',
Expand All @@ -206,7 +207,7 @@ describe('buildJsonResults', () => {
Object.assign({}, constants.DEFAULT_OPTIONS, {
includeShortConsoleOutput: "false"
}));
expect(jsonResults.testsuites[1].testsuite[1]['system-out']).not.toBeDefined();

expect(jsonResults.testsuites[1].testsuite[2]['system-out']).not.toBeDefined();
});
});
2 changes: 1 addition & 1 deletion __tests__/getOptions.test.js
Expand Up @@ -6,7 +6,7 @@ const getOptions = require('../utils/getOptions.js');
jest.mock('fs', () => {
return Object.assign(
{},
require.requireActual('fs'),
jest.requireActual('fs'),
{
existsSync: jest.fn().mockReturnValue(true)
}
Expand Down
4 changes: 2 additions & 2 deletions __tests__/testResultProcessor.test.js
Expand Up @@ -3,7 +3,7 @@
jest.mock('mkdirp', () => {
return Object.assign(
{},
require.requireActual('mkdirp'),
jest.requireActual('mkdirp'),
{
sync: jest.fn()
}
Expand All @@ -13,7 +13,7 @@ jest.mock('mkdirp', () => {
jest.mock('fs', () => {
return Object.assign(
{},
require.requireActual('fs'),
jest.requireActual('fs'),
{
writeFileSync: jest.fn()
}
Expand Down
4 changes: 3 additions & 1 deletion constants/index.js
Expand Up @@ -14,6 +14,7 @@ module.exports = {
JEST_JUNIT_INCLUDE_CONSOLE_OUTPUT: 'includeConsoleOutput',
JEST_JUNIT_INCLUDE_SHORT_CONSOLE_OUTPUT: 'includeShortConsoleOutput',
JEST_USE_PATH_FOR_SUITE_NAME: 'usePathForSuiteName',
JEST_JUNIT_TEST_SUITE_PROPERTIES_JSON_FILE: 'testSuitePropertiesFile'
},
DEFAULT_OPTIONS: {
suiteName: 'jest tests',
Expand All @@ -27,7 +28,8 @@ module.exports = {
usePathForSuiteName: 'false',
addFileAttribute: 'false',
includeConsoleOutput: 'false',
includeShortConsoleOutput: 'false'
includeShortConsoleOutput: 'false',
testSuitePropertiesFile: 'junitProperties.js'
},
CLASSNAME_VAR: 'classname',
FILENAME_VAR: 'filename',
Expand Down
3 changes: 2 additions & 1 deletion jest.config.js
Expand Up @@ -12,5 +12,6 @@ module.exports = {
"<rootDir>/integration-tests/testResultsProcessor/",
"<rootDir>/integration-tests/reporter/"
],
setupFilesAfterEnv: ["<rootDir>/__tests__/lib/setupTests.js"]
setupFilesAfterEnv: ["<rootDir>/__tests__/lib/setupTests.js"],
reporters: ['default', '.']
};
5 changes: 5 additions & 0 deletions junitProperties.js
@@ -0,0 +1,5 @@
module.exports = (suite) => {
return {
'best-tester': 'Jason Palmer'
}
}
6 changes: 3 additions & 3 deletions package.json
@@ -1,13 +1,13 @@
{
"name": "jest-junit",
"version": "10.0.0",
"version": "11.0.0",
"description": "A jest reporter that generates junit xml files",
"main": "index.js",
"repository": "https://github.com/jest-community/jest-junit",
"author": "Jason Palmer",
"license": "Apache-2.0",
"engines": {
"node": ">=8.0.0"
"node": ">=10.12.0"
},
"files": [
"index.js",
Expand All @@ -21,7 +21,7 @@
},
"dependencies": {
"jest-validate": "^24.9.0",
"mkdirp": "^0.5.1",
"mkdirp": "^1.0.4",
"strip-ansi": "^5.2.0",
"uuid": "^3.3.3",
"xml": "^1.0.1"
Expand Down
32 changes: 30 additions & 2 deletions utils/buildJsonResults.js
Expand Up @@ -3,7 +3,7 @@
const stripAnsi = require('strip-ansi');
const constants = require('../constants/index');
const path = require('path');

const fs = require('fs');

// Wrap the varName with template tags
const toTemplateTag = function (varName) {
Expand Down Expand Up @@ -35,6 +35,10 @@ const executionTime = function (startTime, endTime) {
}

module.exports = function (report, appDirectory, options) {
// Check if there is a junitProperties.js (or whatever they called it)
const junitSuitePropertiesFilePath = path.join(process.cwd(), options.testSuitePropertiesFile);
let ignoreSuitePropertiesCheck = !fs.existsSync(junitSuitePropertiesFilePath);

// Generate a single XML file for all jest tests
let jsonResults = {
'testsuites': [{
Expand Down Expand Up @@ -114,7 +118,7 @@ module.exports = function (report, appDirectory, options) {

testSuite.testsuite.push(testSuiteConsole);
}

// Write short stdout console output if available
if (options.includeShortConsoleOutput === 'true' && suite.console && suite.console.length) {
// Extract and then Stringify the console message value
Expand All @@ -129,6 +133,30 @@ module.exports = function (report, appDirectory, options) {
testSuite.testsuite.push(testSuiteConsole);
}

if (!ignoreSuitePropertiesCheck) {
let junitSuiteProperties = require(junitSuitePropertiesFilePath)(suite);

// Add any test suite properties
let testSuitePropertyMain = {
'properties': []
};

Object.keys(junitSuiteProperties).forEach((p) => {
let testSuiteProperty = {
'property': {
_attr: {
name: p,
value: replaceVars(junitSuiteProperties[p], suiteNameVariables)
}
}
};

testSuitePropertyMain.properties.push(testSuiteProperty);
});

testSuite.testsuite.push(testSuitePropertyMain);
}

// Iterate through test cases
suite.testResults.forEach((tc) => {
const classname = tc.ancestorTitles.join(options.ancestorSeparator);
Expand Down
19 changes: 18 additions & 1 deletion yarn.lock
Expand Up @@ -2237,6 +2237,11 @@ minimist@^1.1.1, minimist@^1.2.0:
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=

minimist@^1.2.5:
version "1.2.5"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==

minimist@~0.0.1:
version "0.0.10"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf"
Expand Down Expand Up @@ -2265,13 +2270,25 @@ mixin-deep@^1.2.0:
for-in "^1.0.2"
is-extendable "^1.0.1"

mkdirp@^0.5.0, mkdirp@^0.5.1:
mkdirp@^0.5.0:
version "0.5.1"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=
dependencies:
minimist "0.0.8"

mkdirp@^0.5.1:
version "0.5.5"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def"
integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==
dependencies:
minimist "^1.2.5"

mkdirp@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e"
integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==

ms@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
Expand Down

0 comments on commit 4e21bc3

Please sign in to comment.