UNPKG

5.12 kBJavaScriptView Raw
1'use strict';
2
3const stripAnsi = require('strip-ansi');
4const constants = require('../constants/index');
5const path = require('path');
6
7
8// Wrap the varName with template tags
9const toTemplateTag = function (varName) {
10 return "{" + varName + "}";
11}
12
13// Replaces var using a template string or a function.
14// When strOrFunc is a template string replaces {varname} with the value from the variables map.
15// When strOrFunc is a function it returns the result of the function to which the variables are passed.
16const 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
33const executionTime = function (startTime, endTime) {
34 return (endTime - startTime) / 1000;
35}
36
37module.exports = function (report, appDirectory, options) {
38 // Generate a single XML file for all jest tests
39 let jsonResults = {
40 'testsuites': [{
41 '_attr': {
42 'name': options.suiteName,
43 'tests': 0,
44 'failures': 0,
45 // Overall execution time:
46 // Since tests are typically executed in parallel this time can be significantly smaller
47 // than the sum of the individual test suites
48 'time': executionTime(report.startTime, Date.now())
49 }
50 }]
51 };
52
53 // Iterate through outer testResults (test suites)
54 report.testResults.forEach((suite) => {
55 // Skip empty test suites
56 if (suite.testResults.length <= 0) {
57 return;
58 }
59
60 // If the usePathForSuiteName option is true and the
61 // suiteNameTemplate value is set to the default, overrides
62 // the suiteNameTemplate.
63 if (options.usePathForSuiteName === 'true' &&
64 options.suiteNameTemplate === toTemplateTag(constants.TITLE_VAR)) {
65
66 options.suiteNameTemplate = toTemplateTag(constants.FILEPATH_VAR);
67 }
68
69 // Build variables for suite name
70 const filepath = path.relative(appDirectory, suite.testFilePath);
71 const filename = path.basename(filepath);
72 const suiteTitle = suite.testResults[0].ancestorTitles[0];
73 const displayName = suite.displayName;
74
75 // Build replacement map
76 let suiteNameVariables = {};
77 suiteNameVariables[constants.FILEPATH_VAR] = filepath;
78 suiteNameVariables[constants.FILENAME_VAR] = filename;
79 suiteNameVariables[constants.TITLE_VAR] = suiteTitle;
80 suiteNameVariables[constants.DISPLAY_NAME_VAR] = displayName;
81
82 // Add <testsuite /> properties
83 const suiteNumTests = suite.numFailingTests + suite.numPassingTests + suite.numPendingTests;
84 const suiteExecutionTime = executionTime(suite.perfStats.start, suite.perfStats.end);
85
86 let testSuite = {
87 'testsuite': [{
88 _attr: {
89 name: replaceVars(options.suiteNameTemplate, suiteNameVariables),
90 errors: 0, // not supported
91 failures: suite.numFailingTests,
92 skipped: suite.numPendingTests,
93 timestamp: (new Date(suite.perfStats.start)).toISOString().slice(0, -5),
94 time: suiteExecutionTime,
95 tests: suiteNumTests
96 }
97 }]
98 };
99
100 // Update top level testsuites properties
101 jsonResults.testsuites[0]._attr.failures += suite.numFailingTests;
102 jsonResults.testsuites[0]._attr.tests += suiteNumTests;
103
104 // Iterate through test cases
105 suite.testResults.forEach((tc) => {
106 const classname = tc.ancestorTitles.join(options.ancestorSeparator);
107 const testTitle = tc.title;
108
109 // Build replacement map
110 let testVariables = {};
111 testVariables[constants.FILEPATH_VAR] = filepath;
112 testVariables[constants.FILENAME_VAR] = filename;
113 testVariables[constants.CLASSNAME_VAR] = classname;
114 testVariables[constants.TITLE_VAR] = testTitle;
115 testVariables[constants.DISPLAY_NAME_VAR] = displayName;
116
117 let testCase = {
118 'testcase': [{
119 _attr: {
120 classname: replaceVars(options.classNameTemplate, testVariables),
121 name: replaceVars(options.titleTemplate, testVariables),
122 time: tc.duration / 1000
123 }
124 }]
125 };
126
127 if (options.addFileAttribute === 'true') {
128 testCase.testcase[0]._attr.file = filepath;
129 }
130
131 // Write out all failure messages as <failure> tags
132 // Nested underneath <testcase> tag
133 if (tc.status === 'failed') {
134 tc.failureMessages.forEach((failure) => {
135 testCase.testcase.push({
136 'failure': stripAnsi(failure)
137 });
138 })
139 }
140
141 // Write out a <skipped> tag if test is skipped
142 // Nested underneath <testcase> tag
143 if (tc.status === 'pending') {
144 testCase.testcase.push({
145 skipped: {}
146 });
147 }
148
149 testSuite.testsuite.push(testCase);
150 });
151
152 jsonResults.testsuites.push(testSuite);
153 });
154
155 return jsonResults;
156};
\No newline at end of file