UNPKG

@jest/core

Version:

Delightful JavaScript Testing.

1,447 lines (1,383 loc) 138 kB
/*! * /** * * 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.0-rc.1","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