From 1a93a6d548763c88c6606502ff413410deaecb02 Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Sun, 3 Mar 2019 20:18:59 +0100 Subject: [PATCH] --wip-- [skip ci] --- packages/jest-reporters/build/Status.js | 225 ++++++++ .../jest-reporters/build/base_reporter.js | 53 ++ .../jest-reporters/build/coverage_reporter.js | 515 ++++++++++++++++++ .../jest-reporters/build/coverage_worker.js | 58 ++ .../jest-reporters/build/default_reporter.js | 253 +++++++++ .../build/generateEmptyCoverage.js | 73 +++ .../jest-reporters/build/get_result_header.js | 75 +++ .../build/get_snapshot_status.js | 115 ++++ .../build/get_snapshot_summary.js | 195 +++++++ packages/jest-reporters/build/index.js | 57 ++ .../jest-reporters/build/notify_reporter.js | 221 ++++++++ .../jest-reporters/build/summary_reporter.js | 260 +++++++++ packages/jest-reporters/build/utils.js | 343 ++++++++++++ .../jest-reporters/build/verbose_reporter.js | 227 ++++++++ 14 files changed, 2670 insertions(+) create mode 100644 packages/jest-reporters/build/Status.js create mode 100644 packages/jest-reporters/build/base_reporter.js create mode 100644 packages/jest-reporters/build/coverage_reporter.js create mode 100644 packages/jest-reporters/build/coverage_worker.js create mode 100644 packages/jest-reporters/build/default_reporter.js create mode 100644 packages/jest-reporters/build/generateEmptyCoverage.js create mode 100644 packages/jest-reporters/build/get_result_header.js create mode 100644 packages/jest-reporters/build/get_snapshot_status.js create mode 100644 packages/jest-reporters/build/get_snapshot_summary.js create mode 100644 packages/jest-reporters/build/index.js create mode 100644 packages/jest-reporters/build/notify_reporter.js create mode 100644 packages/jest-reporters/build/summary_reporter.js create mode 100644 packages/jest-reporters/build/utils.js create mode 100644 packages/jest-reporters/build/verbose_reporter.js diff --git a/packages/jest-reporters/build/Status.js b/packages/jest-reporters/build/Status.js new file mode 100644 index 000000000000..2be9fd56e992 --- /dev/null +++ b/packages/jest-reporters/build/Status.js @@ -0,0 +1,225 @@ +'use strict'; + +Object.defineProperty(exports, '__esModule', { + value: true +}); +exports.default = void 0; + +function _chalk() { + const data = _interopRequireDefault(require('chalk')); + + _chalk = function _chalk() { + return data; + }; + + return data; +} + +function _stringLength() { + const data = _interopRequireDefault(require('string-length')); + + _stringLength = function _stringLength() { + return data; + }; + + return data; +} + +var _utils = require('./utils'); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : {default: obj}; +} + +/** + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * + */ +const RUNNING_TEXT = ' RUNS '; +const RUNNING = _chalk().default.reset.inverse.yellow.bold(RUNNING_TEXT) + ' '; +/** + * This class is a perf optimization for sorting the list of currently + * running tests. It tries to keep tests in the same positions without + * shifting the whole list. + */ + +class CurrentTestList { + constructor() { + this._array = []; + } + + add(testPath, config) { + const index = this._array.indexOf(null); + + const record = { + config, + testPath + }; + + if (index !== -1) { + this._array[index] = record; + } else { + this._array.push(record); + } + } + + delete(testPath) { + const record = this._array.find( + record => record && record.testPath === testPath + ); + + this._array[this._array.indexOf(record || null)] = null; + } + + get() { + return this._array; + } +} +/** + * A class that generates the CLI status of currently running tests + * and also provides an ANSI escape sequence to remove status lines + * from the terminal. + */ + +class Status { + constructor() { + this._cache = null; + this._currentTests = new CurrentTestList(); + this._done = false; + this._emitScheduled = false; + this._estimatedTime = 0; + this._height = 0; + this._showStatus = false; + } + + onChange(callback) { + this._callback = callback; + } + + runStarted(aggregatedResults, options) { + this._estimatedTime = (options && options.estimatedTime) || 0; + this._showStatus = options && options.showStatus; + this._interval = setInterval(() => this._tick(), 1000); + this._aggregatedResults = aggregatedResults; + + this._debouncedEmit(); + } + + runFinished() { + this._done = true; + clearInterval(this._interval); + + this._emit(); + } + + testStarted(testPath, config) { + this._currentTests.add(testPath, config); + + if (!this._showStatus) { + this._emit(); + } else { + this._debouncedEmit(); + } + } + + testFinished(config, testResult, aggregatedResults) { + const testFilePath = testResult.testFilePath; + this._aggregatedResults = aggregatedResults; + + this._currentTests.delete(testFilePath); + + this._debouncedEmit(); + } + + get() { + if (this._cache) { + return this._cache; + } + + if (this._done) { + return { + clear: '', + content: '' + }; + } // $FlowFixMe + + const width = process.stdout.columns; + let content = '\n'; + + this._currentTests.get().forEach(record => { + if (record) { + const config = record.config, + testPath = record.testPath; + const projectDisplayName = config.displayName + ? (0, _utils.printDisplayName)(config) + ' ' + : ''; + const prefix = RUNNING + projectDisplayName; + content += + (0, _utils.wrapAnsiString)( + prefix + + (0, _utils.trimAndFormatPath)( + (0, _stringLength().default)(prefix), + config, + testPath, + width + ), + width + ) + '\n'; + } + }); + + if (this._showStatus && this._aggregatedResults) { + content += + '\n' + + (0, _utils.getSummary)(this._aggregatedResults, { + estimatedTime: this._estimatedTime, + roundTime: true, + width + }); + } + + let height = 0; + + for (let i = 0; i < content.length; i++) { + if (content[i] === '\n') { + height++; + } + } + + const clear = '\r\x1B[K\r\x1B[1A'.repeat(height); + return (this._cache = { + clear, + content + }); + } + + _emit() { + this._cache = null; + this._lastUpdated = Date.now(); + + this._callback(); + } + + _debouncedEmit() { + if (!this._emitScheduled) { + // Perf optimization to avoid two separate renders When + // one test finishes and another test starts executing. + this._emitScheduled = true; + setTimeout(() => { + this._emit(); + + this._emitScheduled = false; + }, 100); + } + } + + _tick() { + this._debouncedEmit(); + } +} + +exports.default = Status; diff --git a/packages/jest-reporters/build/base_reporter.js b/packages/jest-reporters/build/base_reporter.js new file mode 100644 index 000000000000..d04e4223dee7 --- /dev/null +++ b/packages/jest-reporters/build/base_reporter.js @@ -0,0 +1,53 @@ +'use strict'; + +Object.defineProperty(exports, '__esModule', { + value: true +}); +exports.default = void 0; + +function _jestUtil() { + const data = require('jest-util'); + + _jestUtil = function _jestUtil() { + return data; + }; + + return data; +} + +/** + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * + */ +const preRunMessageRemove = _jestUtil().preRunMessage.remove; + +class BaseReporter { + log(message) { + process.stderr.write(message + '\n'); + } + + onRunStart(results, options) { + preRunMessageRemove(process.stderr); + } + + onTestResult(test, testResult, results) {} + + onTestStart(test) {} + + onRunComplete(contexts, aggregatedResults) {} + + _setError(error) { + this._error = error; + } // Return an error that occurred during reporting. This error will + // define whether the test run was successful or failed. + + getLastError() { + return this._error; + } +} + +exports.default = BaseReporter; diff --git a/packages/jest-reporters/build/coverage_reporter.js b/packages/jest-reporters/build/coverage_reporter.js new file mode 100644 index 000000000000..47514835a083 --- /dev/null +++ b/packages/jest-reporters/build/coverage_reporter.js @@ -0,0 +1,515 @@ +'use strict'; + +Object.defineProperty(exports, '__esModule', { + value: true +}); +exports.default = void 0; + +function _jestUtil() { + const data = require('jest-util'); + + _jestUtil = function _jestUtil() { + return data; + }; + + return data; +} + +function _istanbulApi() { + const data = require('istanbul-api'); + + _istanbulApi = function _istanbulApi() { + return data; + }; + + return data; +} + +function _chalk() { + const data = _interopRequireDefault(require('chalk')); + + _chalk = function _chalk() { + return data; + }; + + return data; +} + +function _istanbulLibCoverage() { + const data = _interopRequireDefault(require('istanbul-lib-coverage')); + + _istanbulLibCoverage = function _istanbulLibCoverage() { + return data; + }; + + return data; +} + +function _istanbulLibSourceMaps() { + const data = _interopRequireDefault(require('istanbul-lib-source-maps')); + + _istanbulLibSourceMaps = function _istanbulLibSourceMaps() { + return data; + }; + + return data; +} + +function _jestWorker() { + const data = _interopRequireDefault(require('jest-worker')); + + _jestWorker = function _jestWorker() { + return data; + }; + + return data; +} + +var _base_reporter = _interopRequireDefault(require('./base_reporter')); + +function _path() { + const data = _interopRequireDefault(require('path')); + + _path = function _path() { + return data; + }; + + return data; +} + +function _glob() { + const data = _interopRequireDefault(require('glob')); + + _glob = function _glob() { + return data; + }; + + return data; +} + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : {default: obj}; +} + +function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { + try { + var info = gen[key](arg); + var value = info.value; + } catch (error) { + reject(error); + return; + } + if (info.done) { + resolve(value); + } else { + Promise.resolve(value).then(_next, _throw); + } +} + +function _asyncToGenerator(fn) { + return function() { + var self = this, + args = arguments; + return new Promise(function(resolve, reject) { + var gen = fn.apply(self, args); + function _next(value) { + asyncGeneratorStep(gen, resolve, reject, _next, _throw, 'next', value); + } + function _throw(err) { + asyncGeneratorStep(gen, resolve, reject, _next, _throw, 'throw', err); + } + _next(undefined); + }); + }; +} + +const FAIL_COLOR = _chalk().default.bold.red; + +const RUNNING_TEST_COLOR = _chalk().default.bold.dim; + +class CoverageReporter extends _base_reporter.default { + constructor(globalConfig, options) { + super(); + this._coverageMap = _istanbulLibCoverage().default.createCoverageMap({}); + this._globalConfig = globalConfig; + this._sourceMapStore = _istanbulLibSourceMaps().default.createSourceMapStore(); + this._options = options || {}; + } + + onTestResult(test, testResult, aggregatedResults) { + if (testResult.coverage) { + this._coverageMap.merge(testResult.coverage); // Remove coverage data to free up some memory. + + delete testResult.coverage; + Object.keys(testResult.sourceMaps).forEach(sourcePath => { + let inputSourceMap; + + try { + const coverage = this._coverageMap.fileCoverageFor(sourcePath); + + var _coverage$toJSON = coverage.toJSON(); + + inputSourceMap = _coverage$toJSON.inputSourceMap; + } finally { + if (inputSourceMap) { + this._sourceMapStore.registerMap(sourcePath, inputSourceMap); + } else { + this._sourceMapStore.registerURL( + sourcePath, + testResult.sourceMaps[sourcePath] + ); + } + } + }); + } + } + + onRunComplete(contexts, aggregatedResults) { + var _this = this; + + return _asyncToGenerator(function*() { + yield _this._addUntestedFiles(_this._globalConfig, contexts); + + const _this$_sourceMapStore = _this._sourceMapStore.transformCoverage( + _this._coverageMap + ), + map = _this$_sourceMapStore.map, + sourceFinder = _this$_sourceMapStore.sourceFinder; + + const reporter = (0, _istanbulApi().createReporter)(); + + try { + if (_this._globalConfig.coverageDirectory) { + reporter.dir = _this._globalConfig.coverageDirectory; + } + + const coverageReporters = _this._globalConfig.coverageReporters || []; + + if (!_this._globalConfig.useStderr && coverageReporters.length < 1) { + coverageReporters.push('text-summary'); + } + + reporter.addAll(coverageReporters); + reporter.write( + map, + sourceFinder && { + sourceFinder + } + ); + aggregatedResults.coverageMap = map; + } catch (e) { + console.error( + _chalk().default.red(` + Failed to write coverage reports: + ERROR: ${e.toString()} + STACK: ${e.stack} + `) + ); + } + + _this._checkThreshold(_this._globalConfig, map); + })(); + } + + _addUntestedFiles(globalConfig, contexts) { + var _this2 = this; + + return _asyncToGenerator(function*() { + const files = []; + contexts.forEach(context => { + const config = context.config; + + if ( + globalConfig.collectCoverageFrom && + globalConfig.collectCoverageFrom.length + ) { + context.hasteFS + .matchFilesWithGlob( + 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 (_this2._globalConfig.maxWorkers <= 1) { + worker = require('./coverage_worker'); + } else { + worker = new (_jestWorker()).default( + require.resolve('./coverage_worker'), + { + exposedMethods: ['worker'], + maxRetries: 2, + numWorkers: _this2._globalConfig.maxWorkers + } + ); + } + + const instrumentation = files.map( + /*#__PURE__*/ + (function() { + var _ref = _asyncToGenerator(function*(fileObj) { + const filename = fileObj.path; + const config = fileObj.config; + + if (!_this2._coverageMap.data[filename]) { + try { + const result = yield worker.worker({ + config, + globalConfig, + options: _this2._options, + path: filename + }); + + if (result) { + _this2._coverageMap.addFileCoverage(result.coverage); + + if (result.sourceMapPath) { + _this2._sourceMapStore.registerURL( + filename, + result.sourceMapPath + ); + } + } + } catch (error) { + console.error( + _chalk().default.red( + [ + `Failed to collect coverage from ${filename}`, + `ERROR: ${error.message}`, + `STACK: ${error.stack}` + ].join('\n') + ) + ); + } + } + }); + + return function(_x) { + return _ref.apply(this, arguments); + }; + })() + ); + + try { + yield Promise.all(instrumentation); + } catch (err) { + // Do nothing; errors were reported earlier to the console. + } + + if (_jestUtil().isInteractive) { + (0, _jestUtil().clearLine)(process.stderr); + } + + if (worker && typeof worker.end === 'function') { + worker.end(); + } + })(); + } + + _checkThreshold(globalConfig, map) { + if (globalConfig.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 != null) { + 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(globalConfig.coverageThreshold); + const groupTypeByThresholdGroup = {}; + const filesByGlob = {}; + const coveredFilesSortedIntoThresholdGroup = coveredFiles.reduce( + (files, file) => { + const pathOrGlobMatches = thresholdGroups.reduce( + (agg, thresholdGroup) => { + const absoluteThresholdGroup = _path().default.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().default.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, + globalConfig.coverageThreshold[thresholdGroup], + coverage + ) + ); + } + + break; + } + + case THRESHOLD_GROUP_TYPES.PATH: { + const coverage = combineCoverage( + getFilesInThresholdGroup(thresholdGroup) + ); + + if (coverage) { + errors = errors.concat( + check( + thresholdGroup, + globalConfig.coverageThreshold[thresholdGroup], + coverage + ) + ); + } + + break; + } + + case THRESHOLD_GROUP_TYPES.GLOB: + getFilesInThresholdGroup(thresholdGroup).forEach( + fileMatchingGlob => { + errors = errors.concat( + check( + fileMatchingGlob, + globalConfig.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'))); + } + } + } // Only exposed for the internal runner. Should not be used + + getCoverageMap() { + return this._coverageMap; + } +} + +exports.default = CoverageReporter; diff --git a/packages/jest-reporters/build/coverage_worker.js b/packages/jest-reporters/build/coverage_worker.js new file mode 100644 index 000000000000..3dd49e94d3ea --- /dev/null +++ b/packages/jest-reporters/build/coverage_worker.js @@ -0,0 +1,58 @@ +'use strict'; + +Object.defineProperty(exports, '__esModule', { + value: true +}); +exports.worker = worker; + +function _exit() { + const data = _interopRequireDefault(require('exit')); + + _exit = function _exit() { + return data; + }; + + return data; +} + +function _fs() { + const data = _interopRequireDefault(require('fs')); + + _fs = function _fs() { + return data; + }; + + return data; +} + +var _generateEmptyCoverage = _interopRequireDefault( + require('./generateEmptyCoverage') +); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : {default: obj}; +} + +/** + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * + */ +// Make sure uncaught errors are logged before we exit. +process.on('uncaughtException', err => { + console.error(err.stack); + (0, _exit().default)(1); +}); + +function worker({config, globalConfig, path, options}) { + return (0, _generateEmptyCoverage.default)( + _fs().default.readFileSync(path, 'utf8'), + path, + globalConfig, + config, + options && options.changedFiles + ); +} diff --git a/packages/jest-reporters/build/default_reporter.js b/packages/jest-reporters/build/default_reporter.js new file mode 100644 index 000000000000..ead2efde21e2 --- /dev/null +++ b/packages/jest-reporters/build/default_reporter.js @@ -0,0 +1,253 @@ +'use strict'; + +Object.defineProperty(exports, '__esModule', { + value: true +}); +exports.default = void 0; + +function _jestUtil() { + const data = require('jest-util'); + + _jestUtil = function _jestUtil() { + return data; + }; + + return data; +} + +function _chalk() { + const data = _interopRequireDefault(require('chalk')); + + _chalk = function _chalk() { + return data; + }; + + return data; +} + +var _base_reporter = _interopRequireDefault(require('./base_reporter')); + +var _Status = _interopRequireDefault(require('./Status')); + +var _get_result_header = _interopRequireDefault(require('./get_result_header')); + +var _get_snapshot_status = _interopRequireDefault( + require('./get_snapshot_status') +); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : {default: obj}; +} + +/** + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * + */ + +/* global stream$Writable, tty$WriteStream */ +const TITLE_BULLET = _chalk().default.bold('\u25cf '); + +class DefaultReporter extends _base_reporter.default { + // ANSI clear sequence for the last printed status + constructor(globalConfig) { + super(); + this._globalConfig = globalConfig; + this._clear = ''; + this._out = process.stdout.write.bind(process.stdout); + this._err = process.stderr.write.bind(process.stderr); + this._status = new _Status.default(); + this._bufferedOutput = new Set(); + + this._wrapStdio(process.stdout); + + this._wrapStdio(process.stderr); + + this._status.onChange(() => { + this._clearStatus(); + + this._printStatus(); + }); + } + + _wrapStdio(stream) { + const originalWrite = stream.write; + let buffer = []; + let timeout = null; + + const flushBufferedOutput = () => { + const string = buffer.join(''); + buffer = []; // This is to avoid conflicts between random output and status text + + this._clearStatus(); + + if (string) { + originalWrite.call(stream, string); + } + + this._printStatus(); + + this._bufferedOutput.delete(flushBufferedOutput); + }; + + this._bufferedOutput.add(flushBufferedOutput); + + const debouncedFlush = () => { + // If the process blows up no errors would be printed. + // There should be a smart way to buffer stderr, but for now + // we just won't buffer it. + if (stream === process.stderr) { + flushBufferedOutput(); + } else { + if (!timeout) { + timeout = setTimeout(() => { + flushBufferedOutput(); + timeout = null; + }, 100); + } + } + }; // $FlowFixMe + + stream.write = chunk => { + buffer.push(chunk); + debouncedFlush(); + return true; + }; + } // Don't wait for the debounced call and flush all output immediately. + + forceFlushBufferedOutput() { + var _iteratorNormalCompletion = true; + var _didIteratorError = false; + var _iteratorError = undefined; + + try { + for ( + var _iterator = this._bufferedOutput[Symbol.iterator](), _step; + !(_iteratorNormalCompletion = (_step = _iterator.next()).done); + _iteratorNormalCompletion = true + ) { + const flushBufferedOutput = _step.value; + flushBufferedOutput(); + } + } catch (err) { + _didIteratorError = true; + _iteratorError = err; + } finally { + try { + if (!_iteratorNormalCompletion && _iterator.return != null) { + _iterator.return(); + } + } finally { + if (_didIteratorError) { + throw _iteratorError; + } + } + } + } + + _clearStatus() { + if (_jestUtil().isInteractive) { + if (this._globalConfig.useStderr) { + this._err(this._clear); + } else { + this._out(this._clear); + } + } + } + + _printStatus() { + const _this$_status$get = this._status.get(), + content = _this$_status$get.content, + clear = _this$_status$get.clear; + + this._clear = clear; + + if (_jestUtil().isInteractive) { + if (this._globalConfig.useStderr) { + this._err(content); + } else { + this._out(content); + } + } + } + + onRunStart(aggregatedResults, options) { + this._status.runStarted(aggregatedResults, options); + } + + onTestStart(test) { + this._status.testStarted(test.path, test.context.config); + } + + onRunComplete() { + this.forceFlushBufferedOutput(); + + this._status.runFinished(); // $FlowFixMe + + process.stdout.write = this._out; // $FlowFixMe + + process.stderr.write = this._err; + (0, _jestUtil().clearLine)(process.stderr); + } + + onTestResult(test, testResult, aggregatedResults) { + this.testFinished(test.context.config, testResult, aggregatedResults); + + if (!testResult.skipped) { + this.printTestFileHeader( + testResult.testFilePath, + test.context.config, + testResult + ); + this.printTestFileFailureMessage( + testResult.testFilePath, + test.context.config, + testResult + ); + } + + this.forceFlushBufferedOutput(); + } + + testFinished(config, testResult, aggregatedResults) { + this._status.testFinished(config, testResult, aggregatedResults); + } + + printTestFileHeader(testPath, config, result) { + this.log( + (0, _get_result_header.default)(result, this._globalConfig, config) + ); + const consoleBuffer = result.console; + + if (consoleBuffer && consoleBuffer.length) { + this.log( + ' ' + + TITLE_BULLET + + 'Console\n\n' + + (0, _jestUtil().getConsoleOutput)( + config.cwd, + !!this._globalConfig.verbose, + consoleBuffer + ) + ); + } + } + + printTestFileFailureMessage(testPath, config, result) { + if (result.failureMessage) { + this.log(result.failureMessage); + } + + const didUpdate = this._globalConfig.updateSnapshot === 'all'; + const snapshotStatuses = (0, _get_snapshot_status.default)( + result.snapshot, + didUpdate + ); + snapshotStatuses.forEach(this.log); + } +} + +exports.default = DefaultReporter; diff --git a/packages/jest-reporters/build/generateEmptyCoverage.js b/packages/jest-reporters/build/generateEmptyCoverage.js new file mode 100644 index 000000000000..59e564dc7ce3 --- /dev/null +++ b/packages/jest-reporters/build/generateEmptyCoverage.js @@ -0,0 +1,73 @@ +'use strict'; + +Object.defineProperty(exports, '__esModule', { + value: true +}); +exports.default = _default; + +function _istanbulLibInstrument() { + const data = require('istanbul-lib-instrument'); + + _istanbulLibInstrument = function _istanbulLibInstrument() { + return data; + }; + + return data; +} + +function _istanbulLibCoverage() { + const data = require('istanbul-lib-coverage'); + + _istanbulLibCoverage = function _istanbulLibCoverage() { + return data; + }; + + return data; +} + +function _transform() { + const data = require('@jest/transform'); + + _transform = function _transform() { + return data; + }; + + return data; +} + +/** + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * + */ +const FileCoverage = _istanbulLibCoverage().classes.FileCoverage; + +function _default(source, filename, globalConfig, config, changedFiles) { + const coverageOptions = { + changedFiles, + collectCoverage: globalConfig.collectCoverage, + collectCoverageFrom: globalConfig.collectCoverageFrom, + collectCoverageOnlyFrom: globalConfig.collectCoverageOnlyFrom + }; + + if ((0, _transform().shouldInstrument)(filename, coverageOptions, config)) { + // Transform file with instrumentation to make sure initial coverage data is well mapped to original code. + const _transformSource = new (_transform()).ScriptTransformer( + config + ).transformSource(filename, source, true), + code = _transformSource.code, + mapCoverage = _transformSource.mapCoverage, + sourceMapPath = _transformSource.sourceMapPath; + + const extracted = (0, _istanbulLibInstrument().readInitialCoverage)(code); + return { + coverage: new FileCoverage(extracted.coverageData), + sourceMapPath: mapCoverage ? sourceMapPath : null + }; + } else { + return null; + } +} diff --git a/packages/jest-reporters/build/get_result_header.js b/packages/jest-reporters/build/get_result_header.js new file mode 100644 index 000000000000..2e5ec69b21f9 --- /dev/null +++ b/packages/jest-reporters/build/get_result_header.js @@ -0,0 +1,75 @@ +'use strict'; + +Object.defineProperty(exports, '__esModule', { + value: true +}); +exports.default = void 0; + +function _chalk() { + const data = _interopRequireDefault(require('chalk')); + + _chalk = function _chalk() { + return data; + }; + + return data; +} + +var _utils = require('./utils'); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : {default: obj}; +} + +/** + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * + */ +const LONG_TEST_COLOR = _chalk().default.reset.bold.bgRed; // Explicitly reset for these messages since they can get written out in the +// middle of error logging + +const FAIL_TEXT = 'FAIL'; +const PASS_TEXT = 'PASS'; +const FAIL = _chalk().default.supportsColor + ? _chalk().default.reset.inverse.bold.red(` ${FAIL_TEXT} `) + : FAIL_TEXT; +const PASS = _chalk().default.supportsColor + ? _chalk().default.reset.inverse.bold.green(` ${PASS_TEXT} `) + : PASS_TEXT; + +var _default = (result, globalConfig, projectConfig) => { + const testPath = result.testFilePath; + const status = + result.numFailingTests > 0 || result.testExecError ? FAIL : PASS; + const runTime = result.perfStats + ? (result.perfStats.end - result.perfStats.start) / 1000 + : null; + const testDetail = []; + + if (runTime !== null && runTime > 5) { + testDetail.push(LONG_TEST_COLOR(runTime + 's')); + } + + if (result.memoryUsage) { + const toMB = bytes => Math.floor(bytes / 1024 / 1024); + + testDetail.push(`${toMB(result.memoryUsage)} MB heap size`); + } + + const projectDisplayName = + projectConfig && projectConfig.displayName + ? (0, _utils.printDisplayName)(projectConfig) + ' ' + : ''; + return ( + `${status} ${projectDisplayName}${(0, _utils.formatTestPath)( + projectConfig ? projectConfig : globalConfig, + testPath + )}` + (testDetail.length ? ` (${testDetail.join(', ')})` : '') + ); +}; + +exports.default = _default; diff --git a/packages/jest-reporters/build/get_snapshot_status.js b/packages/jest-reporters/build/get_snapshot_status.js new file mode 100644 index 000000000000..5f7ce81a657d --- /dev/null +++ b/packages/jest-reporters/build/get_snapshot_status.js @@ -0,0 +1,115 @@ +'use strict'; + +Object.defineProperty(exports, '__esModule', { + value: true +}); +exports.default = void 0; + +function _chalk() { + const data = _interopRequireDefault(require('chalk')); + + _chalk = function _chalk() { + return data; + }; + + return data; +} + +function _jestUtil() { + const data = require('jest-util'); + + _jestUtil = function _jestUtil() { + return data; + }; + + return data; +} + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : {default: obj}; +} + +/** + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * + */ +const ARROW = ' \u203A '; +const DOT = ' \u2022 '; + +const FAIL_COLOR = _chalk().default.bold.red; + +const SNAPSHOT_ADDED = _chalk().default.bold.green; + +const SNAPSHOT_UPDATED = _chalk().default.bold.green; + +const SNAPSHOT_OUTDATED = _chalk().default.bold.yellow; + +var _default = (snapshot, afterUpdate) => { + const statuses = []; + + if (snapshot.added) { + statuses.push( + SNAPSHOT_ADDED( + ARROW + + (0, _jestUtil().pluralize)('snapshot', snapshot.added) + + ' written.' + ) + ); + } + + if (snapshot.updated) { + statuses.push( + SNAPSHOT_UPDATED( + ARROW + + (0, _jestUtil().pluralize)('snapshot', snapshot.updated) + + ' updated.' + ) + ); + } + + if (snapshot.unmatched) { + statuses.push( + FAIL_COLOR( + ARROW + + (0, _jestUtil().pluralize)('snapshot', snapshot.unmatched) + + ' failed.' + ) + ); + } + + if (snapshot.unchecked) { + if (afterUpdate) { + statuses.push( + SNAPSHOT_UPDATED( + ARROW + + (0, _jestUtil().pluralize)('snapshot', snapshot.unchecked) + + ' removed.' + ) + ); + } else { + statuses.push( + SNAPSHOT_OUTDATED( + ARROW + + (0, _jestUtil().pluralize)('snapshot', snapshot.unchecked) + + ' obsolete' + ) + '.' + ); + } + + snapshot.uncheckedKeys.forEach(key => { + statuses.push(` ${DOT}${key}`); + }); + } + + if (snapshot.fileDeleted) { + statuses.push(SNAPSHOT_UPDATED(ARROW + 'snapshot file removed.')); + } + + return statuses; +}; + +exports.default = _default; diff --git a/packages/jest-reporters/build/get_snapshot_summary.js b/packages/jest-reporters/build/get_snapshot_summary.js new file mode 100644 index 000000000000..c4661a026391 --- /dev/null +++ b/packages/jest-reporters/build/get_snapshot_summary.js @@ -0,0 +1,195 @@ +'use strict'; + +Object.defineProperty(exports, '__esModule', { + value: true +}); +exports.default = void 0; + +function _chalk() { + const data = _interopRequireDefault(require('chalk')); + + _chalk = function _chalk() { + return data; + }; + + return data; +} + +function _jestUtil() { + const data = require('jest-util'); + + _jestUtil = function _jestUtil() { + return data; + }; + + return data; +} + +var _utils = require('./utils'); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : {default: obj}; +} + +/** + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * + */ +const ARROW = ' \u203A '; +const DOWN_ARROW = ' \u21B3 '; +const DOT = ' \u2022 '; + +const FAIL_COLOR = _chalk().default.bold.red; + +const OBSOLETE_COLOR = _chalk().default.bold.yellow; + +const SNAPSHOT_ADDED = _chalk().default.bold.green; + +const SNAPSHOT_NOTE = _chalk().default.dim; + +const SNAPSHOT_REMOVED = _chalk().default.bold.green; + +const SNAPSHOT_SUMMARY = _chalk().default.bold; + +const SNAPSHOT_UPDATED = _chalk().default.bold.green; + +var _default = (snapshots, globalConfig, updateCommand) => { + const summary = []; + summary.push(SNAPSHOT_SUMMARY('Snapshot Summary')); + + if (snapshots.added) { + summary.push( + SNAPSHOT_ADDED( + ARROW + + (0, _jestUtil().pluralize)('snapshot', snapshots.added) + + ' written ' + ) + + `from ${(0, _jestUtil().pluralize)( + 'test suite', + snapshots.filesAdded + )}.` + ); + } + + if (snapshots.unmatched) { + summary.push( + FAIL_COLOR( + `${ARROW}${(0, _jestUtil().pluralize)( + 'snapshot', + snapshots.unmatched + )} failed` + ) + + ` from ${(0, _jestUtil().pluralize)( + 'test suite', + snapshots.filesUnmatched + )}. ` + + SNAPSHOT_NOTE( + 'Inspect your code changes or ' + updateCommand + ' to update them.' + ) + ); + } + + if (snapshots.updated) { + summary.push( + SNAPSHOT_UPDATED( + ARROW + + (0, _jestUtil().pluralize)('snapshot', snapshots.updated) + + ' updated ' + ) + + `from ${(0, _jestUtil().pluralize)( + 'test suite', + snapshots.filesUpdated + )}.` + ); + } + + if (snapshots.filesRemoved) { + if (snapshots.didUpdate) { + summary.push( + SNAPSHOT_REMOVED( + `${ARROW}${(0, _jestUtil().pluralize)( + 'snapshot file', + snapshots.filesRemoved + )} removed ` + ) + + `from ${(0, _jestUtil().pluralize)( + 'test suite', + snapshots.filesRemoved + )}.` + ); + } else { + summary.push( + OBSOLETE_COLOR( + `${ARROW}${(0, _jestUtil().pluralize)( + 'snapshot file', + snapshots.filesRemoved + )} obsolete ` + ) + + `from ${(0, _jestUtil().pluralize)( + 'test suite', + snapshots.filesRemoved + )}. ` + + SNAPSHOT_NOTE( + `To remove ${ + snapshots.filesRemoved === 1 ? 'it' : 'them all' + }, ${updateCommand}.` + ) + ); + } + } + + if (snapshots.unchecked) { + if (snapshots.didUpdate) { + summary.push( + SNAPSHOT_REMOVED( + `${ARROW}${(0, _jestUtil().pluralize)( + 'snapshot', + snapshots.unchecked + )} removed ` + ) + + `from ${(0, _jestUtil().pluralize)( + 'test suite', + snapshots.uncheckedKeysByFile.length + )}.` + ); + } else { + summary.push( + OBSOLETE_COLOR( + `${ARROW}${(0, _jestUtil().pluralize)( + 'snapshot', + snapshots.unchecked + )} obsolete ` + ) + + `from ${(0, _jestUtil().pluralize)( + 'test suite', + snapshots.uncheckedKeysByFile.length + )}. ` + + SNAPSHOT_NOTE( + `To remove ${ + snapshots.unchecked === 1 ? 'it' : 'them all' + }, ${updateCommand}.` + ) + ); + } + + snapshots.uncheckedKeysByFile.forEach(uncheckedFile => { + summary.push( + ` ${DOWN_ARROW}${(0, _utils.formatTestPath)( + globalConfig, + uncheckedFile.filePath + )}` + ); + uncheckedFile.keys.forEach(key => { + summary.push(` ${DOT}${key}`); + }); + }); + } + + return summary; +}; + +exports.default = _default; diff --git a/packages/jest-reporters/build/index.js b/packages/jest-reporters/build/index.js new file mode 100644 index 000000000000..16b0de7ad096 --- /dev/null +++ b/packages/jest-reporters/build/index.js @@ -0,0 +1,57 @@ +'use strict'; + +Object.defineProperty(exports, '__esModule', { + value: true +}); +Object.defineProperty(exports, 'BaseReporter', { + enumerable: true, + get: function get() { + return _base_reporter.default; + } +}); +Object.defineProperty(exports, 'CoverageReporter', { + enumerable: true, + get: function get() { + return _coverage_reporter.default; + } +}); +Object.defineProperty(exports, 'DefaultReporter', { + enumerable: true, + get: function get() { + return _default_reporter.default; + } +}); +Object.defineProperty(exports, 'NotifyReporter', { + enumerable: true, + get: function get() { + return _notify_reporter.default; + } +}); +Object.defineProperty(exports, 'SummaryReporter', { + enumerable: true, + get: function get() { + return _summary_reporter.default; + } +}); +Object.defineProperty(exports, 'VerboseReporter', { + enumerable: true, + get: function get() { + return _verbose_reporter.default; + } +}); + +var _base_reporter = _interopRequireDefault(require('./base_reporter')); + +var _coverage_reporter = _interopRequireDefault(require('./coverage_reporter')); + +var _default_reporter = _interopRequireDefault(require('./default_reporter')); + +var _notify_reporter = _interopRequireDefault(require('./notify_reporter')); + +var _summary_reporter = _interopRequireDefault(require('./summary_reporter')); + +var _verbose_reporter = _interopRequireDefault(require('./verbose_reporter')); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : {default: obj}; +} diff --git a/packages/jest-reporters/build/notify_reporter.js b/packages/jest-reporters/build/notify_reporter.js new file mode 100644 index 000000000000..132c0102bcf7 --- /dev/null +++ b/packages/jest-reporters/build/notify_reporter.js @@ -0,0 +1,221 @@ +'use strict'; + +Object.defineProperty(exports, '__esModule', { + value: true +}); +exports.default = void 0; + +function _exit() { + const data = _interopRequireDefault(require('exit')); + + _exit = function _exit() { + return data; + }; + + return data; +} + +function _path() { + const data = _interopRequireDefault(require('path')); + + _path = function _path() { + return data; + }; + + return data; +} + +function _util() { + const data = _interopRequireDefault(require('util')); + + _util = function _util() { + return data; + }; + + return data; +} + +function _nodeNotifier() { + const data = _interopRequireDefault(require('node-notifier')); + + _nodeNotifier = function _nodeNotifier() { + return data; + }; + + return data; +} + +var _base_reporter = _interopRequireDefault(require('./base_reporter')); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : {default: obj}; +} + +function _slicedToArray(arr, i) { + return ( + _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest() + ); +} + +function _nonIterableRest() { + throw new TypeError('Invalid attempt to destructure non-iterable instance'); +} + +function _iterableToArrayLimit(arr, i) { + var _arr = []; + var _n = true; + var _d = false; + var _e = undefined; + try { + for ( + var _i = arr[Symbol.iterator](), _s; + !(_n = (_s = _i.next()).done); + _n = true + ) { + _arr.push(_s.value); + if (i && _arr.length === i) break; + } + } catch (err) { + _d = true; + _e = err; + } finally { + try { + if (!_n && _i['return'] != null) _i['return'](); + } finally { + if (_d) throw _e; + } + } + return _arr; +} + +function _arrayWithHoles(arr) { + if (Array.isArray(arr)) return arr; +} + +const isDarwin = process.platform === 'darwin'; + +const icon = _path().default.resolve(__dirname, '../assets/jest_logo.png'); + +class NotifyReporter extends _base_reporter.default { + constructor(globalConfig, startRun, context) { + super(); + this._globalConfig = globalConfig; + this._startRun = startRun; + this._context = context; + } + + onRunComplete(contexts, result) { + const success = + result.numFailedTests === 0 && result.numRuntimeErrorTestSuites === 0; + const firstContext = contexts.values().next(); + const hasteFS = + firstContext && firstContext.value && firstContext.value.hasteFS; + let packageName; + + if (hasteFS != null) { + // assuming root package.json is the first one + const _hasteFS$matchFiles = hasteFS.matchFiles('package.json'), + _hasteFS$matchFiles2 = _slicedToArray(_hasteFS$matchFiles, 1), + filePath = _hasteFS$matchFiles2[0]; + + packageName = + filePath != null + ? hasteFS.getModuleName(filePath) + : this._globalConfig.rootDir; + } else { + packageName = this._globalConfig.rootDir; + } + + packageName = packageName != null ? `${packageName} - ` : ''; + const notifyMode = this._globalConfig.notifyMode; + const statusChanged = + this._context.previousSuccess !== success || this._context.firstRun; + const testsHaveRun = result.numTotalTests !== 0; + + if ( + testsHaveRun && + success && + (notifyMode === 'always' || + notifyMode === 'success' || + notifyMode === 'success-change' || + (notifyMode === 'change' && statusChanged) || + (notifyMode === 'failure-change' && statusChanged)) + ) { + const title = _util().default.format('%s%d%% Passed', packageName, 100); + + const message = _util().default.format( + (isDarwin ? '\u2705 ' : '') + '%d tests passed', + result.numPassedTests + ); + + _nodeNotifier().default.notify({ + icon, + message, + title + }); + } else if ( + testsHaveRun && + !success && + (notifyMode === 'always' || + notifyMode === 'failure' || + notifyMode === 'failure-change' || + (notifyMode === 'change' && statusChanged) || + (notifyMode === 'success-change' && statusChanged)) + ) { + const failed = result.numFailedTests / result.numTotalTests; + + const title = _util().default.format( + '%s%d%% Failed', + packageName, + Math.ceil(Number.isNaN(failed) ? 0 : failed * 100) + ); + + const message = _util().default.format( + (isDarwin ? '\u26D4\uFE0F ' : '') + '%d of %d tests failed', + result.numFailedTests, + result.numTotalTests + ); + + const watchMode = this._globalConfig.watch || this._globalConfig.watchAll; + const restartAnswer = 'Run again'; + const quitAnswer = 'Exit tests'; + + if (!watchMode) { + _nodeNotifier().default.notify({ + icon, + message, + title + }); + } else { + _nodeNotifier().default.notify( + { + actions: [restartAnswer, quitAnswer], + closeLabel: 'Close', + icon, + message, + title + }, + (err, _, metadata) => { + if (err || !metadata) { + return; + } + + if (metadata.activationValue === quitAnswer) { + (0, _exit().default)(0); + return; + } + + if (metadata.activationValue === restartAnswer) { + this._startRun(this._globalConfig); + } + } + ); + } + } + + this._context.previousSuccess = success; + this._context.firstRun = false; + } +} + +exports.default = NotifyReporter; diff --git a/packages/jest-reporters/build/summary_reporter.js b/packages/jest-reporters/build/summary_reporter.js new file mode 100644 index 000000000000..f0163e6c3dd4 --- /dev/null +++ b/packages/jest-reporters/build/summary_reporter.js @@ -0,0 +1,260 @@ +'use strict'; + +Object.defineProperty(exports, '__esModule', { + value: true +}); +exports.default = void 0; + +function _chalk() { + const data = _interopRequireDefault(require('chalk')); + + _chalk = function _chalk() { + return data; + }; + + return data; +} + +function _jestUtil() { + const data = require('jest-util'); + + _jestUtil = function _jestUtil() { + return data; + }; + + return data; +} + +var _base_reporter = _interopRequireDefault(require('./base_reporter')); + +var _utils = require('./utils'); + +var _get_result_header = _interopRequireDefault(require('./get_result_header')); + +var _get_snapshot_summary = _interopRequireDefault( + require('./get_snapshot_summary') +); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : {default: obj}; +} + +/** + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * + */ +const TEST_SUMMARY_THRESHOLD = 20; +const NPM_EVENTS = new Set([ + 'prepublish', + 'publish', + 'postpublish', + 'preinstall', + 'install', + 'postinstall', + 'preuninstall', + 'uninstall', + 'postuninstall', + 'preversion', + 'version', + 'postversion', + 'pretest', + 'test', + 'posttest', + 'prestop', + 'stop', + 'poststop', + 'prestart', + 'start', + 'poststart', + 'prerestart', + 'restart', + 'postrestart' +]); + +class SummaryReporter extends _base_reporter.default { + constructor(globalConfig) { + super(); + this._globalConfig = globalConfig; + this._estimatedTime = 0; + } // If we write more than one character at a time it is possible that + // Node.js exits in the middle of printing the result. This was first observed + // in Node.js 0.10 and still persists in Node.js 6.7+. + // Let's print the test failure summary character by character which is safer + // when hundreds of tests are failing. + + _write(string) { + for (let i = 0; i < string.length; i++) { + process.stderr.write(string.charAt(i)); + } + } + + onRunStart(aggregatedResults, options) { + super.onRunStart(aggregatedResults, options); + this._estimatedTime = options.estimatedTime; + } + + onRunComplete(contexts, aggregatedResults) { + const numTotalTestSuites = aggregatedResults.numTotalTestSuites, + testResults = aggregatedResults.testResults, + wasInterrupted = aggregatedResults.wasInterrupted; + + if (numTotalTestSuites) { + const lastResult = testResults[testResults.length - 1]; // Print a newline if the last test did not fail to line up newlines + // similar to when an error would have been thrown in the test. + + if ( + !this._globalConfig.verbose && + lastResult && + !lastResult.numFailingTests && + !lastResult.testExecError + ) { + this.log(''); + } + + this._printSummary(aggregatedResults, this._globalConfig); + + this._printSnapshotSummary( + aggregatedResults.snapshot, + this._globalConfig + ); + + if (numTotalTestSuites) { + let message = (0, _utils.getSummary)(aggregatedResults, { + estimatedTime: this._estimatedTime + }); + + if (!this._globalConfig.silent) { + message += + '\n' + + (wasInterrupted + ? _chalk().default.bold.red('Test run was interrupted.') + : this._getTestSummary(contexts, this._globalConfig)); + } + + this.log(message); + } + } + } + + _printSnapshotSummary(snapshots, globalConfig) { + if ( + snapshots.added || + snapshots.filesRemoved || + snapshots.unchecked || + snapshots.unmatched || + snapshots.updated + ) { + let updateCommand; + const event = process.env.npm_lifecycle_event; + const prefix = NPM_EVENTS.has(event) ? '' : 'run '; + const isYarn = + typeof process.env.npm_config_user_agent === 'string' && + process.env.npm_config_user_agent.match('yarn') !== null; + const client = isYarn ? 'yarn' : 'npm'; + const scriptUsesJest = + typeof process.env.npm_lifecycle_script === 'string' && + process.env.npm_lifecycle_script.indexOf('jest') !== -1; + + if (globalConfig.watch || globalConfig.watchAll) { + updateCommand = 'press `u`'; + } else if (event && scriptUsesJest) { + updateCommand = `run \`${client + + ' ' + + prefix + + event + + (isYarn ? '' : ' --')} -u\``; + } else { + updateCommand = 're-run jest with `-u`'; + } + + const snapshotSummary = (0, _get_snapshot_summary.default)( + snapshots, + globalConfig, + updateCommand + ); + snapshotSummary.forEach(this.log); + this.log(''); // print empty line + } + } + + _printSummary(aggregatedResults, globalConfig) { + // If there were any failing tests and there was a large number of tests + // executed, re-print the failing results at the end of execution output. + const failedTests = aggregatedResults.numFailedTests; + const runtimeErrors = aggregatedResults.numRuntimeErrorTestSuites; + + if ( + failedTests + runtimeErrors > 0 && + aggregatedResults.numTotalTestSuites > TEST_SUMMARY_THRESHOLD + ) { + this.log(_chalk().default.bold('Summary of all failing tests')); + aggregatedResults.testResults.forEach(testResult => { + const failureMessage = testResult.failureMessage; + + if (failureMessage) { + this._write( + (0, _get_result_header.default)(testResult, globalConfig) + + '\n' + + failureMessage + + '\n' + ); + } + }); + this.log(''); // print empty line + } + } + + _getTestSummary(contexts, globalConfig) { + const getMatchingTestsInfo = () => { + const prefix = globalConfig.findRelatedTests + ? ' related to files matching ' + : ' matching '; + return ( + _chalk().default.dim(prefix) + + (0, _jestUtil().testPathPatternToRegExp)( + globalConfig.testPathPattern + ).toString() + ); + }; + + let testInfo = ''; + + if (globalConfig.runTestsByPath) { + testInfo = _chalk().default.dim(' within paths'); + } else if (globalConfig.onlyChanged) { + testInfo = _chalk().default.dim(' related to changed files'); + } else if (globalConfig.testPathPattern) { + testInfo = getMatchingTestsInfo(); + } + + let nameInfo = ''; + + if (globalConfig.runTestsByPath) { + nameInfo = ' ' + globalConfig.nonFlagArgs.map(p => `"${p}"`).join(', '); + } else if (globalConfig.testNamePattern) { + nameInfo = + _chalk().default.dim(' with tests matching ') + + `"${globalConfig.testNamePattern}"`; + } + + const contextInfo = + contexts.size > 1 + ? _chalk().default.dim(' in ') + + contexts.size + + _chalk().default.dim(' projects') + : ''; + return ( + _chalk().default.dim('Ran all test suites') + + testInfo + + nameInfo + + contextInfo + + _chalk().default.dim('.') + ); + } +} + +exports.default = SummaryReporter; diff --git a/packages/jest-reporters/build/utils.js b/packages/jest-reporters/build/utils.js new file mode 100644 index 000000000000..04bd7b9879a8 --- /dev/null +++ b/packages/jest-reporters/build/utils.js @@ -0,0 +1,343 @@ +'use strict'; + +Object.defineProperty(exports, '__esModule', { + value: true +}); +exports.wrapAnsiString = exports.getSummary = exports.relativePath = exports.formatTestPath = exports.trimAndFormatPath = exports.printDisplayName = void 0; + +function _path() { + const data = _interopRequireDefault(require('path')); + + _path = function _path() { + return data; + }; + + return data; +} + +function _chalk() { + const data = _interopRequireDefault(require('chalk')); + + _chalk = function _chalk() { + return data; + }; + + return data; +} + +function _slash() { + const data = _interopRequireDefault(require('slash')); + + _slash = function _slash() { + return data; + }; + + return data; +} + +function _jestUtil() { + const data = require('jest-util'); + + _jestUtil = function _jestUtil() { + return data; + }; + + return data; +} + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : {default: obj}; +} + +/** + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * + */ +const PROGRESS_BAR_WIDTH = 40; + +const printDisplayName = config => { + const displayName = config.displayName; + + if (displayName) { + return _chalk().default.supportsColor + ? _chalk().default.reset.inverse.white(` ${displayName} `) + : displayName; + } + + return ''; +}; + +exports.printDisplayName = printDisplayName; + +const trimAndFormatPath = (pad, config, testPath, columns) => { + const maxLength = columns - pad; + const relative = relativePath(config, testPath); + const basename = relative.basename; + let dirname = relative.dirname; // length is ok + + if ((dirname + _path().default.sep + basename).length <= maxLength) { + return (0, _slash().default)( + _chalk().default.dim(dirname + _path().default.sep) + + _chalk().default.bold(basename) + ); + } // we can fit trimmed dirname and full basename + + const basenameLength = basename.length; + + if (basenameLength + 4 < maxLength) { + const dirnameLength = maxLength - 4 - basenameLength; + dirname = + '...' + dirname.slice(dirname.length - dirnameLength, dirname.length); + return (0, _slash().default)( + _chalk().default.dim(dirname + _path().default.sep) + + _chalk().default.bold(basename) + ); + } + + if (basenameLength + 4 === maxLength) { + return (0, _slash().default)( + _chalk().default.dim('...' + _path().default.sep) + + _chalk().default.bold(basename) + ); + } // can't fit dirname, but can fit trimmed basename + + return (0, _slash().default)( + _chalk().default.bold( + '...' + basename.slice(basename.length - maxLength - 4, basename.length) + ) + ); +}; + +exports.trimAndFormatPath = trimAndFormatPath; + +const formatTestPath = (config, testPath) => { + const _relativePath = relativePath(config, testPath), + dirname = _relativePath.dirname, + basename = _relativePath.basename; + + return (0, _slash().default)( + _chalk().default.dim(dirname + _path().default.sep) + + _chalk().default.bold(basename) + ); +}; + +exports.formatTestPath = formatTestPath; + +const relativePath = (config, testPath) => { + // this function can be called with ProjectConfigs or GlobalConfigs. GlobalConfigs + // do not have config.cwd, only config.rootDir. Try using config.cwd, fallback + // to config.rootDir. (Also, some unit just use config.rootDir, which is ok) + testPath = _path().default.relative(config.cwd || config.rootDir, testPath); + + const dirname = _path().default.dirname(testPath); + + const basename = _path().default.basename(testPath); + + return { + basename, + dirname + }; +}; + +exports.relativePath = relativePath; + +const getSummary = (aggregatedResults, options) => { + let runTime = (Date.now() - aggregatedResults.startTime) / 1000; + + if (options && options.roundTime) { + runTime = Math.floor(runTime); + } + + const estimatedTime = (options && options.estimatedTime) || 0; + const snapshotResults = aggregatedResults.snapshot; + const snapshotsAdded = snapshotResults.added; + const snapshotsFailed = snapshotResults.unmatched; + const snapshotsOutdated = snapshotResults.unchecked; + const snapshotsFilesRemoved = snapshotResults.filesRemoved; + const snapshotsDidUpdate = snapshotResults.didUpdate; + const snapshotsPassed = snapshotResults.matched; + const snapshotsTotal = snapshotResults.total; + const snapshotsUpdated = snapshotResults.updated; + const suitesFailed = aggregatedResults.numFailedTestSuites; + const suitesPassed = aggregatedResults.numPassedTestSuites; + const suitesPending = aggregatedResults.numPendingTestSuites; + const suitesRun = suitesFailed + suitesPassed; + const suitesTotal = aggregatedResults.numTotalTestSuites; + const testsFailed = aggregatedResults.numFailedTests; + const testsPassed = aggregatedResults.numPassedTests; + const testsPending = aggregatedResults.numPendingTests; + const testsTodo = aggregatedResults.numTodoTests; + const testsTotal = aggregatedResults.numTotalTests; + const width = (options && options.width) || 0; + const suites = + _chalk().default.bold('Test Suites: ') + + (suitesFailed + ? _chalk().default.bold.red(`${suitesFailed} failed`) + ', ' + : '') + + (suitesPending + ? _chalk().default.bold.yellow(`${suitesPending} skipped`) + ', ' + : '') + + (suitesPassed + ? _chalk().default.bold.green(`${suitesPassed} passed`) + ', ' + : '') + + (suitesRun !== suitesTotal + ? suitesRun + ' of ' + suitesTotal + : suitesTotal) + + ` total`; + const tests = + _chalk().default.bold('Tests: ') + + (testsFailed + ? _chalk().default.bold.red(`${testsFailed} failed`) + ', ' + : '') + + (testsPending + ? _chalk().default.bold.yellow(`${testsPending} skipped`) + ', ' + : '') + + (testsTodo + ? _chalk().default.bold.magenta(`${testsTodo} todo`) + ', ' + : '') + + (testsPassed + ? _chalk().default.bold.green(`${testsPassed} passed`) + ', ' + : '') + + `${testsTotal} total`; + const snapshots = + _chalk().default.bold('Snapshots: ') + + (snapshotsFailed + ? _chalk().default.bold.red(`${snapshotsFailed} failed`) + ', ' + : '') + + (snapshotsOutdated && !snapshotsDidUpdate + ? _chalk().default.bold.yellow(`${snapshotsOutdated} obsolete`) + ', ' + : '') + + (snapshotsOutdated && snapshotsDidUpdate + ? _chalk().default.bold.green(`${snapshotsOutdated} removed`) + ', ' + : '') + + (snapshotsFilesRemoved && !snapshotsDidUpdate + ? _chalk().default.bold.yellow( + (0, _jestUtil().pluralize)('file', snapshotsFilesRemoved) + + ' obsolete' + ) + ', ' + : '') + + (snapshotsFilesRemoved && snapshotsDidUpdate + ? _chalk().default.bold.green( + (0, _jestUtil().pluralize)('file', snapshotsFilesRemoved) + ' removed' + ) + ', ' + : '') + + (snapshotsUpdated + ? _chalk().default.bold.green(`${snapshotsUpdated} updated`) + ', ' + : '') + + (snapshotsAdded + ? _chalk().default.bold.green(`${snapshotsAdded} written`) + ', ' + : '') + + (snapshotsPassed + ? _chalk().default.bold.green(`${snapshotsPassed} passed`) + ', ' + : '') + + `${snapshotsTotal} total`; + const time = renderTime(runTime, estimatedTime, width); + return [suites, tests, snapshots, time].join('\n'); +}; + +exports.getSummary = getSummary; + +const renderTime = (runTime, estimatedTime, width) => { + // If we are more than one second over the estimated time, highlight it. + const renderedTime = + estimatedTime && runTime >= estimatedTime + 1 + ? _chalk().default.bold.yellow(runTime + 's') + : runTime + 's'; + let time = _chalk().default.bold(`Time:`) + ` ${renderedTime}`; + + if (runTime < estimatedTime) { + time += `, estimated ${estimatedTime}s`; + } // Only show a progress bar if the test run is actually going to take + // some time. + + if (estimatedTime > 2 && runTime < estimatedTime && width) { + const availableWidth = Math.min(PROGRESS_BAR_WIDTH, width); + const length = Math.min( + Math.floor((runTime / estimatedTime) * availableWidth), + availableWidth + ); + + if (availableWidth >= 2) { + time += + '\n' + + _chalk() + .default.green('█') + .repeat(length) + + _chalk() + .default.white('█') + .repeat(availableWidth - length); + } + } + + return time; +}; // word-wrap a string that contains ANSI escape sequences. +// ANSI escape sequences do not add to the string length. + +const wrapAnsiString = (string, terminalWidth) => { + if (terminalWidth === 0) { + // if the terminal width is zero, don't bother word-wrapping + return string; + } + + const ANSI_REGEXP = /[\u001b\u009b]\[\d{1,2}m/g; + const tokens = []; + let lastIndex = 0; + let match; + + while ((match = ANSI_REGEXP.exec(string))) { + const ansi = match[0]; + const index = match['index']; + + if (index != lastIndex) { + tokens.push(['string', string.slice(lastIndex, index)]); + } + + tokens.push(['ansi', ansi]); + lastIndex = index + ansi.length; + } + + if (lastIndex != string.length - 1) { + tokens.push(['string', string.slice(lastIndex, string.length)]); + } + + let lastLineLength = 0; + return tokens + .reduce( + (lines, [kind, token]) => { + if (kind === 'string') { + if (lastLineLength + token.length > terminalWidth) { + while (token.length) { + const chunk = token.slice(0, terminalWidth - lastLineLength); + const remaining = token.slice( + terminalWidth - lastLineLength, + token.length + ); + lines[lines.length - 1] += chunk; + lastLineLength += chunk.length; + token = remaining; + + if (token.length) { + lines.push(''); + lastLineLength = 0; + } + } + } else { + lines[lines.length - 1] += token; + lastLineLength += token.length; + } + } else { + lines[lines.length - 1] += token; + } + + return lines; + }, + [''] + ) + .join('\n'); +}; + +exports.wrapAnsiString = wrapAnsiString; diff --git a/packages/jest-reporters/build/verbose_reporter.js b/packages/jest-reporters/build/verbose_reporter.js new file mode 100644 index 000000000000..7d1d3960d6bb --- /dev/null +++ b/packages/jest-reporters/build/verbose_reporter.js @@ -0,0 +1,227 @@ +'use strict'; + +Object.defineProperty(exports, '__esModule', { + value: true +}); +exports.default = void 0; + +function _chalk() { + const data = _interopRequireDefault(require('chalk')); + + _chalk = function _chalk() { + return data; + }; + + return data; +} + +function _jestUtil() { + const data = require('jest-util'); + + _jestUtil = function _jestUtil() { + return data; + }; + + return data; +} + +var _default_reporter = _interopRequireDefault(require('./default_reporter')); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : {default: obj}; +} + +/** + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * + */ +const ICONS = _jestUtil().specialChars.ICONS; + +class VerboseReporter extends _default_reporter.default { + constructor(globalConfig) { + super(globalConfig); + this._globalConfig = globalConfig; + } + + static filterTestResults(testResults) { + return testResults.filter(({status}) => status !== 'pending'); + } + + static groupTestsBySuites(testResults) { + const root = { + suites: [], + tests: [], + title: '' + }; + testResults.forEach(testResult => { + let targetSuite = root; // Find the target suite for this test, + // creating nested suites as necessary. + + var _iteratorNormalCompletion = true; + var _didIteratorError = false; + var _iteratorError = undefined; + + try { + for ( + var _iterator = testResult.ancestorTitles[Symbol.iterator](), _step; + !(_iteratorNormalCompletion = (_step = _iterator.next()).done); + _iteratorNormalCompletion = true + ) { + const title = _step.value; + let matchingSuite = targetSuite.suites.find(s => s.title === title); + + if (!matchingSuite) { + matchingSuite = { + suites: [], + tests: [], + title + }; + targetSuite.suites.push(matchingSuite); + } + + targetSuite = matchingSuite; + } + } catch (err) { + _didIteratorError = true; + _iteratorError = err; + } finally { + try { + if (!_iteratorNormalCompletion && _iterator.return != null) { + _iterator.return(); + } + } finally { + if (_didIteratorError) { + throw _iteratorError; + } + } + } + + targetSuite.tests.push(testResult); + }); + return root; + } + + onTestResult(test, result, aggregatedResults) { + super.testFinished(test.context.config, result, aggregatedResults); + + if (!result.skipped) { + this.printTestFileHeader( + result.testFilePath, + test.context.config, + result + ); + + if (!result.testExecError && !result.skipped) { + this._logTestResults(result.testResults); + } + + this.printTestFileFailureMessage( + result.testFilePath, + test.context.config, + result + ); + } + + super.forceFlushBufferedOutput(); + } + + _logTestResults(testResults) { + this._logSuite(VerboseReporter.groupTestsBySuites(testResults), 0); + + this._logLine(); + } + + _logSuite(suite, indentLevel) { + if (suite.title) { + this._logLine(suite.title, indentLevel); + } + + this._logTests(suite.tests, indentLevel + 1); + + suite.suites.forEach(suite => this._logSuite(suite, indentLevel + 1)); + } + + _getIcon(status) { + if (status === 'failed') { + return _chalk().default.red(ICONS.failed); + } else if (status === 'pending') { + return _chalk().default.yellow(ICONS.pending); + } else if (status === 'todo') { + return _chalk().default.magenta(ICONS.todo); + } else { + return _chalk().default.green(ICONS.success); + } + } + + _logTest(test, indentLevel) { + const status = this._getIcon(test.status); + + const time = test.duration ? ` (${test.duration.toFixed(0)}ms)` : ''; + + this._logLine( + status + ' ' + _chalk().default.dim(test.title + time), + indentLevel + ); + } + + _logTests(tests, indentLevel) { + if (this._globalConfig.expand) { + tests.forEach(test => this._logTest(test, indentLevel)); + } else { + const summedTests = tests.reduce( + (result, test) => { + if (test.status === 'pending') { + result.pending += 1; + } else if (test.status === 'todo') { + result.todo += 1; + } else { + this._logTest(test, indentLevel); + } + + return result; + }, + { + pending: 0, + todo: 0 + } + ); + + if (summedTests.pending > 0) { + this._logSummedTests( + 'skipped', + this._getIcon('pending'), + summedTests.pending, + indentLevel + ); + } + + if (summedTests.todo > 0) { + this._logSummedTests( + 'todo', + this._getIcon('todo'), + summedTests.todo, + indentLevel + ); + } + } + } + + _logSummedTests(prefix, icon, count, indentLevel) { + const text = _chalk().default.dim( + `${prefix} ${count} test${count === 1 ? '' : 's'}` + ); + + this._logLine(`${icon} ${text}`, indentLevel); + } + + _logLine(str, indentLevel) { + const indentation = ' '.repeat(indentLevel || 0); + this.log(indentation + (str || '')); + } +} + +exports.default = VerboseReporter;