Spaces:
Sleeping
Sleeping
; | |
Object.defineProperty(exports, '__esModule', { | |
value: true | |
}); | |
exports.default = void 0; | |
function path() { | |
const data = _interopRequireWildcard(require('path')); | |
path = function () { | |
return data; | |
}; | |
return data; | |
} | |
function _v8Coverage() { | |
const data = require('@bcoe/v8-coverage'); | |
_v8Coverage = function () { | |
return data; | |
}; | |
return data; | |
} | |
function _chalk() { | |
const data = _interopRequireDefault(require('chalk')); | |
_chalk = function () { | |
return data; | |
}; | |
return data; | |
} | |
function _glob() { | |
const data = _interopRequireDefault(require('glob')); | |
_glob = function () { | |
return data; | |
}; | |
return data; | |
} | |
function fs() { | |
const data = _interopRequireWildcard(require('graceful-fs')); | |
fs = function () { | |
return data; | |
}; | |
return data; | |
} | |
function _istanbulLibCoverage() { | |
const data = _interopRequireDefault(require('istanbul-lib-coverage')); | |
_istanbulLibCoverage = function () { | |
return data; | |
}; | |
return data; | |
} | |
function _istanbulLibReport() { | |
const data = _interopRequireDefault(require('istanbul-lib-report')); | |
_istanbulLibReport = function () { | |
return data; | |
}; | |
return data; | |
} | |
function _istanbulLibSourceMaps() { | |
const data = _interopRequireDefault(require('istanbul-lib-source-maps')); | |
_istanbulLibSourceMaps = function () { | |
return data; | |
}; | |
return data; | |
} | |
function _istanbulReports() { | |
const data = _interopRequireDefault(require('istanbul-reports')); | |
_istanbulReports = function () { | |
return data; | |
}; | |
return data; | |
} | |
function _v8ToIstanbul() { | |
const data = _interopRequireDefault(require('v8-to-istanbul')); | |
_v8ToIstanbul = function () { | |
return data; | |
}; | |
return data; | |
} | |
function _jestUtil() { | |
const data = require('jest-util'); | |
_jestUtil = function () { | |
return data; | |
}; | |
return data; | |
} | |
function _jestWorker() { | |
const data = require('jest-worker'); | |
_jestWorker = function () { | |
return data; | |
}; | |
return data; | |
} | |
var _BaseReporter = _interopRequireDefault(require('./BaseReporter')); | |
var _getWatermarks = _interopRequireDefault(require('./getWatermarks')); | |
function _interopRequireDefault(obj) { | |
return obj && obj.__esModule ? obj : {default: obj}; | |
} | |
function _getRequireWildcardCache(nodeInterop) { | |
if (typeof WeakMap !== 'function') return null; | |
var cacheBabelInterop = new WeakMap(); | |
var cacheNodeInterop = new WeakMap(); | |
return (_getRequireWildcardCache = function (nodeInterop) { | |
return nodeInterop ? cacheNodeInterop : cacheBabelInterop; | |
})(nodeInterop); | |
} | |
function _interopRequireWildcard(obj, nodeInterop) { | |
if (!nodeInterop && obj && obj.__esModule) { | |
return obj; | |
} | |
if (obj === null || (typeof obj !== 'object' && typeof obj !== 'function')) { | |
return {default: obj}; | |
} | |
var cache = _getRequireWildcardCache(nodeInterop); | |
if (cache && cache.has(obj)) { | |
return cache.get(obj); | |
} | |
var newObj = {}; | |
var hasPropertyDescriptor = | |
Object.defineProperty && Object.getOwnPropertyDescriptor; | |
for (var key in obj) { | |
if (key !== 'default' && Object.prototype.hasOwnProperty.call(obj, key)) { | |
var desc = hasPropertyDescriptor | |
? Object.getOwnPropertyDescriptor(obj, key) | |
: null; | |
if (desc && (desc.get || desc.set)) { | |
Object.defineProperty(newObj, key, desc); | |
} else { | |
newObj[key] = obj[key]; | |
} | |
} | |
} | |
newObj.default = obj; | |
if (cache) { | |
cache.set(obj, newObj); | |
} | |
return newObj; | |
} | |
function _defineProperty(obj, key, value) { | |
if (key in obj) { | |
Object.defineProperty(obj, key, { | |
value: value, | |
enumerable: true, | |
configurable: true, | |
writable: true | |
}); | |
} else { | |
obj[key] = value; | |
} | |
return obj; | |
} | |
const FAIL_COLOR = _chalk().default.bold.red; | |
const RUNNING_TEST_COLOR = _chalk().default.bold.dim; | |
class CoverageReporter extends _BaseReporter.default { | |
constructor(globalConfig, options) { | |
super(); | |
_defineProperty(this, '_coverageMap', void 0); | |
_defineProperty(this, '_globalConfig', void 0); | |
_defineProperty(this, '_sourceMapStore', void 0); | |
_defineProperty(this, '_options', void 0); | |
_defineProperty(this, '_v8CoverageResults', void 0); | |
this._coverageMap = _istanbulLibCoverage().default.createCoverageMap({}); | |
this._globalConfig = globalConfig; | |
this._sourceMapStore = | |
_istanbulLibSourceMaps().default.createSourceMapStore(); | |
this._v8CoverageResults = []; | |
this._options = options || {}; | |
} | |
onTestResult(_test, testResult) { | |
if (testResult.v8Coverage) { | |
this._v8CoverageResults.push(testResult.v8Coverage); | |
return; | |
} | |
if (testResult.coverage) { | |
this._coverageMap.merge(testResult.coverage); | |
} | |
} | |
async onRunComplete(contexts, aggregatedResults) { | |
await this._addUntestedFiles(contexts); | |
const {map, reportContext} = await this._getCoverageResult(); | |
try { | |
const coverageReporters = this._globalConfig.coverageReporters || []; | |
if (!this._globalConfig.useStderr && coverageReporters.length < 1) { | |
coverageReporters.push('text-summary'); | |
} | |
coverageReporters.forEach(reporter => { | |
let additionalOptions = {}; | |
if (Array.isArray(reporter)) { | |
[reporter, additionalOptions] = reporter; | |
} | |
_istanbulReports() | |
.default.create(reporter, { | |
maxCols: process.stdout.columns || Infinity, | |
...additionalOptions | |
}) | |
.execute(reportContext); | |
}); | |
aggregatedResults.coverageMap = map; | |
} catch (e) { | |
console.error( | |
_chalk().default.red(` | |
Failed to write coverage reports: | |
ERROR: ${e.toString()} | |
STACK: ${e.stack} | |
`) | |
); | |
} | |
this._checkThreshold(map); | |
} | |
async _addUntestedFiles(contexts) { | |
const files = []; | |
contexts.forEach(context => { | |
const config = context.config; | |
if ( | |
this._globalConfig.collectCoverageFrom && | |
this._globalConfig.collectCoverageFrom.length | |
) { | |
context.hasteFS | |
.matchFilesWithGlob( | |
this._globalConfig.collectCoverageFrom, | |
config.rootDir | |
) | |
.forEach(filePath => | |
files.push({ | |
config, | |
path: filePath | |
}) | |
); | |
} | |
}); | |
if (!files.length) { | |
return; | |
} | |
if (_jestUtil().isInteractive) { | |
process.stderr.write( | |
RUNNING_TEST_COLOR('Running coverage on untested files...') | |
); | |
} | |
let worker; | |
if (this._globalConfig.maxWorkers <= 1) { | |
worker = require('./CoverageWorker'); | |
} else { | |
worker = new (_jestWorker().Worker)(require.resolve('./CoverageWorker'), { | |
exposedMethods: ['worker'], | |
maxRetries: 2, | |
numWorkers: this._globalConfig.maxWorkers | |
}); | |
} | |
const instrumentation = files.map(async fileObj => { | |
const filename = fileObj.path; | |
const config = fileObj.config; | |
const hasCoverageData = this._v8CoverageResults.some(v8Res => | |
v8Res.some(innerRes => innerRes.result.url === filename) | |
); | |
if ( | |
!hasCoverageData && | |
!this._coverageMap.data[filename] && | |
'worker' in worker | |
) { | |
try { | |
const result = await worker.worker({ | |
config, | |
globalConfig: this._globalConfig, | |
options: { | |
...this._options, | |
changedFiles: | |
this._options.changedFiles && | |
Array.from(this._options.changedFiles), | |
sourcesRelatedToTestsInChangedFiles: | |
this._options.sourcesRelatedToTestsInChangedFiles && | |
Array.from(this._options.sourcesRelatedToTestsInChangedFiles) | |
}, | |
path: filename | |
}); | |
if (result) { | |
if (result.kind === 'V8Coverage') { | |
this._v8CoverageResults.push([ | |
{ | |
codeTransformResult: undefined, | |
result: result.result | |
} | |
]); | |
} else { | |
this._coverageMap.addFileCoverage(result.coverage); | |
} | |
} | |
} catch (error) { | |
console.error( | |
_chalk().default.red( | |
[ | |
`Failed to collect coverage from ${filename}`, | |
`ERROR: ${error.message}`, | |
`STACK: ${error.stack}` | |
].join('\n') | |
) | |
); | |
} | |
} | |
}); | |
try { | |
await Promise.all(instrumentation); | |
} catch { | |
// Do nothing; errors were reported earlier to the console. | |
} | |
if (_jestUtil().isInteractive) { | |
(0, _jestUtil().clearLine)(process.stderr); | |
} | |
if (worker && 'end' in worker && typeof worker.end === 'function') { | |
await worker.end(); | |
} | |
} | |
_checkThreshold(map) { | |
const {coverageThreshold} = this._globalConfig; | |
if (coverageThreshold) { | |
function check(name, thresholds, actuals) { | |
return ['statements', 'branches', 'lines', 'functions'].reduce( | |
(errors, key) => { | |
const actual = actuals[key].pct; | |
const actualUncovered = actuals[key].total - actuals[key].covered; | |
const threshold = thresholds[key]; | |
if (threshold !== undefined) { | |
if (threshold < 0) { | |
if (threshold * -1 < actualUncovered) { | |
errors.push( | |
`Jest: Uncovered count for ${key} (${actualUncovered}) ` + | |
`exceeds ${name} threshold (${-1 * threshold})` | |
); | |
} | |
} else if (actual < threshold) { | |
errors.push( | |
`Jest: "${name}" coverage threshold for ${key} (${threshold}%) not met: ${actual}%` | |
); | |
} | |
} | |
return errors; | |
}, | |
[] | |
); | |
} | |
const THRESHOLD_GROUP_TYPES = { | |
GLOB: 'glob', | |
GLOBAL: 'global', | |
PATH: 'path' | |
}; | |
const coveredFiles = map.files(); | |
const thresholdGroups = Object.keys(coverageThreshold); | |
const groupTypeByThresholdGroup = {}; | |
const filesByGlob = {}; | |
const coveredFilesSortedIntoThresholdGroup = coveredFiles.reduce( | |
(files, file) => { | |
const pathOrGlobMatches = thresholdGroups.reduce( | |
(agg, thresholdGroup) => { | |
const absoluteThresholdGroup = path().resolve(thresholdGroup); // The threshold group might be a path: | |
if (file.indexOf(absoluteThresholdGroup) === 0) { | |
groupTypeByThresholdGroup[thresholdGroup] = | |
THRESHOLD_GROUP_TYPES.PATH; | |
return agg.concat([[file, thresholdGroup]]); | |
} // If the threshold group is not a path it might be a glob: | |
// Note: glob.sync is slow. By memoizing the files matching each glob | |
// (rather than recalculating it for each covered file) we save a tonne | |
// of execution time. | |
if (filesByGlob[absoluteThresholdGroup] === undefined) { | |
filesByGlob[absoluteThresholdGroup] = _glob() | |
.default.sync(absoluteThresholdGroup) | |
.map(filePath => path().resolve(filePath)); | |
} | |
if (filesByGlob[absoluteThresholdGroup].indexOf(file) > -1) { | |
groupTypeByThresholdGroup[thresholdGroup] = | |
THRESHOLD_GROUP_TYPES.GLOB; | |
return agg.concat([[file, thresholdGroup]]); | |
} | |
return agg; | |
}, | |
[] | |
); | |
if (pathOrGlobMatches.length > 0) { | |
return files.concat(pathOrGlobMatches); | |
} // Neither a glob or a path? Toss it in global if there's a global threshold: | |
if (thresholdGroups.indexOf(THRESHOLD_GROUP_TYPES.GLOBAL) > -1) { | |
groupTypeByThresholdGroup[THRESHOLD_GROUP_TYPES.GLOBAL] = | |
THRESHOLD_GROUP_TYPES.GLOBAL; | |
return files.concat([[file, THRESHOLD_GROUP_TYPES.GLOBAL]]); | |
} // A covered file that doesn't have a threshold: | |
return files.concat([[file, undefined]]); | |
}, | |
[] | |
); | |
const getFilesInThresholdGroup = thresholdGroup => | |
coveredFilesSortedIntoThresholdGroup | |
.filter(fileAndGroup => fileAndGroup[1] === thresholdGroup) | |
.map(fileAndGroup => fileAndGroup[0]); | |
function combineCoverage(filePaths) { | |
return filePaths | |
.map(filePath => map.fileCoverageFor(filePath)) | |
.reduce((combinedCoverage, nextFileCoverage) => { | |
if (combinedCoverage === undefined || combinedCoverage === null) { | |
return nextFileCoverage.toSummary(); | |
} | |
return combinedCoverage.merge(nextFileCoverage.toSummary()); | |
}, undefined); | |
} | |
let errors = []; | |
thresholdGroups.forEach(thresholdGroup => { | |
switch (groupTypeByThresholdGroup[thresholdGroup]) { | |
case THRESHOLD_GROUP_TYPES.GLOBAL: { | |
const coverage = combineCoverage( | |
getFilesInThresholdGroup(THRESHOLD_GROUP_TYPES.GLOBAL) | |
); | |
if (coverage) { | |
errors = errors.concat( | |
check( | |
thresholdGroup, | |
coverageThreshold[thresholdGroup], | |
coverage | |
) | |
); | |
} | |
break; | |
} | |
case THRESHOLD_GROUP_TYPES.PATH: { | |
const coverage = combineCoverage( | |
getFilesInThresholdGroup(thresholdGroup) | |
); | |
if (coverage) { | |
errors = errors.concat( | |
check( | |
thresholdGroup, | |
coverageThreshold[thresholdGroup], | |
coverage | |
) | |
); | |
} | |
break; | |
} | |
case THRESHOLD_GROUP_TYPES.GLOB: | |
getFilesInThresholdGroup(thresholdGroup).forEach( | |
fileMatchingGlob => { | |
errors = errors.concat( | |
check( | |
fileMatchingGlob, | |
coverageThreshold[thresholdGroup], | |
map.fileCoverageFor(fileMatchingGlob).toSummary() | |
) | |
); | |
} | |
); | |
break; | |
default: | |
// If the file specified by path is not found, error is returned. | |
if (thresholdGroup !== THRESHOLD_GROUP_TYPES.GLOBAL) { | |
errors = errors.concat( | |
`Jest: Coverage data for ${thresholdGroup} was not found.` | |
); | |
} | |
// Sometimes all files in the coverage data are matched by | |
// PATH and GLOB threshold groups in which case, don't error when | |
// the global threshold group doesn't match any files. | |
} | |
}); | |
errors = errors.filter( | |
err => err !== undefined && err !== null && err.length > 0 | |
); | |
if (errors.length > 0) { | |
this.log(`${FAIL_COLOR(errors.join('\n'))}`); | |
this._setError(new Error(errors.join('\n'))); | |
} | |
} | |
} | |
async _getCoverageResult() { | |
if (this._globalConfig.coverageProvider === 'v8') { | |
const mergedCoverages = (0, _v8Coverage().mergeProcessCovs)( | |
this._v8CoverageResults.map(cov => ({ | |
result: cov.map(r => r.result) | |
})) | |
); | |
const fileTransforms = new Map(); | |
this._v8CoverageResults.forEach(res => | |
res.forEach(r => { | |
if (r.codeTransformResult && !fileTransforms.has(r.result.url)) { | |
fileTransforms.set(r.result.url, r.codeTransformResult); | |
} | |
}) | |
); | |
const transformedCoverage = await Promise.all( | |
mergedCoverages.result.map(async res => { | |
var _fileTransform$wrappe; | |
const fileTransform = fileTransforms.get(res.url); | |
let sourcemapContent = undefined; | |
if ( | |
fileTransform !== null && | |
fileTransform !== void 0 && | |
fileTransform.sourceMapPath && | |
fs().existsSync(fileTransform.sourceMapPath) | |
) { | |
sourcemapContent = JSON.parse( | |
fs().readFileSync(fileTransform.sourceMapPath, 'utf8') | |
); | |
} | |
const converter = (0, _v8ToIstanbul().default)( | |
res.url, | |
(_fileTransform$wrappe = | |
fileTransform === null || fileTransform === void 0 | |
? void 0 | |
: fileTransform.wrapperLength) !== null && | |
_fileTransform$wrappe !== void 0 | |
? _fileTransform$wrappe | |
: 0, | |
fileTransform && sourcemapContent | |
? { | |
originalSource: fileTransform.originalCode, | |
source: fileTransform.code, | |
sourceMap: { | |
sourcemap: { | |
file: res.url, | |
...sourcemapContent | |
} | |
} | |
} | |
: { | |
source: fs().readFileSync(res.url, 'utf8') | |
} | |
); | |
await converter.load(); | |
converter.applyCoverage(res.functions); | |
const istanbulData = converter.toIstanbul(); | |
converter.destroy(); | |
return istanbulData; | |
}) | |
); | |
const map = _istanbulLibCoverage().default.createCoverageMap({}); | |
transformedCoverage.forEach(res => map.merge(res)); | |
const reportContext = _istanbulLibReport().default.createContext({ | |
coverageMap: map, | |
dir: this._globalConfig.coverageDirectory, | |
watermarks: (0, _getWatermarks.default)(this._globalConfig) | |
}); | |
return { | |
map, | |
reportContext | |
}; | |
} | |
const map = await this._sourceMapStore.transformCoverage(this._coverageMap); | |
const reportContext = _istanbulLibReport().default.createContext({ | |
coverageMap: map, | |
dir: this._globalConfig.coverageDirectory, | |
sourceFinder: this._sourceMapStore.sourceFinder, | |
watermarks: (0, _getWatermarks.default)(this._globalConfig) | |
}); | |
return { | |
map, | |
reportContext | |
}; | |
} | |
} | |
exports.default = CoverageReporter; | |
_defineProperty(CoverageReporter, 'filename', __filename); | |