You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
770 lines
20 KiB
770 lines
20 KiB
2 years ago
|
'use strict';
|
||
|
|
||
|
Object.defineProperty(exports, '__esModule', {
|
||
|
value: true
|
||
|
});
|
||
|
exports.default = watch;
|
||
|
|
||
|
function path() {
|
||
|
const data = _interopRequireWildcard(require('path'));
|
||
|
|
||
|
path = function () {
|
||
|
return data;
|
||
|
};
|
||
|
|
||
|
return data;
|
||
|
}
|
||
|
|
||
|
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 _exit() {
|
||
|
const data = _interopRequireDefault(require('exit'));
|
||
|
|
||
|
_exit = function () {
|
||
|
return data;
|
||
|
};
|
||
|
|
||
|
return data;
|
||
|
}
|
||
|
|
||
|
function _slash() {
|
||
|
const data = _interopRequireDefault(require('slash'));
|
||
|
|
||
|
_slash = function () {
|
||
|
return data;
|
||
|
};
|
||
|
|
||
|
return data;
|
||
|
}
|
||
|
|
||
|
function _jestMessageUtil() {
|
||
|
const data = require('jest-message-util');
|
||
|
|
||
|
_jestMessageUtil = function () {
|
||
|
return data;
|
||
|
};
|
||
|
|
||
|
return data;
|
||
|
}
|
||
|
|
||
|
function _jestUtil() {
|
||
|
const data = require('jest-util');
|
||
|
|
||
|
_jestUtil = function () {
|
||
|
return data;
|
||
|
};
|
||
|
|
||
|
return data;
|
||
|
}
|
||
|
|
||
|
function _jestValidate() {
|
||
|
const data = require('jest-validate');
|
||
|
|
||
|
_jestValidate = function () {
|
||
|
return data;
|
||
|
};
|
||
|
|
||
|
return data;
|
||
|
}
|
||
|
|
||
|
function _jestWatcher() {
|
||
|
const data = require('jest-watcher');
|
||
|
|
||
|
_jestWatcher = function () {
|
||
|
return data;
|
||
|
};
|
||
|
|
||
|
return data;
|
||
|
}
|
||
|
|
||
|
var _FailedTestsCache = _interopRequireDefault(require('./FailedTestsCache'));
|
||
|
|
||
|
var _SearchSource = _interopRequireDefault(require('./SearchSource'));
|
||
|
|
||
|
var _TestWatcher = _interopRequireDefault(require('./TestWatcher'));
|
||
|
|
||
|
var _getChangedFilesPromise = _interopRequireDefault(
|
||
|
require('./getChangedFilesPromise')
|
||
|
);
|
||
|
|
||
|
var _activeFiltersMessage = _interopRequireDefault(
|
||
|
require('./lib/activeFiltersMessage')
|
||
|
);
|
||
|
|
||
|
var _createContext = _interopRequireDefault(require('./lib/createContext'));
|
||
|
|
||
|
var _isValidPath = _interopRequireDefault(require('./lib/isValidPath'));
|
||
|
|
||
|
var _updateGlobalConfig = _interopRequireDefault(
|
||
|
require('./lib/updateGlobalConfig')
|
||
|
);
|
||
|
|
||
|
var _watchPluginsHelpers = require('./lib/watchPluginsHelpers');
|
||
|
|
||
|
var _FailedTestsInteractive = _interopRequireDefault(
|
||
|
require('./plugins/FailedTestsInteractive')
|
||
|
);
|
||
|
|
||
|
var _Quit = _interopRequireDefault(require('./plugins/Quit'));
|
||
|
|
||
|
var _TestNamePattern = _interopRequireDefault(
|
||
|
require('./plugins/TestNamePattern')
|
||
|
);
|
||
|
|
||
|
var _TestPathPattern = _interopRequireDefault(
|
||
|
require('./plugins/TestPathPattern')
|
||
|
);
|
||
|
|
||
|
var _UpdateSnapshots = _interopRequireDefault(
|
||
|
require('./plugins/UpdateSnapshots')
|
||
|
);
|
||
|
|
||
|
var _UpdateSnapshotsInteractive = _interopRequireDefault(
|
||
|
require('./plugins/UpdateSnapshotsInteractive')
|
||
|
);
|
||
|
|
||
|
var _runJest = _interopRequireDefault(require('./runJest'));
|
||
|
|
||
|
function _interopRequireDefault(obj) {
|
||
|
return obj && obj.__esModule ? obj : {default: obj};
|
||
|
}
|
||
|
|
||
|
function _getRequireWildcardCache(nodeInterop) {
|
||
|
if (typeof WeakMap !== 'function') return null;
|
||
|
var cacheBabelInterop = new WeakMap();
|
||
|
var cacheNodeInterop = new WeakMap();
|
||
|
return (_getRequireWildcardCache = function (nodeInterop) {
|
||
|
return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
|
||
|
})(nodeInterop);
|
||
|
}
|
||
|
|
||
|
function _interopRequireWildcard(obj, nodeInterop) {
|
||
|
if (!nodeInterop && obj && obj.__esModule) {
|
||
|
return obj;
|
||
|
}
|
||
|
if (obj === null || (typeof obj !== 'object' && typeof obj !== 'function')) {
|
||
|
return {default: obj};
|
||
|
}
|
||
|
var cache = _getRequireWildcardCache(nodeInterop);
|
||
|
if (cache && cache.has(obj)) {
|
||
|
return cache.get(obj);
|
||
|
}
|
||
|
var newObj = {};
|
||
|
var hasPropertyDescriptor =
|
||
|
Object.defineProperty && Object.getOwnPropertyDescriptor;
|
||
|
for (var key in obj) {
|
||
|
if (key !== 'default' && Object.prototype.hasOwnProperty.call(obj, key)) {
|
||
|
var desc = hasPropertyDescriptor
|
||
|
? Object.getOwnPropertyDescriptor(obj, key)
|
||
|
: null;
|
||
|
if (desc && (desc.get || desc.set)) {
|
||
|
Object.defineProperty(newObj, key, desc);
|
||
|
} else {
|
||
|
newObj[key] = obj[key];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
newObj.default = obj;
|
||
|
if (cache) {
|
||
|
cache.set(obj, newObj);
|
||
|
}
|
||
|
return newObj;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 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 {print: preRunMessagePrint} = _jestUtil().preRunMessage;
|
||
|
|
||
|
let hasExitListener = false;
|
||
|
const INTERNAL_PLUGINS = [
|
||
|
_FailedTestsInteractive.default,
|
||
|
_TestPathPattern.default,
|
||
|
_TestNamePattern.default,
|
||
|
_UpdateSnapshots.default,
|
||
|
_UpdateSnapshotsInteractive.default,
|
||
|
_Quit.default
|
||
|
];
|
||
|
const RESERVED_KEY_PLUGINS = new Map([
|
||
|
[
|
||
|
_UpdateSnapshots.default,
|
||
|
{
|
||
|
forbiddenOverwriteMessage: 'updating snapshots',
|
||
|
key: 'u'
|
||
|
}
|
||
|
],
|
||
|
[
|
||
|
_UpdateSnapshotsInteractive.default,
|
||
|
{
|
||
|
forbiddenOverwriteMessage: 'updating snapshots interactively',
|
||
|
key: 'i'
|
||
|
}
|
||
|
],
|
||
|
[
|
||
|
_Quit.default,
|
||
|
{
|
||
|
forbiddenOverwriteMessage: 'quitting watch mode'
|
||
|
}
|
||
|
]
|
||
|
]);
|
||
|
|
||
|
async function watch(
|
||
|
initialGlobalConfig,
|
||
|
contexts,
|
||
|
outputStream,
|
||
|
hasteMapInstances,
|
||
|
stdin = process.stdin,
|
||
|
hooks = new (_jestWatcher().JestHook)(),
|
||
|
filter
|
||
|
) {
|
||
|
// `globalConfig` will be constantly updated and reassigned as a result of
|
||
|
// watch mode interactions.
|
||
|
let globalConfig = initialGlobalConfig;
|
||
|
let activePlugin;
|
||
|
globalConfig = (0, _updateGlobalConfig.default)(globalConfig, {
|
||
|
mode: globalConfig.watch ? 'watch' : 'watchAll',
|
||
|
passWithNoTests: true
|
||
|
});
|
||
|
|
||
|
const updateConfigAndRun = ({
|
||
|
bail,
|
||
|
changedSince,
|
||
|
collectCoverage,
|
||
|
collectCoverageFrom,
|
||
|
collectCoverageOnlyFrom,
|
||
|
coverageDirectory,
|
||
|
coverageReporters,
|
||
|
findRelatedTests,
|
||
|
mode,
|
||
|
nonFlagArgs,
|
||
|
notify,
|
||
|
notifyMode,
|
||
|
onlyFailures,
|
||
|
reporters,
|
||
|
testNamePattern,
|
||
|
testPathPattern,
|
||
|
updateSnapshot,
|
||
|
verbose
|
||
|
} = {}) => {
|
||
|
const previousUpdateSnapshot = globalConfig.updateSnapshot;
|
||
|
globalConfig = (0, _updateGlobalConfig.default)(globalConfig, {
|
||
|
bail,
|
||
|
changedSince,
|
||
|
collectCoverage,
|
||
|
collectCoverageFrom,
|
||
|
collectCoverageOnlyFrom,
|
||
|
coverageDirectory,
|
||
|
coverageReporters,
|
||
|
findRelatedTests,
|
||
|
mode,
|
||
|
nonFlagArgs,
|
||
|
notify,
|
||
|
notifyMode,
|
||
|
onlyFailures,
|
||
|
reporters,
|
||
|
testNamePattern,
|
||
|
testPathPattern,
|
||
|
updateSnapshot,
|
||
|
verbose
|
||
|
});
|
||
|
startRun(globalConfig);
|
||
|
globalConfig = (0, _updateGlobalConfig.default)(globalConfig, {
|
||
|
// updateSnapshot is not sticky after a run.
|
||
|
updateSnapshot:
|
||
|
previousUpdateSnapshot === 'all' ? 'none' : previousUpdateSnapshot
|
||
|
});
|
||
|
};
|
||
|
|
||
|
const watchPlugins = INTERNAL_PLUGINS.map(
|
||
|
InternalPlugin =>
|
||
|
new InternalPlugin({
|
||
|
stdin,
|
||
|
stdout: outputStream
|
||
|
})
|
||
|
);
|
||
|
watchPlugins.forEach(plugin => {
|
||
|
const hookSubscriber = hooks.getSubscriber();
|
||
|
|
||
|
if (plugin.apply) {
|
||
|
plugin.apply(hookSubscriber);
|
||
|
}
|
||
|
});
|
||
|
|
||
|
if (globalConfig.watchPlugins != null) {
|
||
|
const watchPluginKeys = new Map();
|
||
|
|
||
|
for (const plugin of watchPlugins) {
|
||
|
const reservedInfo = RESERVED_KEY_PLUGINS.get(plugin.constructor) || {};
|
||
|
const key = reservedInfo.key || getPluginKey(plugin, globalConfig);
|
||
|
|
||
|
if (!key) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
const {forbiddenOverwriteMessage} = reservedInfo;
|
||
|
watchPluginKeys.set(key, {
|
||
|
forbiddenOverwriteMessage,
|
||
|
overwritable: forbiddenOverwriteMessage == null,
|
||
|
plugin
|
||
|
});
|
||
|
}
|
||
|
|
||
|
for (const pluginWithConfig of globalConfig.watchPlugins) {
|
||
|
let plugin;
|
||
|
|
||
|
try {
|
||
|
const ThirdPartyPlugin = await (0, _jestUtil().requireOrImportModule)(
|
||
|
pluginWithConfig.path
|
||
|
);
|
||
|
plugin = new ThirdPartyPlugin({
|
||
|
config: pluginWithConfig.config,
|
||
|
stdin,
|
||
|
stdout: outputStream
|
||
|
});
|
||
|
} catch (error) {
|
||
|
const errorWithContext = new Error(
|
||
|
`Failed to initialize watch plugin "${_chalk().default.bold(
|
||
|
(0, _slash().default)(
|
||
|
path().relative(process.cwd(), pluginWithConfig.path)
|
||
|
)
|
||
|
)}":\n\n${(0, _jestMessageUtil().formatExecError)(
|
||
|
error,
|
||
|
contexts[0].config,
|
||
|
{
|
||
|
noStackTrace: false
|
||
|
}
|
||
|
)}`
|
||
|
);
|
||
|
delete errorWithContext.stack;
|
||
|
return Promise.reject(errorWithContext);
|
||
|
}
|
||
|
|
||
|
checkForConflicts(watchPluginKeys, plugin, globalConfig);
|
||
|
const hookSubscriber = hooks.getSubscriber();
|
||
|
|
||
|
if (plugin.apply) {
|
||
|
plugin.apply(hookSubscriber);
|
||
|
}
|
||
|
|
||
|
watchPlugins.push(plugin);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
const failedTestsCache = new _FailedTestsCache.default();
|
||
|
let searchSources = contexts.map(context => ({
|
||
|
context,
|
||
|
searchSource: new _SearchSource.default(context)
|
||
|
}));
|
||
|
let isRunning = false;
|
||
|
let testWatcher;
|
||
|
let shouldDisplayWatchUsage = true;
|
||
|
let isWatchUsageDisplayed = false;
|
||
|
|
||
|
const emitFileChange = () => {
|
||
|
if (hooks.isUsed('onFileChange')) {
|
||
|
const projects = searchSources.map(({context, searchSource}) => ({
|
||
|
config: context.config,
|
||
|
testPaths: searchSource.findMatchingTests('').tests.map(t => t.path)
|
||
|
}));
|
||
|
hooks.getEmitter().onFileChange({
|
||
|
projects
|
||
|
});
|
||
|
}
|
||
|
};
|
||
|
|
||
|
emitFileChange();
|
||
|
hasteMapInstances.forEach((hasteMapInstance, index) => {
|
||
|
hasteMapInstance.on('change', ({eventsQueue, hasteFS, moduleMap}) => {
|
||
|
const validPaths = eventsQueue.filter(({filePath}) =>
|
||
|
(0, _isValidPath.default)(globalConfig, filePath)
|
||
|
);
|
||
|
|
||
|
if (validPaths.length) {
|
||
|
const context = (contexts[index] = (0, _createContext.default)(
|
||
|
contexts[index].config,
|
||
|
{
|
||
|
hasteFS,
|
||
|
moduleMap
|
||
|
}
|
||
|
));
|
||
|
activePlugin = null;
|
||
|
searchSources = searchSources.slice();
|
||
|
searchSources[index] = {
|
||
|
context,
|
||
|
searchSource: new _SearchSource.default(context)
|
||
|
};
|
||
|
emitFileChange();
|
||
|
startRun(globalConfig);
|
||
|
}
|
||
|
});
|
||
|
});
|
||
|
|
||
|
if (!hasExitListener) {
|
||
|
hasExitListener = true;
|
||
|
process.on('exit', () => {
|
||
|
if (activePlugin) {
|
||
|
outputStream.write(_ansiEscapes().default.cursorDown());
|
||
|
outputStream.write(_ansiEscapes().default.eraseDown);
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
|
||
|
const startRun = globalConfig => {
|
||
|
if (isRunning) {
|
||
|
return Promise.resolve(null);
|
||
|
}
|
||
|
|
||
|
testWatcher = new _TestWatcher.default({
|
||
|
isWatchMode: true
|
||
|
});
|
||
|
_jestUtil().isInteractive &&
|
||
|
outputStream.write(_jestUtil().specialChars.CLEAR);
|
||
|
preRunMessagePrint(outputStream);
|
||
|
isRunning = true;
|
||
|
const configs = contexts.map(context => context.config);
|
||
|
const changedFilesPromise = (0, _getChangedFilesPromise.default)(
|
||
|
globalConfig,
|
||
|
configs
|
||
|
);
|
||
|
return (0, _runJest.default)({
|
||
|
changedFilesPromise,
|
||
|
contexts,
|
||
|
failedTestsCache,
|
||
|
filter,
|
||
|
globalConfig,
|
||
|
jestHooks: hooks.getEmitter(),
|
||
|
onComplete: results => {
|
||
|
isRunning = false;
|
||
|
hooks.getEmitter().onTestRunComplete(results); // Create a new testWatcher instance so that re-runs won't be blocked.
|
||
|
// The old instance that was passed to Jest will still be interrupted
|
||
|
// and prevent test runs from the previous run.
|
||
|
|
||
|
testWatcher = new _TestWatcher.default({
|
||
|
isWatchMode: true
|
||
|
}); // Do not show any Watch Usage related stuff when running in a
|
||
|
// non-interactive environment
|
||
|
|
||
|
if (_jestUtil().isInteractive) {
|
||
|
if (shouldDisplayWatchUsage) {
|
||
|
outputStream.write(usage(globalConfig, watchPlugins));
|
||
|
shouldDisplayWatchUsage = false; // hide Watch Usage after first run
|
||
|
|
||
|
isWatchUsageDisplayed = true;
|
||
|
} else {
|
||
|
outputStream.write(showToggleUsagePrompt());
|
||
|
shouldDisplayWatchUsage = false;
|
||
|
isWatchUsageDisplayed = false;
|
||
|
}
|
||
|
} else {
|
||
|
outputStream.write('\n');
|
||
|
}
|
||
|
|
||
|
failedTestsCache.setTestResults(results.testResults);
|
||
|
},
|
||
|
outputStream,
|
||
|
startRun,
|
||
|
testWatcher
|
||
|
}).catch(
|
||
|
(
|
||
|
error // Errors thrown inside `runJest`, e.g. by resolvers, are caught here for
|
||
|
) =>
|
||
|
// continuous watch mode execution. We need to reprint them to the
|
||
|
// terminal and give just a little bit of extra space so they fit below
|
||
|
// `preRunMessagePrint` message nicely.
|
||
|
console.error(
|
||
|
'\n\n' +
|
||
|
(0, _jestMessageUtil().formatExecError)(error, contexts[0].config, {
|
||
|
noStackTrace: false
|
||
|
})
|
||
|
)
|
||
|
);
|
||
|
};
|
||
|
|
||
|
const onKeypress = key => {
|
||
|
if (
|
||
|
key === _jestWatcher().KEYS.CONTROL_C ||
|
||
|
key === _jestWatcher().KEYS.CONTROL_D
|
||
|
) {
|
||
|
if (typeof stdin.setRawMode === 'function') {
|
||
|
stdin.setRawMode(false);
|
||
|
}
|
||
|
|
||
|
outputStream.write('\n');
|
||
|
(0, _exit().default)(0);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (activePlugin != null && activePlugin.onKey) {
|
||
|
// if a plugin is activate, Jest should let it handle keystrokes, so ignore
|
||
|
// them here
|
||
|
activePlugin.onKey(key);
|
||
|
return;
|
||
|
} // Abort test run
|
||
|
|
||
|
const pluginKeys = (0, _watchPluginsHelpers.getSortedUsageRows)(
|
||
|
watchPlugins,
|
||
|
globalConfig
|
||
|
).map(usage => Number(usage.key).toString(16));
|
||
|
|
||
|
if (
|
||
|
isRunning &&
|
||
|
testWatcher &&
|
||
|
['q', _jestWatcher().KEYS.ENTER, 'a', 'o', 'f']
|
||
|
.concat(pluginKeys)
|
||
|
.includes(key)
|
||
|
) {
|
||
|
testWatcher.setState({
|
||
|
interrupted: true
|
||
|
});
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
const matchingWatchPlugin = (0,
|
||
|
_watchPluginsHelpers.filterInteractivePlugins)(
|
||
|
watchPlugins,
|
||
|
globalConfig
|
||
|
).find(plugin => getPluginKey(plugin, globalConfig) === key);
|
||
|
|
||
|
if (matchingWatchPlugin != null) {
|
||
|
if (isRunning) {
|
||
|
testWatcher.setState({
|
||
|
interrupted: true
|
||
|
});
|
||
|
return;
|
||
|
} // "activate" the plugin, which has jest ignore keystrokes so the plugin
|
||
|
// can handle them
|
||
|
|
||
|
activePlugin = matchingWatchPlugin;
|
||
|
|
||
|
if (activePlugin.run) {
|
||
|
activePlugin.run(globalConfig, updateConfigAndRun).then(
|
||
|
shouldRerun => {
|
||
|
activePlugin = null;
|
||
|
|
||
|
if (shouldRerun) {
|
||
|
updateConfigAndRun();
|
||
|
}
|
||
|
},
|
||
|
() => {
|
||
|
activePlugin = null;
|
||
|
onCancelPatternPrompt();
|
||
|
}
|
||
|
);
|
||
|
} else {
|
||
|
activePlugin = null;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
switch (key) {
|
||
|
case _jestWatcher().KEYS.ENTER:
|
||
|
startRun(globalConfig);
|
||
|
break;
|
||
|
|
||
|
case 'a':
|
||
|
globalConfig = (0, _updateGlobalConfig.default)(globalConfig, {
|
||
|
mode: 'watchAll',
|
||
|
testNamePattern: '',
|
||
|
testPathPattern: ''
|
||
|
});
|
||
|
startRun(globalConfig);
|
||
|
break;
|
||
|
|
||
|
case 'c':
|
||
|
updateConfigAndRun({
|
||
|
mode: 'watch',
|
||
|
testNamePattern: '',
|
||
|
testPathPattern: ''
|
||
|
});
|
||
|
break;
|
||
|
|
||
|
case 'f':
|
||
|
globalConfig = (0, _updateGlobalConfig.default)(globalConfig, {
|
||
|
onlyFailures: !globalConfig.onlyFailures
|
||
|
});
|
||
|
startRun(globalConfig);
|
||
|
break;
|
||
|
|
||
|
case 'o':
|
||
|
globalConfig = (0, _updateGlobalConfig.default)(globalConfig, {
|
||
|
mode: 'watch',
|
||
|
testNamePattern: '',
|
||
|
testPathPattern: ''
|
||
|
});
|
||
|
startRun(globalConfig);
|
||
|
break;
|
||
|
|
||
|
case '?':
|
||
|
break;
|
||
|
|
||
|
case 'w':
|
||
|
if (!shouldDisplayWatchUsage && !isWatchUsageDisplayed) {
|
||
|
outputStream.write(_ansiEscapes().default.cursorUp());
|
||
|
outputStream.write(_ansiEscapes().default.eraseDown);
|
||
|
outputStream.write(usage(globalConfig, watchPlugins));
|
||
|
isWatchUsageDisplayed = true;
|
||
|
shouldDisplayWatchUsage = false;
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
const onCancelPatternPrompt = () => {
|
||
|
outputStream.write(_ansiEscapes().default.cursorHide);
|
||
|
outputStream.write(_jestUtil().specialChars.CLEAR);
|
||
|
outputStream.write(usage(globalConfig, watchPlugins));
|
||
|
outputStream.write(_ansiEscapes().default.cursorShow);
|
||
|
};
|
||
|
|
||
|
if (typeof stdin.setRawMode === 'function') {
|
||
|
stdin.setRawMode(true);
|
||
|
stdin.resume();
|
||
|
stdin.setEncoding('utf8');
|
||
|
stdin.on('data', onKeypress);
|
||
|
}
|
||
|
|
||
|
startRun(globalConfig);
|
||
|
return Promise.resolve();
|
||
|
}
|
||
|
|
||
|
const checkForConflicts = (watchPluginKeys, plugin, globalConfig) => {
|
||
|
const key = getPluginKey(plugin, globalConfig);
|
||
|
|
||
|
if (!key) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
const conflictor = watchPluginKeys.get(key);
|
||
|
|
||
|
if (!conflictor || conflictor.overwritable) {
|
||
|
watchPluginKeys.set(key, {
|
||
|
overwritable: false,
|
||
|
plugin
|
||
|
});
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
let error;
|
||
|
|
||
|
if (conflictor.forbiddenOverwriteMessage) {
|
||
|
error = `
|
||
|
Watch plugin ${_chalk().default.bold.red(
|
||
|
getPluginIdentifier(plugin)
|
||
|
)} attempted to register key ${_chalk().default.bold.red(`<${key}>`)},
|
||
|
that is reserved internally for ${_chalk().default.bold.red(
|
||
|
conflictor.forbiddenOverwriteMessage
|
||
|
)}.
|
||
|
Please change the configuration key for this plugin.`.trim();
|
||
|
} else {
|
||
|
const plugins = [conflictor.plugin, plugin]
|
||
|
.map(p => _chalk().default.bold.red(getPluginIdentifier(p)))
|
||
|
.join(' and ');
|
||
|
error = `
|
||
|
Watch plugins ${plugins} both attempted to register key ${_chalk().default.bold.red(
|
||
|
`<${key}>`
|
||
|
)}.
|
||
|
Please change the key configuration for one of the conflicting plugins to avoid overlap.`.trim();
|
||
|
}
|
||
|
|
||
|
throw new (_jestValidate().ValidationError)(
|
||
|
'Watch plugin configuration error',
|
||
|
error
|
||
|
);
|
||
|
};
|
||
|
|
||
|
const getPluginIdentifier = (
|
||
|
plugin // This breaks as `displayName` is not defined as a static, but since
|
||
|
) =>
|
||
|
// WatchPlugin is an interface, and it is my understanding interface
|
||
|
// static fields are not definable anymore, no idea how to circumvent
|
||
|
// this :-(
|
||
|
// @ts-expect-error: leave `displayName` be.
|
||
|
plugin.constructor.displayName || plugin.constructor.name;
|
||
|
|
||
|
const getPluginKey = (plugin, globalConfig) => {
|
||
|
if (typeof plugin.getUsageInfo === 'function') {
|
||
|
return (
|
||
|
plugin.getUsageInfo(globalConfig) || {
|
||
|
key: null
|
||
|
}
|
||
|
).key;
|
||
|
}
|
||
|
|
||
|
return null;
|
||
|
};
|
||
|
|
||
|
const usage = (globalConfig, watchPlugins, delimiter = '\n') => {
|
||
|
const messages = [
|
||
|
(0, _activeFiltersMessage.default)(globalConfig),
|
||
|
globalConfig.testPathPattern || globalConfig.testNamePattern
|
||
|
? _chalk().default.dim(' \u203A Press ') +
|
||
|
'c' +
|
||
|
_chalk().default.dim(' to clear filters.')
|
||
|
: null,
|
||
|
'\n' + _chalk().default.bold('Watch Usage'),
|
||
|
globalConfig.watch
|
||
|
? _chalk().default.dim(' \u203A Press ') +
|
||
|
'a' +
|
||
|
_chalk().default.dim(' to run all tests.')
|
||
|
: null,
|
||
|
globalConfig.onlyFailures
|
||
|
? _chalk().default.dim(' \u203A Press ') +
|
||
|
'f' +
|
||
|
_chalk().default.dim(' to quit "only failed tests" mode.')
|
||
|
: _chalk().default.dim(' \u203A Press ') +
|
||
|
'f' +
|
||
|
_chalk().default.dim(' to run only failed tests.'),
|
||
|
(globalConfig.watchAll ||
|
||
|
globalConfig.testPathPattern ||
|
||
|
globalConfig.testNamePattern) &&
|
||
|
!globalConfig.noSCM
|
||
|
? _chalk().default.dim(' \u203A Press ') +
|
||
|
'o' +
|
||
|
_chalk().default.dim(' to only run tests related to changed files.')
|
||
|
: null,
|
||
|
...(0, _watchPluginsHelpers.getSortedUsageRows)(
|
||
|
watchPlugins,
|
||
|
globalConfig
|
||
|
).map(
|
||
|
plugin =>
|
||
|
_chalk().default.dim(' \u203A Press') +
|
||
|
' ' +
|
||
|
plugin.key +
|
||
|
' ' +
|
||
|
_chalk().default.dim(`to ${plugin.prompt}.`)
|
||
|
),
|
||
|
_chalk().default.dim(' \u203A Press ') +
|
||
|
'Enter' +
|
||
|
_chalk().default.dim(' to trigger a test run.')
|
||
|
];
|
||
|
return messages.filter(message => !!message).join(delimiter) + '\n';
|
||
|
};
|
||
|
|
||
|
const showToggleUsagePrompt = () =>
|
||
|
'\n' +
|
||
|
_chalk().default.bold('Watch Usage: ') +
|
||
|
_chalk().default.dim('Press ') +
|
||
|
'w' +
|
||
|
_chalk().default.dim(' to show more.');
|