@jest/core
Version:
Delightful JavaScript Testing.
1,447 lines (1,383 loc) • 138 kB
JavaScript
/*!
* /**
* * Copyright (c) Meta Platforms, Inc. and affiliates.
* *
* * This source code is licensed under the MIT license found in the
* * LICENSE file in the root directory of this source tree.
* * /
*/
/******/ (() => { // webpackBootstrap
/******/ "use strict";
/******/ var __webpack_modules__ = ({
/***/ "./package.json":
/***/ ((module) => {
module.exports = /*#__PURE__*/JSON.parse('{"name":"@jest/core","description":"Delightful JavaScript Testing.","version":"30.0.2","main":"./build/index.js","types":"./build/index.d.ts","exports":{".":{"types":"./build/index.d.ts","require":"./build/index.js","import":"./build/index.mjs","default":"./build/index.js"},"./package.json":"./package.json"},"dependencies":{"@jest/console":"workspace:*","@jest/pattern":"workspace:*","@jest/reporters":"workspace:*","@jest/test-result":"workspace:*","@jest/transform":"workspace:*","@jest/types":"workspace:*","@types/node":"*","ansi-escapes":"^4.3.2","chalk":"^4.1.2","ci-info":"^4.2.0","exit-x":"^0.2.2","graceful-fs":"^4.2.11","jest-changed-files":"workspace:*","jest-config":"workspace:*","jest-haste-map":"workspace:*","jest-message-util":"workspace:*","jest-regex-util":"workspace:*","jest-resolve":"workspace:*","jest-resolve-dependencies":"workspace:*","jest-runner":"workspace:*","jest-runtime":"workspace:*","jest-snapshot":"workspace:*","jest-util":"workspace:*","jest-validate":"workspace:*","jest-watcher":"workspace:*","micromatch":"^4.0.8","pretty-format":"workspace:*","slash":"^3.0.0"},"devDependencies":{"@jest/test-sequencer":"workspace:*","@jest/test-utils":"workspace:*","@types/graceful-fs":"^4.1.9","@types/micromatch":"^4.0.9"},"peerDependencies":{"node-notifier":"^8.0.1 || ^9.0.0 || ^10.0.0"},"peerDependenciesMeta":{"node-notifier":{"optional":true}},"engines":{"node":"^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"},"repository":{"type":"git","url":"https://github.com/jestjs/jest.git","directory":"packages/jest-core"},"bugs":{"url":"https://github.com/jestjs/jest/issues"},"homepage":"https://jestjs.io/","license":"MIT","keywords":["ava","babel","coverage","easy","expect","facebook","immersive","instant","jasmine","jest","jsdom","mocha","mocking","painless","qunit","runner","sandboxed","snapshot","tap","tape","test","testing","typescript","watch"],"publishConfig":{"access":"public"}}');
/***/ }),
/***/ "./src/FailedTestsCache.ts":
/***/ ((__unused_webpack_module, exports) => {
Object.defineProperty(exports, "__esModule", ({
value: true
}));
exports["default"] = void 0;
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
class FailedTestsCache {
_enabledTestsMap;
filterTests(tests) {
const enabledTestsMap = this._enabledTestsMap;
if (!enabledTestsMap) {
return tests;
}
return tests.filter(testResult => enabledTestsMap[testResult.path]);
}
setTestResults(testResults) {
this._enabledTestsMap = (testResults || []).reduce((suiteMap, testResult) => {
if (!testResult.numFailingTests) {
return suiteMap;
}
suiteMap[testResult.testFilePath] = testResult.testResults.reduce((testMap, test) => {
if (test.status !== 'failed') {
return testMap;
}
testMap[test.fullName] = true;
return testMap;
}, {});
return suiteMap;
}, {});
this._enabledTestsMap = Object.freeze(this._enabledTestsMap);
}
}
exports["default"] = FailedTestsCache;
/***/ }),
/***/ "./src/FailedTestsInteractiveMode.ts":
/***/ ((__unused_webpack_module, exports) => {
Object.defineProperty(exports, "__esModule", ({
value: true
}));
exports["default"] = void 0;
function _ansiEscapes() {
const data = _interopRequireDefault(require("ansi-escapes"));
_ansiEscapes = function () {
return data;
};
return data;
}
function _chalk() {
const data = _interopRequireDefault(require("chalk"));
_chalk = function () {
return data;
};
return data;
}
function _jestUtil() {
const data = require("jest-util");
_jestUtil = function () {
return data;
};
return data;
}
function _jestWatcher() {
const data = require("jest-watcher");
_jestWatcher = function () {
return data;
};
return data;
}
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const {
ARROW,
CLEAR
} = _jestUtil().specialChars;
function describeKey(key, description) {
return `${_chalk().default.dim(`${ARROW}Press`)} ${key} ${_chalk().default.dim(description)}`;
}
const TestProgressLabel = _chalk().default.bold('Interactive Test Progress');
class FailedTestsInteractiveMode {
_isActive = false;
_countPaths = 0;
_skippedNum = 0;
_testAssertions = [];
_updateTestRunnerConfig;
constructor(_pipe) {
this._pipe = _pipe;
}
isActive() {
return this._isActive;
}
put(key) {
switch (key) {
case 's':
if (this._skippedNum === this._testAssertions.length) {
break;
}
this._skippedNum += 1;
// move skipped test to the end
this._testAssertions.push(this._testAssertions.shift());
if (this._testAssertions.length - this._skippedNum > 0) {
this._run();
} else {
this._drawUIDoneWithSkipped();
}
break;
case 'q':
case _jestWatcher().KEYS.ESCAPE:
this.abort();
break;
case 'r':
this.restart();
break;
case _jestWatcher().KEYS.ENTER:
if (this._testAssertions.length === 0) {
this.abort();
} else {
this._run();
}
break;
default:
}
}
run(failedTestAssertions, updateConfig) {
if (failedTestAssertions.length === 0) return;
this._testAssertions = [...failedTestAssertions];
this._countPaths = this._testAssertions.length;
this._updateTestRunnerConfig = updateConfig;
this._isActive = true;
this._run();
}
updateWithResults(results) {
if (!results.snapshot.failure && results.numFailedTests > 0) {
return this._drawUIOverlay();
}
this._testAssertions.shift();
if (this._testAssertions.length === 0) {
return this._drawUIOverlay();
}
// Go to the next test
return this._run();
}
_clearTestSummary() {
this._pipe.write(_ansiEscapes().default.cursorUp(6));
this._pipe.write(_ansiEscapes().default.eraseDown);
}
_drawUIDone() {
this._pipe.write(CLEAR);
const messages = [_chalk().default.bold('Watch Usage'), describeKey('Enter', 'to return to watch mode.')];
this._pipe.write(`${messages.join('\n')}\n`);
}
_drawUIDoneWithSkipped() {
this._pipe.write(CLEAR);
let stats = `${(0, _jestUtil().pluralize)('test', this._countPaths)} reviewed`;
if (this._skippedNum > 0) {
const skippedText = _chalk().default.bold.yellow(`${(0, _jestUtil().pluralize)('test', this._skippedNum)} skipped`);
stats = `${stats}, ${skippedText}`;
}
const message = [TestProgressLabel, `${ARROW}${stats}`, '\n', _chalk().default.bold('Watch Usage'), describeKey('r', 'to restart Interactive Mode.'), describeKey('q', 'to quit Interactive Mode.'), describeKey('Enter', 'to return to watch mode.')];
this._pipe.write(`\n${message.join('\n')}`);
}
_drawUIProgress() {
this._clearTestSummary();
const numPass = this._countPaths - this._testAssertions.length;
const numRemaining = this._countPaths - numPass - this._skippedNum;
let stats = `${(0, _jestUtil().pluralize)('test', numRemaining)} remaining`;
if (this._skippedNum > 0) {
const skippedText = _chalk().default.bold.yellow(`${(0, _jestUtil().pluralize)('test', this._skippedNum)} skipped`);
stats = `${stats}, ${skippedText}`;
}
const message = [TestProgressLabel, `${ARROW}${stats}`, '\n', _chalk().default.bold('Watch Usage'), describeKey('s', 'to skip the current test.'), describeKey('q', 'to quit Interactive Mode.'), describeKey('Enter', 'to return to watch mode.')];
this._pipe.write(`\n${message.join('\n')}`);
}
_drawUIOverlay() {
if (this._testAssertions.length === 0) return this._drawUIDone();
return this._drawUIProgress();
}
_run() {
if (this._updateTestRunnerConfig) {
this._updateTestRunnerConfig(this._testAssertions[0]);
}
}
abort() {
this._isActive = false;
this._skippedNum = 0;
if (this._updateTestRunnerConfig) {
this._updateTestRunnerConfig();
}
}
restart() {
this._skippedNum = 0;
this._countPaths = this._testAssertions.length;
this._run();
}
}
exports["default"] = FailedTestsInteractiveMode;
/***/ }),
/***/ "./src/ReporterDispatcher.ts":
/***/ ((__unused_webpack_module, exports) => {
Object.defineProperty(exports, "__esModule", ({
value: true
}));
exports["default"] = void 0;
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
class ReporterDispatcher {
_reporters;
constructor() {
this._reporters = [];
}
register(reporter) {
this._reporters.push(reporter);
}
unregister(reporterConstructor) {
this._reporters = this._reporters.filter(reporter => !(reporter instanceof reporterConstructor));
}
async onTestFileResult(test, testResult, results) {
for (const reporter of this._reporters) {
if (reporter.onTestFileResult) {
await reporter.onTestFileResult(test, testResult, results);
} else if (reporter.onTestResult) {
await reporter.onTestResult(test, testResult, results);
}
}
// Release memory if unused later.
testResult.coverage = undefined;
testResult.console = undefined;
}
async onTestFileStart(test) {
for (const reporter of this._reporters) {
if (reporter.onTestFileStart) {
await reporter.onTestFileStart(test);
} else if (reporter.onTestStart) {
await reporter.onTestStart(test);
}
}
}
async onRunStart(results, options) {
for (const reporter of this._reporters) {
if (reporter.onRunStart) {
await reporter.onRunStart(results, options);
}
}
}
async onTestCaseStart(test, testCaseStartInfo) {
for (const reporter of this._reporters) {
if (reporter.onTestCaseStart) {
await reporter.onTestCaseStart(test, testCaseStartInfo);
}
}
}
async onTestCaseResult(test, testCaseResult) {
for (const reporter of this._reporters) {
if (reporter.onTestCaseResult) {
await reporter.onTestCaseResult(test, testCaseResult);
}
}
}
async onRunComplete(testContexts, results) {
for (const reporter of this._reporters) {
if (reporter.onRunComplete) {
await reporter.onRunComplete(testContexts, results);
}
}
}
// Return a list of last errors for every reporter
getErrors() {
return this._reporters.reduce((list, reporter) => {
const error = reporter.getLastError?.();
return error ? [...list, error] : list;
}, []);
}
hasErrors() {
return this.getErrors().length > 0;
}
}
exports["default"] = ReporterDispatcher;
/***/ }),
/***/ "./src/SearchSource.ts":
/***/ ((__unused_webpack_module, exports) => {
Object.defineProperty(exports, "__esModule", ({
value: true
}));
exports["default"] = void 0;
function os() {
const data = _interopRequireWildcard(require("os"));
os = function () {
return data;
};
return data;
}
function path() {
const data = _interopRequireWildcard(require("path"));
path = function () {
return data;
};
return data;
}
function _micromatch() {
const data = _interopRequireDefault(require("micromatch"));
_micromatch = function () {
return data;
};
return data;
}
function _jestConfig() {
const data = require("jest-config");
_jestConfig = function () {
return data;
};
return data;
}
function _jestRegexUtil() {
const data = require("jest-regex-util");
_jestRegexUtil = function () {
return data;
};
return data;
}
function _jestResolveDependencies() {
const data = require("jest-resolve-dependencies");
_jestResolveDependencies = function () {
return data;
};
return data;
}
function _jestSnapshot() {
const data = require("jest-snapshot");
_jestSnapshot = function () {
return data;
};
return data;
}
function _jestUtil() {
const data = require("jest-util");
_jestUtil = function () {
return data;
};
return data;
}
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const regexToMatcher = testRegex => {
const regexes = testRegex.map(testRegex => new RegExp(testRegex));
return path => regexes.some(regex => {
const result = regex.test(path);
// prevent stateful regexes from breaking, just in case
regex.lastIndex = 0;
return result;
});
};
const toTests = (context, tests) => tests.map(path => ({
context,
duration: undefined,
path
}));
const hasSCM = changedFilesInfo => {
const {
repos
} = changedFilesInfo;
// no SCM (git/hg/...) is found in any of the roots.
const noSCM = Object.values(repos).every(scm => scm.size === 0);
return !noSCM;
};
function normalizePosix(filePath) {
return filePath.replaceAll('\\', '/');
}
class SearchSource {
_context;
_dependencyResolver;
_testPathCases = [];
constructor(context) {
const {
config
} = context;
this._context = context;
this._dependencyResolver = null;
const rootPattern = new RegExp(config.roots.map(dir => (0, _jestRegexUtil().escapePathForRegex)(dir + path().sep)).join('|'));
this._testPathCases.push({
isMatch: path => rootPattern.test(path),
stat: 'roots'
});
if (config.testMatch.length > 0) {
this._testPathCases.push({
isMatch: (0, _jestUtil().globsToMatcher)(config.testMatch),
stat: 'testMatch'
});
}
if (config.testPathIgnorePatterns.length > 0) {
const testIgnorePatternsRegex = new RegExp(config.testPathIgnorePatterns.join('|'));
this._testPathCases.push({
isMatch: path => !testIgnorePatternsRegex.test(path),
stat: 'testPathIgnorePatterns'
});
}
if (config.testRegex.length > 0) {
this._testPathCases.push({
isMatch: regexToMatcher(config.testRegex),
stat: 'testRegex'
});
}
}
async _getOrBuildDependencyResolver() {
if (!this._dependencyResolver) {
this._dependencyResolver = new (_jestResolveDependencies().DependencyResolver)(this._context.resolver, this._context.hasteFS, await (0, _jestSnapshot().buildSnapshotResolver)(this._context.config));
}
return this._dependencyResolver;
}
_filterTestPathsWithStats(allPaths, testPathPatternsExecutor) {
const data = {
stats: {
roots: 0,
testMatch: 0,
testPathIgnorePatterns: 0,
testRegex: 0
},
tests: [],
total: allPaths.length
};
const testCases = [...this._testPathCases]; // clone
if (testPathPatternsExecutor.isSet()) {
testCases.push({
isMatch: path => testPathPatternsExecutor.isMatch(path),
stat: 'testPathPatterns'
});
data.stats.testPathPatterns = 0;
}
data.tests = allPaths.filter(test => {
let filterResult = true;
for (const {
isMatch,
stat
} of testCases) {
if (isMatch(test.path)) {
data.stats[stat]++;
} else {
filterResult = false;
}
}
return filterResult;
});
return data;
}
_getAllTestPaths(testPathPatternsExecutor) {
return this._filterTestPathsWithStats(toTests(this._context, this._context.hasteFS.getAllFiles()), testPathPatternsExecutor);
}
isTestFilePath(path) {
return this._testPathCases.every(testCase => testCase.isMatch(path));
}
findMatchingTests(testPathPatternsExecutor) {
return this._getAllTestPaths(testPathPatternsExecutor);
}
async findRelatedTests(allPaths, collectCoverage) {
const dependencyResolver = await this._getOrBuildDependencyResolver();
if (!collectCoverage) {
return {
tests: toTests(this._context, dependencyResolver.resolveInverse(allPaths, this.isTestFilePath.bind(this), {
skipNodeResolution: this._context.config.skipNodeResolution
}))
};
}
const testModulesMap = dependencyResolver.resolveInverseModuleMap(allPaths, this.isTestFilePath.bind(this), {
skipNodeResolution: this._context.config.skipNodeResolution
});
const allPathsAbsolute = new Set([...allPaths].map(p => path().resolve(p)));
const collectCoverageFrom = new Set();
for (const testModule of testModulesMap) {
if (!testModule.dependencies) {
continue;
}
for (const p of testModule.dependencies) {
if (!allPathsAbsolute.has(p)) {
continue;
}
const filename = (0, _jestConfig().replaceRootDirInPath)(this._context.config.rootDir, p);
collectCoverageFrom.add(path().isAbsolute(filename) ? path().relative(this._context.config.rootDir, filename) : filename);
}
}
return {
collectCoverageFrom,
tests: toTests(this._context, testModulesMap.map(testModule => testModule.file))
};
}
findTestsByPaths(paths) {
return {
tests: toTests(this._context, paths.map(p => path().resolve(this._context.config.cwd, p)).filter(this.isTestFilePath.bind(this)))
};
}
async findRelatedTestsFromPattern(paths, collectCoverage) {
if (Array.isArray(paths) && paths.length > 0) {
const resolvedPaths = paths.map(p => path().resolve(this._context.config.cwd, p));
return this.findRelatedTests(new Set(resolvedPaths), collectCoverage);
}
return {
tests: []
};
}
async findTestRelatedToChangedFiles(changedFilesInfo, collectCoverage) {
if (!hasSCM(changedFilesInfo)) {
return {
noSCM: true,
tests: []
};
}
const {
changedFiles
} = changedFilesInfo;
return this.findRelatedTests(changedFiles, collectCoverage);
}
async _getTestPaths(globalConfig, projectConfig, changedFiles) {
if (globalConfig.onlyChanged) {
if (!changedFiles) {
throw new Error('Changed files must be set when running with -o.');
}
return this.findTestRelatedToChangedFiles(changedFiles, globalConfig.collectCoverage);
}
let paths = globalConfig.nonFlagArgs;
if (globalConfig.findRelatedTests && 'win32' === os().platform()) {
paths = this.filterPathsWin32(paths);
}
if (globalConfig.runTestsByPath && paths && paths.length > 0) {
return this.findTestsByPaths(paths);
} else if (globalConfig.findRelatedTests && paths && paths.length > 0) {
return this.findRelatedTestsFromPattern(paths, globalConfig.collectCoverage);
} else {
return this.findMatchingTests(globalConfig.testPathPatterns.toExecutor({
rootDir: projectConfig.rootDir
}));
}
}
filterPathsWin32(paths) {
const allFiles = this._context.hasteFS.getAllFiles();
const options = {
nocase: true,
windows: false
};
paths = paths.map(p => {
// micromatch works with forward slashes: https://github.com/micromatch/micromatch#backslashes
const normalizedPath = normalizePosix(path().resolve(this._context.config.cwd, p));
const match = (0, _micromatch().default)(allFiles.map(normalizePosix), normalizedPath, options);
return match[0];
}).filter(Boolean).map(p => path().resolve(p));
return paths;
}
async getTestPaths(globalConfig, projectConfig, changedFiles, filter) {
const searchResult = await this._getTestPaths(globalConfig, projectConfig, changedFiles);
const filterPath = globalConfig.filter;
if (filter) {
const tests = searchResult.tests;
const filterResult = await filter(tests.map(test => test.path));
if (!Array.isArray(filterResult.filtered)) {
throw new TypeError(`Filter ${filterPath} did not return a valid test list`);
}
const filteredSet = new Set(filterResult.filtered);
return {
...searchResult,
tests: tests.filter(test => filteredSet.has(test.path))
};
}
return searchResult;
}
async findRelatedSourcesFromTestsInChangedFiles(changedFilesInfo) {
if (!hasSCM(changedFilesInfo)) {
return [];
}
const {
changedFiles
} = changedFilesInfo;
const dependencyResolver = await this._getOrBuildDependencyResolver();
const relatedSourcesSet = new Set();
for (const filePath of changedFiles) {
if (this.isTestFilePath(filePath)) {
const sourcePaths = dependencyResolver.resolve(filePath, {
skipNodeResolution: this._context.config.skipNodeResolution
});
for (const sourcePath of sourcePaths) relatedSourcesSet.add(sourcePath);
}
}
return [...relatedSourcesSet];
}
}
exports["default"] = SearchSource;
/***/ }),
/***/ "./src/SnapshotInteractiveMode.ts":
/***/ ((__unused_webpack_module, exports) => {
Object.defineProperty(exports, "__esModule", ({
value: true
}));
exports["default"] = void 0;
function _ansiEscapes() {
const data = _interopRequireDefault(require("ansi-escapes"));
_ansiEscapes = function () {
return data;
};
return data;
}
function _chalk() {
const data = _interopRequireDefault(require("chalk"));
_chalk = function () {
return data;
};
return data;
}
function _jestUtil() {
const data = require("jest-util");
_jestUtil = function () {
return data;
};
return data;
}
function _jestWatcher() {
const data = require("jest-watcher");
_jestWatcher = function () {
return data;
};
return data;
}
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const {
ARROW,
CLEAR
} = _jestUtil().specialChars;
class SnapshotInteractiveMode {
_pipe;
_isActive;
_updateTestRunnerConfig;
_testAssertions;
_countPaths;
_skippedNum;
constructor(pipe) {
this._pipe = pipe;
this._isActive = false;
this._skippedNum = 0;
}
isActive() {
return this._isActive;
}
getSkippedNum() {
return this._skippedNum;
}
_clearTestSummary() {
this._pipe.write(_ansiEscapes().default.cursorUp(6));
this._pipe.write(_ansiEscapes().default.eraseDown);
}
_drawUIProgress() {
this._clearTestSummary();
const numPass = this._countPaths - this._testAssertions.length;
const numRemaining = this._countPaths - numPass - this._skippedNum;
let stats = _chalk().default.bold.dim(`${(0, _jestUtil().pluralize)('snapshot', numRemaining)} remaining`);
if (numPass) {
stats += `, ${_chalk().default.bold.green(`${(0, _jestUtil().pluralize)('snapshot', numPass)} updated`)}`;
}
if (this._skippedNum) {
stats += `, ${_chalk().default.bold.yellow(`${(0, _jestUtil().pluralize)('snapshot', this._skippedNum)} skipped`)}`;
}
const messages = [`\n${_chalk().default.bold('Interactive Snapshot Progress')}`, ARROW + stats, `\n${_chalk().default.bold('Watch Usage')}`, `${_chalk().default.dim(`${ARROW}Press `)}u${_chalk().default.dim(' to update failing snapshots for this test.')}`, `${_chalk().default.dim(`${ARROW}Press `)}s${_chalk().default.dim(' to skip the current test.')}`, `${_chalk().default.dim(`${ARROW}Press `)}q${_chalk().default.dim(' to quit Interactive Snapshot Mode.')}`, `${_chalk().default.dim(`${ARROW}Press `)}Enter${_chalk().default.dim(' to trigger a test run.')}`];
this._pipe.write(`${messages.filter(Boolean).join('\n')}\n`);
}
_drawUIDoneWithSkipped() {
this._pipe.write(CLEAR);
const numPass = this._countPaths - this._testAssertions.length;
let stats = _chalk().default.bold.dim(`${(0, _jestUtil().pluralize)('snapshot', this._countPaths)} reviewed`);
if (numPass) {
stats += `, ${_chalk().default.bold.green(`${(0, _jestUtil().pluralize)('snapshot', numPass)} updated`)}`;
}
if (this._skippedNum) {
stats += `, ${_chalk().default.bold.yellow(`${(0, _jestUtil().pluralize)('snapshot', this._skippedNum)} skipped`)}`;
}
const messages = [`\n${_chalk().default.bold('Interactive Snapshot Result')}`, ARROW + stats, `\n${_chalk().default.bold('Watch Usage')}`, `${_chalk().default.dim(`${ARROW}Press `)}r${_chalk().default.dim(' to restart Interactive Snapshot Mode.')}`, `${_chalk().default.dim(`${ARROW}Press `)}q${_chalk().default.dim(' to quit Interactive Snapshot Mode.')}`];
this._pipe.write(`${messages.filter(Boolean).join('\n')}\n`);
}
_drawUIDone() {
this._pipe.write(CLEAR);
const numPass = this._countPaths - this._testAssertions.length;
let stats = _chalk().default.bold.dim(`${(0, _jestUtil().pluralize)('snapshot', this._countPaths)} reviewed`);
if (numPass) {
stats += `, ${_chalk().default.bold.green(`${(0, _jestUtil().pluralize)('snapshot', numPass)} updated`)}`;
}
const messages = [`\n${_chalk().default.bold('Interactive Snapshot Result')}`, ARROW + stats, `\n${_chalk().default.bold('Watch Usage')}`, `${_chalk().default.dim(`${ARROW}Press `)}Enter${_chalk().default.dim(' to return to watch mode.')}`];
this._pipe.write(`${messages.filter(Boolean).join('\n')}\n`);
}
_drawUIOverlay() {
if (this._testAssertions.length === 0) {
return this._drawUIDone();
}
if (this._testAssertions.length - this._skippedNum === 0) {
return this._drawUIDoneWithSkipped();
}
return this._drawUIProgress();
}
put(key) {
switch (key) {
case 's':
if (this._skippedNum === this._testAssertions.length) break;
this._skippedNum += 1;
// move skipped test to the end
this._testAssertions.push(this._testAssertions.shift());
if (this._testAssertions.length - this._skippedNum > 0) {
this._run(false);
} else {
this._drawUIDoneWithSkipped();
}
break;
case 'u':
this._run(true);
break;
case 'q':
case _jestWatcher().KEYS.ESCAPE:
this.abort();
break;
case 'r':
this.restart();
break;
case _jestWatcher().KEYS.ENTER:
if (this._testAssertions.length === 0) {
this.abort();
} else {
this._run(false);
}
break;
default:
break;
}
}
abort() {
this._isActive = false;
this._skippedNum = 0;
this._updateTestRunnerConfig(null, false);
}
restart() {
this._skippedNum = 0;
this._countPaths = this._testAssertions.length;
this._run(false);
}
updateWithResults(results) {
const hasSnapshotFailure = !!results.snapshot.failure;
if (hasSnapshotFailure) {
this._drawUIOverlay();
return;
}
this._testAssertions.shift();
if (this._testAssertions.length - this._skippedNum === 0) {
this._drawUIOverlay();
return;
}
// Go to the next test
this._run(false);
}
_run(shouldUpdateSnapshot) {
const testAssertion = this._testAssertions[0];
this._updateTestRunnerConfig(testAssertion, shouldUpdateSnapshot);
}
run(failedSnapshotTestAssertions, onConfigChange) {
if (failedSnapshotTestAssertions.length === 0) {
return;
}
this._testAssertions = [...failedSnapshotTestAssertions];
this._countPaths = this._testAssertions.length;
this._updateTestRunnerConfig = onConfigChange;
this._isActive = true;
this._run(false);
}
}
exports["default"] = SnapshotInteractiveMode;
/***/ }),
/***/ "./src/TestNamePatternPrompt.ts":
/***/ ((__unused_webpack_module, exports) => {
Object.defineProperty(exports, "__esModule", ({
value: true
}));
exports["default"] = void 0;
function _jestWatcher() {
const data = require("jest-watcher");
_jestWatcher = function () {
return data;
};
return data;
}
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
class TestNamePatternPrompt extends _jestWatcher().PatternPrompt {
constructor(pipe, prompt) {
super(pipe, prompt, 'tests');
}
_onChange(pattern, options) {
super._onChange(pattern, options);
this._printPrompt(pattern);
}
_printPrompt(pattern) {
const pipe = this._pipe;
(0, _jestWatcher().printPatternCaret)(pattern, pipe);
(0, _jestWatcher().printRestoredPatternCaret)(pattern, this._currentUsageRows, pipe);
}
}
exports["default"] = TestNamePatternPrompt;
/***/ }),
/***/ "./src/TestPathPatternPrompt.ts":
/***/ ((__unused_webpack_module, exports) => {
Object.defineProperty(exports, "__esModule", ({
value: true
}));
exports["default"] = void 0;
function _jestWatcher() {
const data = require("jest-watcher");
_jestWatcher = function () {
return data;
};
return data;
}
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
class TestPathPatternPrompt extends _jestWatcher().PatternPrompt {
constructor(pipe, prompt) {
super(pipe, prompt, 'filenames');
}
_onChange(pattern, options) {
super._onChange(pattern, options);
this._printPrompt(pattern);
}
_printPrompt(pattern) {
const pipe = this._pipe;
(0, _jestWatcher().printPatternCaret)(pattern, pipe);
(0, _jestWatcher().printRestoredPatternCaret)(pattern, this._currentUsageRows, pipe);
}
}
exports["default"] = TestPathPatternPrompt;
/***/ }),
/***/ "./src/TestScheduler.ts":
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
Object.defineProperty(exports, "__esModule", ({
value: true
}));
exports.createTestScheduler = createTestScheduler;
function _chalk() {
const data = _interopRequireDefault(require("chalk"));
_chalk = function () {
return data;
};
return data;
}
function _ciInfo() {
const data = require("ci-info");
_ciInfo = function () {
return data;
};
return data;
}
function _exitX() {
const data = _interopRequireDefault(require("exit-x"));
_exitX = function () {
return data;
};
return data;
}
function _reporters() {
const data = require("@jest/reporters");
_reporters = function () {
return data;
};
return data;
}
function _testResult() {
const data = require("@jest/test-result");
_testResult = function () {
return data;
};
return data;
}
function _transform() {
const data = require("@jest/transform");
_transform = function () {
return data;
};
return data;
}
function _jestMessageUtil() {
const data = require("jest-message-util");
_jestMessageUtil = function () {
return data;
};
return data;
}
function _jestSnapshot() {
const data = require("jest-snapshot");
_jestSnapshot = function () {
return data;
};
return data;
}
function _jestUtil() {
const data = require("jest-util");
_jestUtil = function () {
return data;
};
return data;
}
var _ReporterDispatcher = _interopRequireDefault(__webpack_require__("./src/ReporterDispatcher.ts"));
var _testSchedulerHelper = __webpack_require__("./src/testSchedulerHelper.ts");
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
async function createTestScheduler(globalConfig, context) {
const scheduler = new TestScheduler(globalConfig, context);
await scheduler._setupReporters();
return scheduler;
}
class TestScheduler {
_context;
_dispatcher;
_globalConfig;
constructor(globalConfig, context) {
this._context = context;
this._dispatcher = new _ReporterDispatcher.default();
this._globalConfig = globalConfig;
}
addReporter(reporter) {
this._dispatcher.register(reporter);
}
removeReporter(reporterConstructor) {
this._dispatcher.unregister(reporterConstructor);
}
async scheduleTests(tests, watcher) {
const onTestFileStart = this._dispatcher.onTestFileStart.bind(this._dispatcher);
const timings = [];
const testContexts = new Set();
for (const test of tests) {
testContexts.add(test.context);
if (test.duration) {
timings.push(test.duration);
}
}
const aggregatedResults = createAggregatedResults(tests.length);
const estimatedTime = Math.ceil(getEstimatedTime(timings, this._globalConfig.maxWorkers) / 1000);
const runInBand = (0, _testSchedulerHelper.shouldRunInBand)(tests, timings, this._globalConfig);
const onResult = async (test, testResult) => {
if (watcher.isInterrupted()) {
return;
}
if (testResult.testResults.length === 0) {
const message = 'Your test suite must contain at least one test.';
return onFailure(test, {
message,
stack: new Error(message).stack
});
}
// Throws when the context is leaked after executing a test.
if (testResult.leaks) {
const message = `${_chalk().default.red.bold('EXPERIMENTAL FEATURE!\n')}Your test suite is leaking memory. Please ensure all references are cleaned.\n` + '\n' + 'There is a number of things that can leak memory:\n' + ' - Async operations that have not finished (e.g. fs.readFile).\n' + ' - Timers not properly mocked (e.g. setInterval, setTimeout).\n' + ' - Keeping references to the global scope.';
return onFailure(test, {
message,
stack: new Error(message).stack
});
}
(0, _testResult().addResult)(aggregatedResults, testResult);
await this._dispatcher.onTestFileResult(test, testResult, aggregatedResults);
return this._bailIfNeeded(testContexts, aggregatedResults, watcher);
};
const onFailure = async (test, error) => {
if (watcher.isInterrupted()) {
return;
}
const testResult = (0, _testResult().buildFailureTestResult)(test.path, error);
testResult.failureMessage = (0, _jestMessageUtil().formatExecError)(testResult.testExecError, test.context.config, this._globalConfig, test.path);
(0, _testResult().addResult)(aggregatedResults, testResult);
await this._dispatcher.onTestFileResult(test, testResult, aggregatedResults);
};
const updateSnapshotState = async () => {
const contextsWithSnapshotResolvers = await Promise.all([...testContexts].map(async context => [context, await (0, _jestSnapshot().buildSnapshotResolver)(context.config)]));
for (const [context, snapshotResolver] of contextsWithSnapshotResolvers) {
const status = (0, _jestSnapshot().cleanup)(context.hasteFS, this._globalConfig.updateSnapshot, snapshotResolver, context.config.testPathIgnorePatterns);
aggregatedResults.snapshot.filesRemoved += status.filesRemoved;
aggregatedResults.snapshot.filesRemovedList = [...(aggregatedResults.snapshot.filesRemovedList || []), ...status.filesRemovedList];
}
const updateAll = this._globalConfig.updateSnapshot === 'all';
aggregatedResults.snapshot.didUpdate = updateAll;
aggregatedResults.snapshot.failure = !!(!updateAll && (aggregatedResults.snapshot.unchecked || aggregatedResults.snapshot.unmatched || aggregatedResults.snapshot.filesRemoved));
};
await this._dispatcher.onRunStart(aggregatedResults, {
estimatedTime,
showStatus: !runInBand
});
const testRunners = Object.create(null);
const contextsByTestRunner = new WeakMap();
try {
await Promise.all([...testContexts].map(async context => {
const {
config
} = context;
if (!testRunners[config.runner]) {
const transformer = await (0, _transform().createScriptTransformer)(config);
const Runner = await transformer.requireAndTranspileModule(config.runner);
const runner = new Runner(this._globalConfig, {
changedFiles: this._context.changedFiles,
sourcesRelatedToTestsInChangedFiles: this._context.sourcesRelatedToTestsInChangedFiles
});
testRunners[config.runner] = runner;
contextsByTestRunner.set(runner, context);
}
}));
const testsByRunner = this._partitionTests(testRunners, tests);
if (testsByRunner) {
try {
for (const runner of Object.keys(testRunners)) {
const testRunner = testRunners[runner];
const context = contextsByTestRunner.get(testRunner);
(0, _jestUtil().invariant)(context);
const tests = testsByRunner[runner];
const testRunnerOptions = {
serial: runInBand || Boolean(testRunner.isSerial)
};
if (testRunner.supportsEventEmitters) {
const unsubscribes = [testRunner.on('test-file-start', ([test]) => onTestFileStart(test)), testRunner.on('test-file-success', ([test, testResult]) => onResult(test, testResult)), testRunner.on('test-file-failure', ([test, error]) => onFailure(test, error)), testRunner.on('test-case-start', ([testPath, testCaseStartInfo]) => {
const test = {
context,
path: testPath
};
this._dispatcher.onTestCaseStart(test, testCaseStartInfo);
}), testRunner.on('test-case-result', ([testPath, testCaseResult]) => {
const test = {
context,
path: testPath
};
this._dispatcher.onTestCaseResult(test, testCaseResult);
})];
await testRunner.runTests(tests, watcher, testRunnerOptions);
for (const sub of unsubscribes) sub();
} else {
await testRunner.runTests(tests, watcher, onTestFileStart, onResult, onFailure, testRunnerOptions);
}
}
} catch (error) {
if (!watcher.isInterrupted()) {
throw error;
}
}
}
} catch (error) {
aggregatedResults.runExecError = buildExecError(error);
await this._dispatcher.onRunComplete(testContexts, aggregatedResults);
throw error;
}
await updateSnapshotState();
aggregatedResults.wasInterrupted = watcher.isInterrupted();
await this._dispatcher.onRunComplete(testContexts, aggregatedResults);
const anyTestFailures = !(aggregatedResults.numFailedTests === 0 && aggregatedResults.numRuntimeErrorTestSuites === 0);
const anyReporterErrors = this._dispatcher.hasErrors();
aggregatedResults.success = !(anyTestFailures || aggregatedResults.snapshot.failure || anyReporterErrors);
return aggregatedResults;
}
_partitionTests(testRunners, tests) {
if (Object.keys(testRunners).length > 1) {
return tests.reduce((testRuns, test) => {
const runner = test.context.config.runner;
if (!testRuns[runner]) {
testRuns[runner] = [];
}
testRuns[runner].push(test);
return testRuns;
}, Object.create(null));
} else if (tests.length > 0 && tests[0] != null) {
// If there is only one runner, don't partition the tests.
return Object.assign(Object.create(null), {
[tests[0].context.config.runner]: tests
});
} else {
return null;
}
}
async _setupReporters() {
const {
collectCoverage: coverage,
notify,
verbose
} = this._globalConfig;
const reporters = this._globalConfig.reporters || [['default', {}]];
let summaryOptions = null;
for (const [reporter, options] of reporters) {
switch (reporter) {
case 'default':
summaryOptions = options;
this.addReporter(verbose ? new (_reporters().VerboseReporter)(this._globalConfig) : new (_reporters().DefaultReporter)(this._globalConfig));
break;
case 'github-actions':
if (_ciInfo().GITHUB_ACTIONS) {
this.addReporter(new (_reporters().GitHubActionsReporter)(this._globalConfig, options));
}
break;
case 'summary':
summaryOptions = options;
break;
default:
await this._addCustomReporter(reporter, options);
}
}
if (notify) {
this.addReporter(new (_reporters().NotifyReporter)(this._globalConfig, this._context));
}
if (coverage) {
this.addReporter(new (_reporters().CoverageReporter)(this._globalConfig, this._context));
}
if (summaryOptions != null) {
this.addReporter(new (_reporters().SummaryReporter)(this._globalConfig, summaryOptions));
}
}
async _addCustomReporter(reporter, options) {
try {
const Reporter = await (0, _jestUtil().requireOrImportModule)(reporter);
this.addReporter(new Reporter(this._globalConfig, options, this._context));
} catch (error) {
error.message = `An error occurred while adding the reporter at path "${_chalk().default.bold(reporter)}".\n${error instanceof Error ? error.message : ''}`;
throw error;
}
}
async _bailIfNeeded(testContexts, aggregatedResults, watcher) {
if (this._globalConfig.bail !== 0 && aggregatedResults.numFailedTests >= this._globalConfig.bail) {
if (watcher.isWatchMode()) {
await watcher.setState({
interrupted: true
});
return;
}
try {
await this._dispatcher.onRunComplete(testContexts, aggregatedResults);
} finally {
const exitCode = this._globalConfig.testFailureExitCode;
(0, _exitX().default)(exitCode);
}
}
}
}
const createAggregatedResults = numTotalTestSuites => {
const result = (0, _testResult().makeEmptyAggregatedTestResult)();
result.numTotalTestSuites = numTotalTestSuites;
result.startTime = Date.now();
result.success = false;
return result;
};
const getEstimatedTime = (timings, workers) => {
if (timings.length === 0) {
return 0;
}
const max = Math.max(...timings);
return timings.length <= workers ? max : Math.max(timings.reduce((sum, time) => sum + time) / workers, max);
};
const strToError = errString => {
const {
message,
stack
} = (0, _jestMessageUtil().separateMessageFromStack)(errString);
if (stack.length > 0) {
return {
message,
stack
};
}
const error = new (_jestUtil().ErrorWithStack)(message, buildExecError);
return {
message,
stack: error.stack || ''
};
};
const buildExecError = err => {
if (typeof err === 'string' || err == null) {
return strToError(err || 'Error');
}
const anyErr = err;
if (typeof anyErr.message === 'string') {
if (typeof anyErr.stack === 'string' && anyErr.stack.length > 0) {
return anyErr;
}
return strToError(anyErr.message);
}
return strToError(JSON.stringify(err));
};
/***/ }),
/***/ "./src/cli/index.ts":
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
Object.defineProperty(exports, "__esModule", ({
value: true
}));
exports.runCLI = runCLI;
function _perf_hooks() {
const data = require("perf_hooks");
_perf_hooks = function () {
return data;
};
return data;
}
function _chalk() {
const data = _interopRequireDefault(require("chalk"));
_chalk = function () {
return data;
};
return data;
}
function _exitX() {
const data = _interopRequireDefault(require("exit-x"));
_exitX = function () {
return data;
};
return data;
}
function fs() {
const data = _interopRequireWildcard(require("graceful-fs"));
fs = function () {
return data;
};
return data;
}
function _console() {
const data = require("@jest/console");
_console = function () {
return data;
};
return data;
}
function _jestConfig() {
const data = require("jest-config");
_jestConfig = function () {
return data;
};
return data;
}
function _jestRuntime() {
const data = _interopRequireDefault(require("jest-runtime"));
_jestRuntime = function () {
return data;
};
return data;
}
function _jestUtil() {
const data = require("jest-util");
_jestUtil = function () {
return data;
};
return data;
}
function _jestWatcher() {
const data = require("jest-watcher");
_jestWatcher = function () {
return data;
};
return data;
}
var _collectHandles = __webpack_require__("./src/collectHandles.ts");
var _getChangedFilesPromise = _interopRequireDefault(__webpack_require__("./src/getChangedFilesPromise.ts"));
var _getConfigsOfProjectsToRun = _interopRequireDefault(__webpack_require__("./src/getConfigsOfProjectsToRun.ts"));
var _getProjectNamesMissingWarning = _interopRequireDefault(__webpack_require__("./src/getProjectNamesMissingWarning.ts"));
var _getSelectProjectsMessage = _interopRequireDefault(__webpack_require__("./src/getSelectProjectsMessage.ts"));
var _createContext = _interopRequireDefault(__webpack_require__("./src/lib/createContext.ts"));
var _handleDeprecationWarnings = _interopRequireDefault(__webpack_require__("./src/lib/handleDeprecationWarnings.ts"));
var _logDebugMessages = _interopRequireDefault(__webpack_require__("./src/lib/logDebugMessages.ts"));
var _runJest = _interopRequireDefault(__webpack_require__("./src/runJest.ts"));
var _watch = _interopRequireDefault(__webpack_require__("./src/watch.ts"));
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const {
print: preRunMessagePrint
} = _jestUtil().preRunMessage;
async function runCLI(argv, projects) {
_perf_hooks().performance.mark('jest/runCLI:start');
let results;
// If we output a JSON object, we can't write anything to stdout, since
// it'll break the JSON structure and it won't be valid.
const outputStream = argv.json || argv.useStderr ? process.stderr : process.stdout;
const {
globalConfig,
configs,
hasDeprecationWarnings
} = await (0, _jestConfig().readConfigs)(argv, projects);
if (argv.debug) {
(0, _logDebugMessages.default)(globalConfig, configs, outputStream);
}
if (argv.showConfig) {
(0, _logDebugMessages.default)(globalConfig, configs, process.stdout);
(0, _exitX().default)(0);
}
if (argv.clearCache) {
// stick in a Set to dedupe the deletions
const uniqueConfigDirectories = new Set(configs.map(config => config.cacheDirectory));
for (const cacheDirectory of uniqueConfigDirectories) {
fs().rmSync(cacheDirectory, {
force: true,
recursive: true
});
process.stdout.write(`Cleared ${cacheDirectory}\n`);
}
(0, _exitX().default)(0);
}
const configsOfProjectsToRun = (0, _getConfigsOfProjectsToRun.default)(configs, {
ignoreProjects: argv.ignoreProjects,
selectProjects: argv.selectProjects
});
if (argv.selectProjects || argv.ignoreProjects) {
const namesMissingWarning = (0, _getProjectNamesMissingWarning.default)(configs, {
ignoreProjects: argv.ignoreProjects,
selectProjects: argv.selectProjects
});
if (namesMissingWarning) {
outputStream.write(namesMissingWarning);
}
outputStream.write((0, _getSelectProjectsMessage.default)(configsOfProjectsToRun, {
ignoreProjects: argv.ignoreProjects,
selectProjects: argv.selectProjects
}));
}
await _run10000(globalConfig, configsOfProjectsToRun, hasDeprecationWarnings, outputStream, r => {
results = r;
});
if (argv.watch || argv.watchAll) {
// If in watch mode, return the promise that will never resolve.
// If the watch mode is interrupted, watch should handle the process
// shutdown.
// eslint-disable-next-line @typescript-eslint/no-empty-function
return new Promise(() => {});
}
if (!results) {
throw new Error('AggregatedResult must be present after test run is complete');
}
const {
openHandles
} = results;
if (openHandles && openHandles.length > 0) {
const formatted = (0, _collectHandles.formatHandleErrors)(ope