jest-html-reporter 2.6.2 → 2.8.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/htmlreporter.js +373 -0
- package/dist/htmlreporter.js.map +1 -0
- package/dist/index.js +602 -0
- package/dist/index.js.map +1 -0
- package/dist/main.js +104 -18
- package/dist/main.min.js +1 -1
- package/dist/sortingMethods.js +57 -0
- package/dist/sortingMethods.js.map +1 -0
- package/package.json +5 -5
- package/style/darkTheme.css +3 -0
- package/style/defaultTheme.css +3 -0
- package/style/lightTheme.css +3 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,602 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
|
|
4
|
+
|
|
5
|
+
var dateformat = _interopDefault(require('dateformat'));
|
|
6
|
+
var fs = _interopDefault(require('fs'));
|
|
7
|
+
var mkdirp = _interopDefault(require('mkdirp'));
|
|
8
|
+
var path = _interopDefault(require('path'));
|
|
9
|
+
var stripAnsi = _interopDefault(require('strip-ansi'));
|
|
10
|
+
var xmlbuilder = _interopDefault(require('xmlbuilder'));
|
|
11
|
+
|
|
12
|
+
var sorting = ((testResults, sortType) => {
|
|
13
|
+
const sortTypeLowercase = sortType && sortType.toLowerCase();
|
|
14
|
+
|
|
15
|
+
switch (sortTypeLowercase) {
|
|
16
|
+
case "status":
|
|
17
|
+
return sortByStatus(testResults);
|
|
18
|
+
|
|
19
|
+
case "executiondesc":
|
|
20
|
+
return sortByExecutionDesc(testResults);
|
|
21
|
+
|
|
22
|
+
case "executionasc":
|
|
23
|
+
return sortByExecutionAsc(testResults);
|
|
24
|
+
|
|
25
|
+
case "titledesc":
|
|
26
|
+
return sortByTitleDesc(testResults);
|
|
27
|
+
|
|
28
|
+
case "titleasc":
|
|
29
|
+
return sortByTitleAsc(testResults);
|
|
30
|
+
|
|
31
|
+
default:
|
|
32
|
+
return testResults;
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
/**
|
|
36
|
+
* Splits test suites apart based on individual test status and sorts by that status:
|
|
37
|
+
* 1. Pending
|
|
38
|
+
* 2. Failed
|
|
39
|
+
* 3. Passed
|
|
40
|
+
*/
|
|
41
|
+
|
|
42
|
+
const sortByStatus = testResults => {
|
|
43
|
+
const pendingSuites = [];
|
|
44
|
+
const failingSuites = [];
|
|
45
|
+
const passingSuites = [];
|
|
46
|
+
testResults.forEach(result => {
|
|
47
|
+
const pending = [];
|
|
48
|
+
const failed = [];
|
|
49
|
+
const passed = [];
|
|
50
|
+
result.testResults.forEach(x => {
|
|
51
|
+
if (x.status === "pending") {
|
|
52
|
+
pending.push(x);
|
|
53
|
+
} else if (x.status === "failed") {
|
|
54
|
+
failed.push(x);
|
|
55
|
+
} else {
|
|
56
|
+
passed.push(x);
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
if (pending.length > 0) {
|
|
61
|
+
pendingSuites.push({ ...result,
|
|
62
|
+
testResults: pending
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (failed.length > 0) {
|
|
67
|
+
failingSuites.push({ ...result,
|
|
68
|
+
testResults: failed
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (passed.length > 0) {
|
|
73
|
+
passingSuites.push({ ...result,
|
|
74
|
+
testResults: passed
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
return [].concat(pendingSuites, failingSuites, passingSuites);
|
|
79
|
+
};
|
|
80
|
+
/**
|
|
81
|
+
* Sorts by Execution Time | Descending
|
|
82
|
+
*/
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
const sortByExecutionDesc = testResults => {
|
|
86
|
+
if (testResults) {
|
|
87
|
+
testResults.sort((a, b) => b.perfStats.end - b.perfStats.start - (a.perfStats.end - a.perfStats.start));
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return testResults;
|
|
91
|
+
};
|
|
92
|
+
/**
|
|
93
|
+
* Sorts by Execution Time | Ascending
|
|
94
|
+
*/
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
const sortByExecutionAsc = testResults => {
|
|
98
|
+
if (testResults) {
|
|
99
|
+
testResults.sort((a, b) => a.perfStats.end - a.perfStats.start - (b.perfStats.end - b.perfStats.start));
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return testResults;
|
|
103
|
+
};
|
|
104
|
+
/**
|
|
105
|
+
* Sorts by Suite filename and Test name | Descending
|
|
106
|
+
*/
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
const sortByTitleDesc = testResults => {
|
|
110
|
+
if (testResults) {
|
|
111
|
+
// Sort Suites
|
|
112
|
+
const sorted = testResults.sort((a, b) => sortAlphabetically(a.testFilePath, b.testFilePath, true)); // Sort Suite testResults
|
|
113
|
+
|
|
114
|
+
sorted.forEach(suite => {
|
|
115
|
+
suite.testResults.sort((a, b) => sortAlphabetically(a.ancestorTitles.join(" "), b.ancestorTitles.join(" "), true));
|
|
116
|
+
});
|
|
117
|
+
return sorted;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return testResults;
|
|
121
|
+
};
|
|
122
|
+
/**
|
|
123
|
+
* Sorts by Suite filename and Test name | Ascending
|
|
124
|
+
*/
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
const sortByTitleAsc = testResults => {
|
|
128
|
+
if (testResults) {
|
|
129
|
+
// Sort Suites
|
|
130
|
+
const sorted = testResults.sort((a, b) => sortAlphabetically(a.testFilePath, b.testFilePath)); // Sort Suite testResults
|
|
131
|
+
|
|
132
|
+
sorted.forEach(suite => {
|
|
133
|
+
suite.testResults.sort((a, b) => sortAlphabetically(a.ancestorTitles.join(" "), b.ancestorTitles.join(" ")));
|
|
134
|
+
});
|
|
135
|
+
return sorted;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return testResults;
|
|
139
|
+
};
|
|
140
|
+
/**
|
|
141
|
+
* Helper sorting method
|
|
142
|
+
*/
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
const sortAlphabetically = (a, b, reversed = false) => {
|
|
146
|
+
if (!reversed && a < b || reversed && a > b) {
|
|
147
|
+
return -1;
|
|
148
|
+
} else if (!reversed && a > b || reversed && a < b) {
|
|
149
|
+
return 1;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return 0;
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
class HTMLReporter {
|
|
156
|
+
constructor(testData, options, consoleLogs) {
|
|
157
|
+
this.testData = testData;
|
|
158
|
+
this.consoleLogList = consoleLogs;
|
|
159
|
+
this.setupConfig(options);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
async generate() {
|
|
163
|
+
try {
|
|
164
|
+
const report = await this.renderTestReport();
|
|
165
|
+
const outputPath = this.getConfigValue("outputPath");
|
|
166
|
+
await mkdirp(path.dirname(outputPath));
|
|
167
|
+
|
|
168
|
+
if (this.getConfigValue("append")) {
|
|
169
|
+
await fs.appendFileSync(outputPath, report);
|
|
170
|
+
} else {
|
|
171
|
+
await fs.writeFileSync(outputPath, report);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
this.logMessage("success", `Report generated (${outputPath})`);
|
|
175
|
+
return report;
|
|
176
|
+
} catch (e) {
|
|
177
|
+
this.logMessage("error", e);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
async renderTestReport() {
|
|
182
|
+
// Generate the content of the test report
|
|
183
|
+
const reportBody = await this.renderTestReportBody(); // --
|
|
184
|
+
// Boilerplate Option
|
|
185
|
+
|
|
186
|
+
if (!!this.getConfigValue("boilerplate")) {
|
|
187
|
+
const boilerplateContent = await fs.readFileSync(this.getConfigValue("boilerplate"), "utf8");
|
|
188
|
+
return boilerplateContent.replace("{jesthtmlreporter-content}", reportBody.toString());
|
|
189
|
+
} // --
|
|
190
|
+
// Create HTML and apply reporter content
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
const HTMLBase = {
|
|
194
|
+
html: {
|
|
195
|
+
head: {
|
|
196
|
+
meta: {
|
|
197
|
+
"@charset": "utf-8"
|
|
198
|
+
},
|
|
199
|
+
title: {
|
|
200
|
+
"#text": this.getConfigValue("pageTitle")
|
|
201
|
+
},
|
|
202
|
+
style: undefined,
|
|
203
|
+
link: undefined
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}; // Default to the currently set theme
|
|
207
|
+
|
|
208
|
+
let stylesheetFilePath = path.join(__dirname, `../style/${this.getConfigValue("theme")}.css`); // Overriding stylesheet
|
|
209
|
+
|
|
210
|
+
if (this.getConfigValue("styleOverridePath")) {
|
|
211
|
+
stylesheetFilePath = this.getConfigValue("styleOverridePath");
|
|
212
|
+
} // Decide whether to inline the CSS or not
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
const inlineCSS = !this.getConfigValue("useCssFile") && !!!this.getConfigValue("styleOverridePath");
|
|
216
|
+
|
|
217
|
+
if (inlineCSS) {
|
|
218
|
+
const stylesheetContent = await fs.readFileSync(stylesheetFilePath, "utf8");
|
|
219
|
+
HTMLBase.html.head.style = {
|
|
220
|
+
"@type": "text/css",
|
|
221
|
+
"#text": stylesheetContent
|
|
222
|
+
};
|
|
223
|
+
} else {
|
|
224
|
+
HTMLBase.html.head.link = {
|
|
225
|
+
"@rel": "stylesheet",
|
|
226
|
+
"@type": "text/css",
|
|
227
|
+
"@href": stylesheetFilePath
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
const report = xmlbuilder.create(HTMLBase);
|
|
232
|
+
report.ele("body").raw(reportBody.toString());
|
|
233
|
+
return report;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
async renderTestReportBody() {
|
|
237
|
+
try {
|
|
238
|
+
if (!this.testData || Object.entries(this.testData).length === 0) {
|
|
239
|
+
throw Error("No test data provided");
|
|
240
|
+
} // HTML Body
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
const reportBody = xmlbuilder.begin().element("div", {
|
|
244
|
+
id: "jesthtml-content"
|
|
245
|
+
});
|
|
246
|
+
/**
|
|
247
|
+
* Page Header
|
|
248
|
+
*/
|
|
249
|
+
|
|
250
|
+
const header = reportBody.ele("header"); // Page Title
|
|
251
|
+
|
|
252
|
+
header.ele("h1", {
|
|
253
|
+
id: "title"
|
|
254
|
+
}, this.getConfigValue("pageTitle")); // Logo
|
|
255
|
+
|
|
256
|
+
const logo = this.getConfigValue("logo");
|
|
257
|
+
|
|
258
|
+
if (logo) {
|
|
259
|
+
header.ele("img", {
|
|
260
|
+
id: "logo",
|
|
261
|
+
src: logo
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Meta-Data
|
|
266
|
+
*/
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
const metaDataContainer = reportBody.ele("div", {
|
|
270
|
+
id: "metadata-container"
|
|
271
|
+
}); // Timestamp
|
|
272
|
+
|
|
273
|
+
const timestamp = new Date(this.testData.startTime);
|
|
274
|
+
metaDataContainer.ele("div", {
|
|
275
|
+
id: "timestamp"
|
|
276
|
+
}, `Start: ${dateformat(timestamp.toDateString(), this.getConfigValue("dateFormat"))}`); // Test Summary
|
|
277
|
+
|
|
278
|
+
metaDataContainer.ele("div", {
|
|
279
|
+
id: "summary"
|
|
280
|
+
}, `${this.testData.numTotalTests} tests -- ${this.testData.numPassedTests} passed / ${this.testData.numFailedTests} failed / ${this.testData.numPendingTests} pending`);
|
|
281
|
+
/**
|
|
282
|
+
* Apply any given sorting method to the test results
|
|
283
|
+
*/
|
|
284
|
+
|
|
285
|
+
const sortedTestResults = sorting(this.testData.testResults, this.getConfigValue("sort"));
|
|
286
|
+
/**
|
|
287
|
+
* Setup ignored test result statuses
|
|
288
|
+
*/
|
|
289
|
+
|
|
290
|
+
const statusIgnoreFilter = this.getConfigValue("statusIgnoreFilter");
|
|
291
|
+
let ignoredStatuses = [];
|
|
292
|
+
|
|
293
|
+
if (statusIgnoreFilter) {
|
|
294
|
+
ignoredStatuses = statusIgnoreFilter.replace(/\s/g, "").toLowerCase().split(",");
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* Test Suites
|
|
298
|
+
*/
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
sortedTestResults.map(suite => {
|
|
302
|
+
// Ignore this suite if there are no results
|
|
303
|
+
if (!suite.testResults || suite.testResults.length <= 0) {
|
|
304
|
+
return;
|
|
305
|
+
} // Suite Information
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
const suiteInfo = reportBody.ele("div", {
|
|
309
|
+
class: "suite-info"
|
|
310
|
+
}); // Suite Path
|
|
311
|
+
|
|
312
|
+
suiteInfo.ele("div", {
|
|
313
|
+
class: "suite-path"
|
|
314
|
+
}, suite.testFilePath); // Suite execution time
|
|
315
|
+
|
|
316
|
+
const executionTime = (suite.perfStats.end - suite.perfStats.start) / 1000;
|
|
317
|
+
suiteInfo.ele("div", {
|
|
318
|
+
class: `suite-time${executionTime > 5 ? " warn" : ""}`
|
|
319
|
+
}, `${executionTime}s`); // Suite Test Table
|
|
320
|
+
|
|
321
|
+
const suiteTable = reportBody.ele("table", {
|
|
322
|
+
class: "suite-table",
|
|
323
|
+
cellspacing: "0",
|
|
324
|
+
cellpadding: "0"
|
|
325
|
+
}); // Test Results
|
|
326
|
+
|
|
327
|
+
suite.testResults // Filter out the test results with statuses that equals the statusIgnoreFilter
|
|
328
|
+
.filter(s => !ignoredStatuses.includes(s.status)).forEach(test => {
|
|
329
|
+
const testTr = suiteTable.ele("tr", {
|
|
330
|
+
class: test.status
|
|
331
|
+
}); // Suite Name(s)
|
|
332
|
+
|
|
333
|
+
testTr.ele("td", {
|
|
334
|
+
class: "suite"
|
|
335
|
+
}, test.ancestorTitles.join(" > ")); // Test name
|
|
336
|
+
|
|
337
|
+
const testTitleTd = testTr.ele("td", {
|
|
338
|
+
class: "test"
|
|
339
|
+
}, test.title); // Test Failure Messages
|
|
340
|
+
|
|
341
|
+
if (test.failureMessages && this.getConfigValue("includeFailureMsg")) {
|
|
342
|
+
const failureMsgDiv = testTitleTd.ele("div", {
|
|
343
|
+
class: "failureMessages"
|
|
344
|
+
});
|
|
345
|
+
test.failureMessages.forEach(failureMsg => {
|
|
346
|
+
failureMsgDiv.ele("pre", {
|
|
347
|
+
class: "failureMsg"
|
|
348
|
+
}, stripAnsi(failureMsg));
|
|
349
|
+
});
|
|
350
|
+
} // Append data to <tr>
|
|
351
|
+
|
|
352
|
+
|
|
353
|
+
testTr.ele("td", {
|
|
354
|
+
class: "result"
|
|
355
|
+
}, test.status === "passed" ? `${test.status} in ${test.duration / 1000}s` : test.status);
|
|
356
|
+
}); // All console.logs caught during the test run
|
|
357
|
+
|
|
358
|
+
if (this.consoleLogList && this.consoleLogList.length > 0 && this.getConfigValue("includeConsoleLog")) {
|
|
359
|
+
// Filter out the logs for this test file path
|
|
360
|
+
const filteredConsoleLogs = this.consoleLogList.find(logs => logs.filePath === suite.testFilePath);
|
|
361
|
+
|
|
362
|
+
if (filteredConsoleLogs && filteredConsoleLogs.logs.length > 0) {
|
|
363
|
+
// Console Log Container
|
|
364
|
+
const consoleLogContainer = reportBody.ele("div", {
|
|
365
|
+
class: "suite-consolelog"
|
|
366
|
+
}); // Console Log Header
|
|
367
|
+
|
|
368
|
+
consoleLogContainer.ele("div", {
|
|
369
|
+
class: "suite-consolelog-header"
|
|
370
|
+
}, "Console Log"); // Apply the logs to the body
|
|
371
|
+
|
|
372
|
+
filteredConsoleLogs.logs.forEach(log => {
|
|
373
|
+
const logElement = consoleLogContainer.ele("div", {
|
|
374
|
+
class: "suite-consolelog-item"
|
|
375
|
+
});
|
|
376
|
+
logElement.ele("pre", {
|
|
377
|
+
class: "suite-consolelog-item-origin"
|
|
378
|
+
}, stripAnsi(log.origin));
|
|
379
|
+
logElement.ele("pre", {
|
|
380
|
+
class: "suite-consolelog-item-message"
|
|
381
|
+
}, stripAnsi(log.message));
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
});
|
|
386
|
+
return reportBody;
|
|
387
|
+
} catch (e) {
|
|
388
|
+
this.logMessage("error", e);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
/**
|
|
392
|
+
* Fetch and setup configuration
|
|
393
|
+
*/
|
|
394
|
+
|
|
395
|
+
|
|
396
|
+
setupConfig(options) {
|
|
397
|
+
this.config = {
|
|
398
|
+
append: {
|
|
399
|
+
defaultValue: false,
|
|
400
|
+
environmentVariable: "JEST_HTML_REPORTER_APPEND",
|
|
401
|
+
configValue: options.append
|
|
402
|
+
},
|
|
403
|
+
boilerplate: {
|
|
404
|
+
defaultValue: null,
|
|
405
|
+
environmentVariable: "JEST_HTML_REPORTER_BOILERPLATE",
|
|
406
|
+
configValue: options.boilerplate
|
|
407
|
+
},
|
|
408
|
+
customScriptPath: {
|
|
409
|
+
defaultValue: null,
|
|
410
|
+
environmentVariable: "JEST_HTML_REPORTER_CUSTOM_SCRIPT_PATH",
|
|
411
|
+
configValue: options.customScriptPath
|
|
412
|
+
},
|
|
413
|
+
dateFormat: {
|
|
414
|
+
defaultValue: "yyyy-mm-dd HH:MM:ss",
|
|
415
|
+
environmentVariable: "JEST_HTML_REPORTER_DATE_FORMAT",
|
|
416
|
+
configValue: options.dateFormat
|
|
417
|
+
},
|
|
418
|
+
executionTimeWarningThreshold: {
|
|
419
|
+
defaultValue: 5,
|
|
420
|
+
environmentVariable: "JEST_HTML_REPORTER_EXECUTION_TIME_WARNING_THRESHOLD",
|
|
421
|
+
configValue: options.executionTimeWarningThreshold
|
|
422
|
+
},
|
|
423
|
+
logo: {
|
|
424
|
+
defaultValue: null,
|
|
425
|
+
environmentVariable: "JEST_HTML_REPORTER_LOGO",
|
|
426
|
+
configValue: options.logo
|
|
427
|
+
},
|
|
428
|
+
includeFailureMsg: {
|
|
429
|
+
defaultValue: false,
|
|
430
|
+
environmentVariable: "JEST_HTML_REPORTER_INCLUDE_FAILURE_MSG",
|
|
431
|
+
configValue: options.includeFailureMsg
|
|
432
|
+
},
|
|
433
|
+
includeConsoleLog: {
|
|
434
|
+
defaultValue: false,
|
|
435
|
+
environmentVariable: "JEST_HTML_REPORTER_INCLUDE_CONSOLE_LOG",
|
|
436
|
+
configValue: options.includeConsoleLog
|
|
437
|
+
},
|
|
438
|
+
outputPath: {
|
|
439
|
+
defaultValue: path.join(process.cwd(), "test-report.html"),
|
|
440
|
+
environmentVariable: "JEST_HTML_REPORTER_OUTPUT_PATH",
|
|
441
|
+
configValue: options.outputPath
|
|
442
|
+
},
|
|
443
|
+
pageTitle: {
|
|
444
|
+
defaultValue: "Test Report",
|
|
445
|
+
environmentVariable: "JEST_HTML_REPORTER_PAGE_TITLE",
|
|
446
|
+
configValue: options.pageTitle
|
|
447
|
+
},
|
|
448
|
+
theme: {
|
|
449
|
+
defaultValue: "defaultTheme",
|
|
450
|
+
environmentVariable: "JEST_HTML_REPORTER_THEME",
|
|
451
|
+
configValue: options.theme
|
|
452
|
+
},
|
|
453
|
+
sort: {
|
|
454
|
+
defaultValue: null,
|
|
455
|
+
environmentVariable: "JEST_HTML_REPORTER_SORT",
|
|
456
|
+
configValue: options.sort
|
|
457
|
+
},
|
|
458
|
+
statusIgnoreFilter: {
|
|
459
|
+
defaultValue: null,
|
|
460
|
+
environmentVariable: "JEST_HTML_REPORTER_STATUS_FILTER",
|
|
461
|
+
configValue: options.statusIgnoreFilter
|
|
462
|
+
},
|
|
463
|
+
styleOverridePath: {
|
|
464
|
+
defaultValue: null,
|
|
465
|
+
environmentVariable: "JEST_HTML_REPORTER_STYLE_OVERRIDE_PATH",
|
|
466
|
+
configValue: options.styleOverridePath
|
|
467
|
+
},
|
|
468
|
+
useCssFile: {
|
|
469
|
+
defaultValue: false,
|
|
470
|
+
environmentVariable: "JEST_HTML_REPORTER_USE_CSS_FILE",
|
|
471
|
+
configValue: options.useCssFile
|
|
472
|
+
}
|
|
473
|
+
}; // Attempt to collect and assign config settings from jesthtmlreporter.config.json
|
|
474
|
+
|
|
475
|
+
try {
|
|
476
|
+
const jesthtmlreporterconfig = fs.readFileSync(path.join(process.cwd(), "jesthtmlreporter.config.json"), "utf8");
|
|
477
|
+
|
|
478
|
+
if (jesthtmlreporterconfig) {
|
|
479
|
+
const parsedConfig = JSON.parse(jesthtmlreporterconfig);
|
|
480
|
+
|
|
481
|
+
for (const key of Object.keys(parsedConfig)) {
|
|
482
|
+
if (this.config[key]) {
|
|
483
|
+
this.config[key].configValue = parsedConfig[key];
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
return;
|
|
488
|
+
}
|
|
489
|
+
} catch (e) {}
|
|
490
|
+
/** do nothing */
|
|
491
|
+
// If above method did not work we attempt to check package.json
|
|
492
|
+
|
|
493
|
+
|
|
494
|
+
try {
|
|
495
|
+
const packageJson = fs.readFileSync(path.join(process.cwd(), "package.json"), "utf8");
|
|
496
|
+
|
|
497
|
+
if (packageJson) {
|
|
498
|
+
const parsedConfig = JSON.parse(packageJson)["jest-html-reporter"];
|
|
499
|
+
|
|
500
|
+
for (const key of Object.keys(parsedConfig)) {
|
|
501
|
+
if (this.config[key]) {
|
|
502
|
+
this.config[key].configValue = parsedConfig[key];
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
} catch (e) {
|
|
507
|
+
/** do nothing */
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
/**
|
|
511
|
+
* Returns the configurated value from the config in the following priority order:
|
|
512
|
+
* Environment Variable > JSON configured value > Default value
|
|
513
|
+
* @param key
|
|
514
|
+
*/
|
|
515
|
+
|
|
516
|
+
|
|
517
|
+
getConfigValue(key) {
|
|
518
|
+
const option = this.config[key];
|
|
519
|
+
|
|
520
|
+
if (!option) {
|
|
521
|
+
return;
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
if (process.env[option.environmentVariable]) {
|
|
525
|
+
return process.env[option.environmentVariable];
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
return option.configValue || option.defaultValue;
|
|
529
|
+
}
|
|
530
|
+
/**
|
|
531
|
+
* Method for logging to the terminal
|
|
532
|
+
* @param type
|
|
533
|
+
* @param message
|
|
534
|
+
* @param ignoreConsole
|
|
535
|
+
*/
|
|
536
|
+
|
|
537
|
+
|
|
538
|
+
logMessage(type = "default", message, ignoreConsole) {
|
|
539
|
+
const logTypes = {
|
|
540
|
+
default: "\x1b[37m%s\x1b[0m",
|
|
541
|
+
success: "\x1b[32m%s\x1b[0m",
|
|
542
|
+
error: "\x1b[31m%s\x1b[0m"
|
|
543
|
+
};
|
|
544
|
+
const logColor = !logTypes[type] ? logTypes.default : logTypes[type];
|
|
545
|
+
const logMsg = `jest-html-reporter >> ${message}`;
|
|
546
|
+
|
|
547
|
+
if (!ignoreConsole) {
|
|
548
|
+
console.log(logColor, logMsg);
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
return {
|
|
552
|
+
logColor,
|
|
553
|
+
logMsg
|
|
554
|
+
}; // Return for testing purposes
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
function JestHtmlReporter(globalConfig, options) {
|
|
560
|
+
const consoleLogs = [];
|
|
561
|
+
/**
|
|
562
|
+
* If the first parameter has a property named 'testResults',
|
|
563
|
+
* the script is being run as a 'testResultsProcessor'.
|
|
564
|
+
* We then need to return the test results as they were received from Jest
|
|
565
|
+
* https://facebook.github.io/jest/docs/en/configuration.html#testresultsprocessor-string
|
|
566
|
+
*/
|
|
567
|
+
|
|
568
|
+
if (Object.prototype.hasOwnProperty.call(globalConfig, "testResults")) {
|
|
569
|
+
// @ts-ignore
|
|
570
|
+
setupAndRun(globalConfig.testResults, options); // Return the results as required by Jest
|
|
571
|
+
|
|
572
|
+
return globalConfig;
|
|
573
|
+
}
|
|
574
|
+
/**
|
|
575
|
+
* The default behaviour - run as Custom Reporter, in parallel with Jest.
|
|
576
|
+
* https://facebook.github.io/jest/docs/en/configuration.html#reporters-array-modulename-modulename-options
|
|
577
|
+
*/
|
|
578
|
+
|
|
579
|
+
|
|
580
|
+
this.onTestResult = (data, result) => {
|
|
581
|
+
// Catch console logs per test
|
|
582
|
+
if (result.console) {
|
|
583
|
+
consoleLogs.push({
|
|
584
|
+
filePath: result.testFilePath,
|
|
585
|
+
logs: result.console
|
|
586
|
+
});
|
|
587
|
+
}
|
|
588
|
+
};
|
|
589
|
+
|
|
590
|
+
this.onRunComplete = (contexts, testResult) => setupAndRun(testResult, options, consoleLogs);
|
|
591
|
+
}
|
|
592
|
+
/**
|
|
593
|
+
* Setup Jest HTML Reporter and generate a report with the given data
|
|
594
|
+
*/
|
|
595
|
+
|
|
596
|
+
|
|
597
|
+
const setupAndRun = (testResults, options, logs) => {
|
|
598
|
+
const reporter = new HTMLReporter(testResults, options, logs);
|
|
599
|
+
return reporter.generate();
|
|
600
|
+
};
|
|
601
|
+
|
|
602
|
+
module.exports = JestHtmlReporter;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;AAGA,kEAA0C;AAG1C,SAAS,gBAAgB,CACvB,YAAiC,EACjC,OAA8B;IAE9B,oDAAoD;IACpD,MAAM,WAAW,GAA+B,EAAE,CAAC;IAEnD;;;;;OAKG;IACH,IAAI,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,YAAY,EAAE,aAAa,CAAC,EAAE;QACrE,kBAAkB;QAClB,MAAM,QAAQ,GAAG,IAAI,sBAAY;QAC/B,aAAa;QACb,YAAY,CAAC,WAAW,EACxB,OAAmC,CACpC,CAAC;QACF,QAAQ,CAAC,QAAQ,EAAE,CAAC;QACpB,yCAAyC;QACzC,OAAO,YAAY,CAAC;KACrB;IAED;;;;OAIG;IACH,IAAI,CAAC,UAAU,GAAG,YAAY,CAAC;IAC/B,IAAI,CAAC,WAAW,GAAG,OAAO,CAAC;IAE3B,IAAI,CAAC,YAAY,GAAG,CAAC,IAAS,EAAE,MAAkB,EAAE,EAAE;QACpD,8BAA8B;QAC9B,IAAI,MAAM,CAAC,OAAO,EAAE;YAClB,WAAW,CAAC,IAAI,CAAC;gBACf,QAAQ,EAAE,MAAM,CAAC,YAAY;gBAC7B,IAAI,EAAE,MAAM,CAAC,OAAO;aACrB,CAAC,CAAC;SACJ;IACH,CAAC,CAAC;IAEF,IAAI,CAAC,aAAa,GAAG,CAAC,QAAa,EAAE,UAA4B,EAAE,EAAE;QACnE,MAAM,QAAQ,GAAG,IAAI,sBAAY,CAC/B,UAAU,EACV,OAAmC,CACpC,CAAC;QACF,QAAQ,CAAC,QAAQ,EAAE,CAAC;QACpB,2CAA2C;IAC7C,CAAC,CAAC;AACJ,CAAC;AAED,kBAAe,gBAAgB,CAAC"}
|