1 | 'use strict';
|
2 |
|
3 | const stripAnsi = require('strip-ansi');
|
4 | const constants = require('../constants/index');
|
5 | const path = require('path');
|
6 | const fs = require('fs');
|
7 |
|
8 |
|
9 | const toTemplateTag = function (varName) {
|
10 | return "{" + varName + "}";
|
11 | }
|
12 |
|
13 |
|
14 |
|
15 |
|
16 | const replaceVars = function (strOrFunc, variables) {
|
17 | if (typeof strOrFunc === 'string') {
|
18 | let str = strOrFunc;
|
19 | Object.keys(variables).forEach((varName) => {
|
20 | str = str.replace(toTemplateTag(varName), variables[varName]);
|
21 | });
|
22 | return str;
|
23 | } else {
|
24 | const func = strOrFunc;
|
25 | const resolvedStr = func(variables);
|
26 | if (typeof resolvedStr !== 'string') {
|
27 | throw new Error('Template function should return a string');
|
28 | }
|
29 | return resolvedStr;
|
30 | }
|
31 | };
|
32 |
|
33 | const executionTime = function (startTime, endTime) {
|
34 | return (endTime - startTime) / 1000;
|
35 | }
|
36 |
|
37 | module.exports = function (report, appDirectory, options) {
|
38 |
|
39 | const junitSuitePropertiesFilePath = path.join(process.cwd(), options.testSuitePropertiesFile);
|
40 | let ignoreSuitePropertiesCheck = !fs.existsSync(junitSuitePropertiesFilePath);
|
41 |
|
42 |
|
43 | let jsonResults = {
|
44 | 'testsuites': [{
|
45 | '_attr': {
|
46 | 'name': options.suiteName,
|
47 | 'tests': 0,
|
48 | 'failures': 0,
|
49 |
|
50 |
|
51 |
|
52 | 'time': executionTime(report.startTime, Date.now())
|
53 | }
|
54 | }]
|
55 | };
|
56 |
|
57 |
|
58 | report.testResults.forEach((suite) => {
|
59 |
|
60 | if (suite.testResults.length <= 0) {
|
61 | return;
|
62 | }
|
63 |
|
64 |
|
65 |
|
66 |
|
67 | if (options.usePathForSuiteName === 'true' &&
|
68 | options.suiteNameTemplate === toTemplateTag(constants.TITLE_VAR)) {
|
69 |
|
70 | options.suiteNameTemplate = toTemplateTag(constants.FILEPATH_VAR);
|
71 | }
|
72 |
|
73 |
|
74 | const filepath = path.relative(appDirectory, suite.testFilePath);
|
75 | const filename = path.basename(filepath);
|
76 | const suiteTitle = suite.testResults[0].ancestorTitles[0];
|
77 | const displayName = suite.displayName;
|
78 |
|
79 |
|
80 | let suiteNameVariables = {};
|
81 | suiteNameVariables[constants.FILEPATH_VAR] = filepath;
|
82 | suiteNameVariables[constants.FILENAME_VAR] = filename;
|
83 | suiteNameVariables[constants.TITLE_VAR] = suiteTitle;
|
84 | suiteNameVariables[constants.DISPLAY_NAME_VAR] = displayName;
|
85 |
|
86 |
|
87 | const suiteNumTests = suite.numFailingTests + suite.numPassingTests + suite.numPendingTests;
|
88 | const suiteExecutionTime = executionTime(suite.perfStats.start, suite.perfStats.end);
|
89 |
|
90 | let testSuite = {
|
91 | 'testsuite': [{
|
92 | _attr: {
|
93 | name: replaceVars(options.suiteNameTemplate, suiteNameVariables),
|
94 | errors: 0,
|
95 | failures: suite.numFailingTests,
|
96 | skipped: suite.numPendingTests,
|
97 | timestamp: (new Date(suite.perfStats.start)).toISOString().slice(0, -5),
|
98 | time: suiteExecutionTime,
|
99 | tests: suiteNumTests
|
100 | }
|
101 | }]
|
102 | };
|
103 |
|
104 |
|
105 | jsonResults.testsuites[0]._attr.failures += suite.numFailingTests;
|
106 | jsonResults.testsuites[0]._attr.tests += suiteNumTests;
|
107 |
|
108 |
|
109 | if (options.includeConsoleOutput === 'true' && suite.console && suite.console.length) {
|
110 |
|
111 |
|
112 |
|
113 | let testSuiteConsole = {
|
114 | 'system-out': {
|
115 | _cdata: JSON.stringify(suite.console, null, 2)
|
116 | }
|
117 | };
|
118 |
|
119 | testSuite.testsuite.push(testSuiteConsole);
|
120 | }
|
121 |
|
122 |
|
123 | if (options.includeShortConsoleOutput === 'true' && suite.console && suite.console.length) {
|
124 |
|
125 |
|
126 |
|
127 | let testSuiteConsole = {
|
128 | 'system-out': {
|
129 | _cdata: JSON.stringify(suite.console.map(item => item.message), null, 2)
|
130 | }
|
131 | };
|
132 |
|
133 | testSuite.testsuite.push(testSuiteConsole);
|
134 | }
|
135 |
|
136 | if (!ignoreSuitePropertiesCheck) {
|
137 | let junitSuiteProperties = require(junitSuitePropertiesFilePath)(suite);
|
138 |
|
139 |
|
140 | let testSuitePropertyMain = {
|
141 | 'properties': []
|
142 | };
|
143 |
|
144 | Object.keys(junitSuiteProperties).forEach((p) => {
|
145 | let testSuiteProperty = {
|
146 | 'property': {
|
147 | _attr: {
|
148 | name: p,
|
149 | value: replaceVars(junitSuiteProperties[p], suiteNameVariables)
|
150 | }
|
151 | }
|
152 | };
|
153 |
|
154 | testSuitePropertyMain.properties.push(testSuiteProperty);
|
155 | });
|
156 |
|
157 | testSuite.testsuite.push(testSuitePropertyMain);
|
158 | }
|
159 |
|
160 |
|
161 | suite.testResults.forEach((tc) => {
|
162 | const classname = tc.ancestorTitles.join(options.ancestorSeparator);
|
163 | const testTitle = tc.title;
|
164 |
|
165 |
|
166 | let testVariables = {};
|
167 | testVariables[constants.FILEPATH_VAR] = filepath;
|
168 | testVariables[constants.FILENAME_VAR] = filename;
|
169 | testVariables[constants.CLASSNAME_VAR] = classname;
|
170 | testVariables[constants.TITLE_VAR] = testTitle;
|
171 | testVariables[constants.DISPLAY_NAME_VAR] = displayName;
|
172 |
|
173 | let testCase = {
|
174 | 'testcase': [{
|
175 | _attr: {
|
176 | classname: replaceVars(options.classNameTemplate, testVariables),
|
177 | name: replaceVars(options.titleTemplate, testVariables),
|
178 | time: tc.duration / 1000
|
179 | }
|
180 | }]
|
181 | };
|
182 |
|
183 | if (options.addFileAttribute === 'true') {
|
184 | testCase.testcase[0]._attr.file = filepath;
|
185 | }
|
186 |
|
187 |
|
188 |
|
189 | if (tc.status === 'failed') {
|
190 | tc.failureMessages.forEach((failure) => {
|
191 | testCase.testcase.push({
|
192 | 'failure': stripAnsi(failure)
|
193 | });
|
194 | })
|
195 | }
|
196 |
|
197 |
|
198 |
|
199 | if (tc.status === 'pending') {
|
200 | testCase.testcase.push({
|
201 | skipped: {}
|
202 | });
|
203 | }
|
204 |
|
205 | testSuite.testsuite.push(testCase);
|
206 | });
|
207 |
|
208 | jsonResults.testsuites.push(testSuite);
|
209 | });
|
210 |
|
211 | return jsonResults;
|
212 | };
|