1 | 'use strict';
|
2 |
|
3 | Object.defineProperty(exports, '__esModule', {
|
4 | value: true
|
5 | });
|
6 | exports.default = void 0;
|
7 |
|
8 | function path() {
|
9 | const data = _interopRequireWildcard(require('path'));
|
10 |
|
11 | path = function () {
|
12 | return data;
|
13 | };
|
14 |
|
15 | return data;
|
16 | }
|
17 |
|
18 | function _v8Coverage() {
|
19 | const data = require('@bcoe/v8-coverage');
|
20 |
|
21 | _v8Coverage = function () {
|
22 | return data;
|
23 | };
|
24 |
|
25 | return data;
|
26 | }
|
27 |
|
28 | function _chalk() {
|
29 | const data = _interopRequireDefault(require('chalk'));
|
30 |
|
31 | _chalk = function () {
|
32 | return data;
|
33 | };
|
34 |
|
35 | return data;
|
36 | }
|
37 |
|
38 | function _glob() {
|
39 | const data = _interopRequireDefault(require('glob'));
|
40 |
|
41 | _glob = function () {
|
42 | return data;
|
43 | };
|
44 |
|
45 | return data;
|
46 | }
|
47 |
|
48 | function fs() {
|
49 | const data = _interopRequireWildcard(require('graceful-fs'));
|
50 |
|
51 | fs = function () {
|
52 | return data;
|
53 | };
|
54 |
|
55 | return data;
|
56 | }
|
57 |
|
58 | function _istanbulLibCoverage() {
|
59 | const data = _interopRequireDefault(require('istanbul-lib-coverage'));
|
60 |
|
61 | _istanbulLibCoverage = function () {
|
62 | return data;
|
63 | };
|
64 |
|
65 | return data;
|
66 | }
|
67 |
|
68 | function _istanbulLibReport() {
|
69 | const data = _interopRequireDefault(require('istanbul-lib-report'));
|
70 |
|
71 | _istanbulLibReport = function () {
|
72 | return data;
|
73 | };
|
74 |
|
75 | return data;
|
76 | }
|
77 |
|
78 | function _istanbulLibSourceMaps() {
|
79 | const data = _interopRequireDefault(require('istanbul-lib-source-maps'));
|
80 |
|
81 | _istanbulLibSourceMaps = function () {
|
82 | return data;
|
83 | };
|
84 |
|
85 | return data;
|
86 | }
|
87 |
|
88 | function _istanbulReports() {
|
89 | const data = _interopRequireDefault(require('istanbul-reports'));
|
90 |
|
91 | _istanbulReports = function () {
|
92 | return data;
|
93 | };
|
94 |
|
95 | return data;
|
96 | }
|
97 |
|
98 | function _v8ToIstanbul() {
|
99 | const data = _interopRequireDefault(require('v8-to-istanbul'));
|
100 |
|
101 | _v8ToIstanbul = function () {
|
102 | return data;
|
103 | };
|
104 |
|
105 | return data;
|
106 | }
|
107 |
|
108 | function _jestUtil() {
|
109 | const data = require('jest-util');
|
110 |
|
111 | _jestUtil = function () {
|
112 | return data;
|
113 | };
|
114 |
|
115 | return data;
|
116 | }
|
117 |
|
118 | function _jestWorker() {
|
119 | const data = require('jest-worker');
|
120 |
|
121 | _jestWorker = function () {
|
122 | return data;
|
123 | };
|
124 |
|
125 | return data;
|
126 | }
|
127 |
|
128 | var _BaseReporter = _interopRequireDefault(require('./BaseReporter'));
|
129 |
|
130 | var _getWatermarks = _interopRequireDefault(require('./getWatermarks'));
|
131 |
|
132 | function _interopRequireDefault(obj) {
|
133 | return obj && obj.__esModule ? obj : {default: obj};
|
134 | }
|
135 |
|
136 | function _getRequireWildcardCache(nodeInterop) {
|
137 | if (typeof WeakMap !== 'function') return null;
|
138 | var cacheBabelInterop = new WeakMap();
|
139 | var cacheNodeInterop = new WeakMap();
|
140 | return (_getRequireWildcardCache = function (nodeInterop) {
|
141 | return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
|
142 | })(nodeInterop);
|
143 | }
|
144 |
|
145 | function _interopRequireWildcard(obj, nodeInterop) {
|
146 | if (!nodeInterop && obj && obj.__esModule) {
|
147 | return obj;
|
148 | }
|
149 | if (obj === null || (typeof obj !== 'object' && typeof obj !== 'function')) {
|
150 | return {default: obj};
|
151 | }
|
152 | var cache = _getRequireWildcardCache(nodeInterop);
|
153 | if (cache && cache.has(obj)) {
|
154 | return cache.get(obj);
|
155 | }
|
156 | var newObj = {};
|
157 | var hasPropertyDescriptor =
|
158 | Object.defineProperty && Object.getOwnPropertyDescriptor;
|
159 | for (var key in obj) {
|
160 | if (key !== 'default' && Object.prototype.hasOwnProperty.call(obj, key)) {
|
161 | var desc = hasPropertyDescriptor
|
162 | ? Object.getOwnPropertyDescriptor(obj, key)
|
163 | : null;
|
164 | if (desc && (desc.get || desc.set)) {
|
165 | Object.defineProperty(newObj, key, desc);
|
166 | } else {
|
167 | newObj[key] = obj[key];
|
168 | }
|
169 | }
|
170 | }
|
171 | newObj.default = obj;
|
172 | if (cache) {
|
173 | cache.set(obj, newObj);
|
174 | }
|
175 | return newObj;
|
176 | }
|
177 |
|
178 | function _defineProperty(obj, key, value) {
|
179 | if (key in obj) {
|
180 | Object.defineProperty(obj, key, {
|
181 | value: value,
|
182 | enumerable: true,
|
183 | configurable: true,
|
184 | writable: true
|
185 | });
|
186 | } else {
|
187 | obj[key] = value;
|
188 | }
|
189 | return obj;
|
190 | }
|
191 |
|
192 | const FAIL_COLOR = _chalk().default.bold.red;
|
193 |
|
194 | const RUNNING_TEST_COLOR = _chalk().default.bold.dim;
|
195 |
|
196 | class CoverageReporter extends _BaseReporter.default {
|
197 | constructor(globalConfig, options) {
|
198 | super();
|
199 |
|
200 | _defineProperty(this, '_coverageMap', void 0);
|
201 |
|
202 | _defineProperty(this, '_globalConfig', void 0);
|
203 |
|
204 | _defineProperty(this, '_sourceMapStore', void 0);
|
205 |
|
206 | _defineProperty(this, '_options', void 0);
|
207 |
|
208 | _defineProperty(this, '_v8CoverageResults', void 0);
|
209 |
|
210 | this._coverageMap = _istanbulLibCoverage().default.createCoverageMap({});
|
211 | this._globalConfig = globalConfig;
|
212 | this._sourceMapStore =
|
213 | _istanbulLibSourceMaps().default.createSourceMapStore();
|
214 | this._v8CoverageResults = [];
|
215 | this._options = options || {};
|
216 | }
|
217 |
|
218 | onTestResult(_test, testResult) {
|
219 | if (testResult.v8Coverage) {
|
220 | this._v8CoverageResults.push(testResult.v8Coverage);
|
221 |
|
222 | return;
|
223 | }
|
224 |
|
225 | if (testResult.coverage) {
|
226 | this._coverageMap.merge(testResult.coverage);
|
227 | }
|
228 | }
|
229 |
|
230 | async onRunComplete(contexts, aggregatedResults) {
|
231 | await this._addUntestedFiles(contexts);
|
232 | const {map, reportContext} = await this._getCoverageResult();
|
233 |
|
234 | try {
|
235 | const coverageReporters = this._globalConfig.coverageReporters || [];
|
236 |
|
237 | if (!this._globalConfig.useStderr && coverageReporters.length < 1) {
|
238 | coverageReporters.push('text-summary');
|
239 | }
|
240 |
|
241 | coverageReporters.forEach(reporter => {
|
242 | let additionalOptions = {};
|
243 |
|
244 | if (Array.isArray(reporter)) {
|
245 | [reporter, additionalOptions] = reporter;
|
246 | }
|
247 |
|
248 | _istanbulReports()
|
249 | .default.create(reporter, {
|
250 | maxCols: process.stdout.columns || Infinity,
|
251 | ...additionalOptions
|
252 | })
|
253 | .execute(reportContext);
|
254 | });
|
255 | aggregatedResults.coverageMap = map;
|
256 | } catch (e) {
|
257 | console.error(
|
258 | _chalk().default.red(`
|
259 | Failed to write coverage reports:
|
260 | ERROR: ${e.toString()}
|
261 | STACK: ${e.stack}
|
262 | `)
|
263 | );
|
264 | }
|
265 |
|
266 | this._checkThreshold(map);
|
267 | }
|
268 |
|
269 | async _addUntestedFiles(contexts) {
|
270 | const files = [];
|
271 | contexts.forEach(context => {
|
272 | const config = context.config;
|
273 |
|
274 | if (
|
275 | this._globalConfig.collectCoverageFrom &&
|
276 | this._globalConfig.collectCoverageFrom.length
|
277 | ) {
|
278 | context.hasteFS
|
279 | .matchFilesWithGlob(
|
280 | this._globalConfig.collectCoverageFrom,
|
281 | config.rootDir
|
282 | )
|
283 | .forEach(filePath =>
|
284 | files.push({
|
285 | config,
|
286 | path: filePath
|
287 | })
|
288 | );
|
289 | }
|
290 | });
|
291 |
|
292 | if (!files.length) {
|
293 | return;
|
294 | }
|
295 |
|
296 | if (_jestUtil().isInteractive) {
|
297 | process.stderr.write(
|
298 | RUNNING_TEST_COLOR('Running coverage on untested files...')
|
299 | );
|
300 | }
|
301 |
|
302 | let worker;
|
303 |
|
304 | if (this._globalConfig.maxWorkers <= 1) {
|
305 | worker = require('./CoverageWorker');
|
306 | } else {
|
307 | worker = new (_jestWorker().Worker)(require.resolve('./CoverageWorker'), {
|
308 | exposedMethods: ['worker'],
|
309 | maxRetries: 2,
|
310 | numWorkers: this._globalConfig.maxWorkers
|
311 | });
|
312 | }
|
313 |
|
314 | const instrumentation = files.map(async fileObj => {
|
315 | const filename = fileObj.path;
|
316 | const config = fileObj.config;
|
317 |
|
318 | const hasCoverageData = this._v8CoverageResults.some(v8Res =>
|
319 | v8Res.some(innerRes => innerRes.result.url === filename)
|
320 | );
|
321 |
|
322 | if (
|
323 | !hasCoverageData &&
|
324 | !this._coverageMap.data[filename] &&
|
325 | 'worker' in worker
|
326 | ) {
|
327 | try {
|
328 | const result = await worker.worker({
|
329 | config,
|
330 | globalConfig: this._globalConfig,
|
331 | options: {
|
332 | ...this._options,
|
333 | changedFiles:
|
334 | this._options.changedFiles &&
|
335 | Array.from(this._options.changedFiles),
|
336 | sourcesRelatedToTestsInChangedFiles:
|
337 | this._options.sourcesRelatedToTestsInChangedFiles &&
|
338 | Array.from(this._options.sourcesRelatedToTestsInChangedFiles)
|
339 | },
|
340 | path: filename
|
341 | });
|
342 |
|
343 | if (result) {
|
344 | if (result.kind === 'V8Coverage') {
|
345 | this._v8CoverageResults.push([
|
346 | {
|
347 | codeTransformResult: undefined,
|
348 | result: result.result
|
349 | }
|
350 | ]);
|
351 | } else {
|
352 | this._coverageMap.addFileCoverage(result.coverage);
|
353 | }
|
354 | }
|
355 | } catch (error) {
|
356 | console.error(
|
357 | _chalk().default.red(
|
358 | [
|
359 | `Failed to collect coverage from ${filename}`,
|
360 | `ERROR: ${error.message}`,
|
361 | `STACK: ${error.stack}`
|
362 | ].join('\n')
|
363 | )
|
364 | );
|
365 | }
|
366 | }
|
367 | });
|
368 |
|
369 | try {
|
370 | await Promise.all(instrumentation);
|
371 | } catch {
|
372 |
|
373 | }
|
374 |
|
375 | if (_jestUtil().isInteractive) {
|
376 | (0, _jestUtil().clearLine)(process.stderr);
|
377 | }
|
378 |
|
379 | if (worker && 'end' in worker && typeof worker.end === 'function') {
|
380 | await worker.end();
|
381 | }
|
382 | }
|
383 |
|
384 | _checkThreshold(map) {
|
385 | const {coverageThreshold} = this._globalConfig;
|
386 |
|
387 | if (coverageThreshold) {
|
388 | function check(name, thresholds, actuals) {
|
389 | return ['statements', 'branches', 'lines', 'functions'].reduce(
|
390 | (errors, key) => {
|
391 | const actual = actuals[key].pct;
|
392 | const actualUncovered = actuals[key].total - actuals[key].covered;
|
393 | const threshold = thresholds[key];
|
394 |
|
395 | if (threshold !== undefined) {
|
396 | if (threshold < 0) {
|
397 | if (threshold * -1 < actualUncovered) {
|
398 | errors.push(
|
399 | `Jest: Uncovered count for ${key} (${actualUncovered}) ` +
|
400 | `exceeds ${name} threshold (${-1 * threshold})`
|
401 | );
|
402 | }
|
403 | } else if (actual < threshold) {
|
404 | errors.push(
|
405 | `Jest: "${name}" coverage threshold for ${key} (${threshold}%) not met: ${actual}%`
|
406 | );
|
407 | }
|
408 | }
|
409 |
|
410 | return errors;
|
411 | },
|
412 | []
|
413 | );
|
414 | }
|
415 |
|
416 | const THRESHOLD_GROUP_TYPES = {
|
417 | GLOB: 'glob',
|
418 | GLOBAL: 'global',
|
419 | PATH: 'path'
|
420 | };
|
421 | const coveredFiles = map.files();
|
422 | const thresholdGroups = Object.keys(coverageThreshold);
|
423 | const groupTypeByThresholdGroup = {};
|
424 | const filesByGlob = {};
|
425 | const coveredFilesSortedIntoThresholdGroup = coveredFiles.reduce(
|
426 | (files, file) => {
|
427 | const pathOrGlobMatches = thresholdGroups.reduce(
|
428 | (agg, thresholdGroup) => {
|
429 | const absoluteThresholdGroup = path().resolve(thresholdGroup);
|
430 |
|
431 | if (file.indexOf(absoluteThresholdGroup) === 0) {
|
432 | groupTypeByThresholdGroup[thresholdGroup] =
|
433 | THRESHOLD_GROUP_TYPES.PATH;
|
434 | return agg.concat([[file, thresholdGroup]]);
|
435 | }
|
436 |
|
437 |
|
438 |
|
439 |
|
440 | if (filesByGlob[absoluteThresholdGroup] === undefined) {
|
441 | filesByGlob[absoluteThresholdGroup] = _glob()
|
442 | .default.sync(absoluteThresholdGroup)
|
443 | .map(filePath => path().resolve(filePath));
|
444 | }
|
445 |
|
446 | if (filesByGlob[absoluteThresholdGroup].indexOf(file) > -1) {
|
447 | groupTypeByThresholdGroup[thresholdGroup] =
|
448 | THRESHOLD_GROUP_TYPES.GLOB;
|
449 | return agg.concat([[file, thresholdGroup]]);
|
450 | }
|
451 |
|
452 | return agg;
|
453 | },
|
454 | []
|
455 | );
|
456 |
|
457 | if (pathOrGlobMatches.length > 0) {
|
458 | return files.concat(pathOrGlobMatches);
|
459 | }
|
460 |
|
461 | if (thresholdGroups.indexOf(THRESHOLD_GROUP_TYPES.GLOBAL) > -1) {
|
462 | groupTypeByThresholdGroup[THRESHOLD_GROUP_TYPES.GLOBAL] =
|
463 | THRESHOLD_GROUP_TYPES.GLOBAL;
|
464 | return files.concat([[file, THRESHOLD_GROUP_TYPES.GLOBAL]]);
|
465 | }
|
466 |
|
467 | return files.concat([[file, undefined]]);
|
468 | },
|
469 | []
|
470 | );
|
471 |
|
472 | const getFilesInThresholdGroup = thresholdGroup =>
|
473 | coveredFilesSortedIntoThresholdGroup
|
474 | .filter(fileAndGroup => fileAndGroup[1] === thresholdGroup)
|
475 | .map(fileAndGroup => fileAndGroup[0]);
|
476 |
|
477 | function combineCoverage(filePaths) {
|
478 | return filePaths
|
479 | .map(filePath => map.fileCoverageFor(filePath))
|
480 | .reduce((combinedCoverage, nextFileCoverage) => {
|
481 | if (combinedCoverage === undefined || combinedCoverage === null) {
|
482 | return nextFileCoverage.toSummary();
|
483 | }
|
484 |
|
485 | return combinedCoverage.merge(nextFileCoverage.toSummary());
|
486 | }, undefined);
|
487 | }
|
488 |
|
489 | let errors = [];
|
490 | thresholdGroups.forEach(thresholdGroup => {
|
491 | switch (groupTypeByThresholdGroup[thresholdGroup]) {
|
492 | case THRESHOLD_GROUP_TYPES.GLOBAL: {
|
493 | const coverage = combineCoverage(
|
494 | getFilesInThresholdGroup(THRESHOLD_GROUP_TYPES.GLOBAL)
|
495 | );
|
496 |
|
497 | if (coverage) {
|
498 | errors = errors.concat(
|
499 | check(
|
500 | thresholdGroup,
|
501 | coverageThreshold[thresholdGroup],
|
502 | coverage
|
503 | )
|
504 | );
|
505 | }
|
506 |
|
507 | break;
|
508 | }
|
509 |
|
510 | case THRESHOLD_GROUP_TYPES.PATH: {
|
511 | const coverage = combineCoverage(
|
512 | getFilesInThresholdGroup(thresholdGroup)
|
513 | );
|
514 |
|
515 | if (coverage) {
|
516 | errors = errors.concat(
|
517 | check(
|
518 | thresholdGroup,
|
519 | coverageThreshold[thresholdGroup],
|
520 | coverage
|
521 | )
|
522 | );
|
523 | }
|
524 |
|
525 | break;
|
526 | }
|
527 |
|
528 | case THRESHOLD_GROUP_TYPES.GLOB:
|
529 | getFilesInThresholdGroup(thresholdGroup).forEach(
|
530 | fileMatchingGlob => {
|
531 | errors = errors.concat(
|
532 | check(
|
533 | fileMatchingGlob,
|
534 | coverageThreshold[thresholdGroup],
|
535 | map.fileCoverageFor(fileMatchingGlob).toSummary()
|
536 | )
|
537 | );
|
538 | }
|
539 | );
|
540 | break;
|
541 |
|
542 | default:
|
543 |
|
544 | if (thresholdGroup !== THRESHOLD_GROUP_TYPES.GLOBAL) {
|
545 | errors = errors.concat(
|
546 | `Jest: Coverage data for ${thresholdGroup} was not found.`
|
547 | );
|
548 | }
|
549 |
|
550 |
|
551 |
|
552 |
|
553 | }
|
554 | });
|
555 | errors = errors.filter(
|
556 | err => err !== undefined && err !== null && err.length > 0
|
557 | );
|
558 |
|
559 | if (errors.length > 0) {
|
560 | this.log(`${FAIL_COLOR(errors.join('\n'))}`);
|
561 |
|
562 | this._setError(new Error(errors.join('\n')));
|
563 | }
|
564 | }
|
565 | }
|
566 |
|
567 | async _getCoverageResult() {
|
568 | if (this._globalConfig.coverageProvider === 'v8') {
|
569 | const mergedCoverages = (0, _v8Coverage().mergeProcessCovs)(
|
570 | this._v8CoverageResults.map(cov => ({
|
571 | result: cov.map(r => r.result)
|
572 | }))
|
573 | );
|
574 | const fileTransforms = new Map();
|
575 |
|
576 | this._v8CoverageResults.forEach(res =>
|
577 | res.forEach(r => {
|
578 | if (r.codeTransformResult && !fileTransforms.has(r.result.url)) {
|
579 | fileTransforms.set(r.result.url, r.codeTransformResult);
|
580 | }
|
581 | })
|
582 | );
|
583 |
|
584 | const transformedCoverage = await Promise.all(
|
585 | mergedCoverages.result.map(async res => {
|
586 | var _fileTransform$wrappe;
|
587 |
|
588 | const fileTransform = fileTransforms.get(res.url);
|
589 | let sourcemapContent = undefined;
|
590 |
|
591 | if (
|
592 | fileTransform !== null &&
|
593 | fileTransform !== void 0 &&
|
594 | fileTransform.sourceMapPath &&
|
595 | fs().existsSync(fileTransform.sourceMapPath)
|
596 | ) {
|
597 | sourcemapContent = JSON.parse(
|
598 | fs().readFileSync(fileTransform.sourceMapPath, 'utf8')
|
599 | );
|
600 | }
|
601 |
|
602 | const converter = (0, _v8ToIstanbul().default)(
|
603 | res.url,
|
604 | (_fileTransform$wrappe =
|
605 | fileTransform === null || fileTransform === void 0
|
606 | ? void 0
|
607 | : fileTransform.wrapperLength) !== null &&
|
608 | _fileTransform$wrappe !== void 0
|
609 | ? _fileTransform$wrappe
|
610 | : 0,
|
611 | fileTransform && sourcemapContent
|
612 | ? {
|
613 | originalSource: fileTransform.originalCode,
|
614 | source: fileTransform.code,
|
615 | sourceMap: {
|
616 | sourcemap: {
|
617 | file: res.url,
|
618 | ...sourcemapContent
|
619 | }
|
620 | }
|
621 | }
|
622 | : {
|
623 | source: fs().readFileSync(res.url, 'utf8')
|
624 | }
|
625 | );
|
626 | await converter.load();
|
627 | converter.applyCoverage(res.functions);
|
628 | return converter.toIstanbul();
|
629 | })
|
630 | );
|
631 |
|
632 | const map = _istanbulLibCoverage().default.createCoverageMap({});
|
633 |
|
634 | transformedCoverage.forEach(res => map.merge(res));
|
635 |
|
636 | const reportContext = _istanbulLibReport().default.createContext({
|
637 | coverageMap: map,
|
638 | dir: this._globalConfig.coverageDirectory,
|
639 | watermarks: (0, _getWatermarks.default)(this._globalConfig)
|
640 | });
|
641 |
|
642 | return {
|
643 | map,
|
644 | reportContext
|
645 | };
|
646 | }
|
647 |
|
648 | const map = await this._sourceMapStore.transformCoverage(this._coverageMap);
|
649 |
|
650 | const reportContext = _istanbulLibReport().default.createContext({
|
651 | coverageMap: map,
|
652 | dir: this._globalConfig.coverageDirectory,
|
653 | sourceFinder: this._sourceMapStore.sourceFinder,
|
654 | watermarks: (0, _getWatermarks.default)(this._globalConfig)
|
655 | });
|
656 |
|
657 | return {
|
658 | map,
|
659 | reportContext
|
660 | };
|
661 | }
|
662 | }
|
663 |
|
664 | exports.default = CoverageReporter;
|
665 |
|
666 | _defineProperty(CoverageReporter, 'filename', __filename);
|