123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776 |
- 'use strict';
- Object.defineProperty(exports, '__esModule', {
- value: true
- });
- exports.default = watch;
- function _path() {
- const data = _interopRequireDefault(require('path'));
- _path = function _path() {
- return data;
- };
- return data;
- }
- function _ansiEscapes() {
- const data = _interopRequireDefault(require('ansi-escapes'));
- _ansiEscapes = function _ansiEscapes() {
- return data;
- };
- return data;
- }
- function _chalk() {
- const data = _interopRequireDefault(require('chalk'));
- _chalk = function _chalk() {
- return data;
- };
- return data;
- }
- function _exit() {
- const data = _interopRequireDefault(require('exit'));
- _exit = function _exit() {
- return data;
- };
- return data;
- }
- function _slash() {
- const data = _interopRequireDefault(require('slash'));
- _slash = function _slash() {
- return data;
- };
- return data;
- }
- function _jestMessageUtil() {
- const data = require('jest-message-util');
- _jestMessageUtil = function _jestMessageUtil() {
- return data;
- };
- return data;
- }
- function _jestUtil() {
- const data = require('jest-util');
- _jestUtil = function _jestUtil() {
- return data;
- };
- return data;
- }
- function _jestValidate() {
- const data = require('jest-validate');
- _jestValidate = function _jestValidate() {
- return data;
- };
- return data;
- }
- function _jestResolve() {
- const data = _interopRequireDefault(require('jest-resolve'));
- _jestResolve = function _jestResolve() {
- return data;
- };
- return data;
- }
- function _jestWatcher() {
- const data = require('jest-watcher');
- _jestWatcher = function _jestWatcher() {
- return data;
- };
- return data;
- }
- var _getChangedFilesPromise = _interopRequireDefault(
- require('./getChangedFilesPromise')
- );
- var _is_valid_path = _interopRequireDefault(require('./lib/is_valid_path'));
- var _create_context = _interopRequireDefault(require('./lib/create_context'));
- var _runJest = _interopRequireDefault(require('./runJest'));
- var _update_global_config = _interopRequireDefault(
- require('./lib/update_global_config')
- );
- var _SearchSource = _interopRequireDefault(require('./SearchSource'));
- var _TestWatcher = _interopRequireDefault(require('./TestWatcher'));
- var _FailedTestsCache = _interopRequireDefault(require('./FailedTestsCache'));
- var _test_path_pattern = _interopRequireDefault(
- require('./plugins/test_path_pattern')
- );
- var _test_name_pattern = _interopRequireDefault(
- require('./plugins/test_name_pattern')
- );
- var _update_snapshots = _interopRequireDefault(
- require('./plugins/update_snapshots')
- );
- var _update_snapshots_interactive = _interopRequireDefault(
- require('./plugins/update_snapshots_interactive')
- );
- var _quit = _interopRequireDefault(require('./plugins/quit'));
- var _watch_plugins_helpers = require('./lib/watch_plugins_helpers');
- var _active_filters_message = _interopRequireDefault(
- require('./lib/active_filters_message')
- );
- function _interopRequireDefault(obj) {
- return obj && obj.__esModule ? obj : {default: obj};
- }
- /**
- * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
- const preRunMessagePrint = _jestUtil().preRunMessage.print;
- let hasExitListener = false;
- const INTERNAL_PLUGINS = [
- _test_path_pattern.default,
- _test_name_pattern.default,
- _update_snapshots.default,
- _update_snapshots_interactive.default,
- _quit.default
- ];
- const RESERVED_KEY_PLUGINS = new Map([
- [
- _update_snapshots.default,
- {
- forbiddenOverwriteMessage: 'updating snapshots',
- key: 'u'
- }
- ],
- [
- _update_snapshots_interactive.default,
- {
- forbiddenOverwriteMessage: 'updating snapshots interactively',
- key: 'i'
- }
- ],
- [
- _quit.default,
- {
- forbiddenOverwriteMessage: 'quitting watch mode'
- }
- ]
- ]);
- 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, _update_global_config.default)(globalConfig, {
- mode: globalConfig.watch ? 'watch' : 'watchAll',
- passWithNoTests: true
- });
- const updateConfigAndRun = ({
- bail,
- changedSince,
- collectCoverage,
- collectCoverageFrom,
- collectCoverageOnlyFrom,
- coverageDirectory,
- coverageReporters,
- mode,
- notify,
- notifyMode,
- onlyFailures,
- reporters,
- testNamePattern,
- testPathPattern,
- updateSnapshot,
- verbose
- } = {}) => {
- const previousUpdateSnapshot = globalConfig.updateSnapshot;
- globalConfig = (0, _update_global_config.default)(globalConfig, {
- bail,
- changedSince,
- collectCoverage,
- collectCoverageFrom,
- collectCoverageOnlyFrom,
- coverageDirectory,
- coverageReporters,
- mode,
- notify,
- notifyMode,
- onlyFailures,
- reporters,
- testNamePattern,
- testPathPattern,
- updateSnapshot,
- verbose
- });
- startRun(globalConfig);
- globalConfig = (0, _update_global_config.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();
- var _iteratorNormalCompletion = true;
- var _didIteratorError = false;
- var _iteratorError = undefined;
- try {
- for (
- var _iterator = watchPlugins[Symbol.iterator](), _step;
- !(_iteratorNormalCompletion = (_step = _iterator.next()).done);
- _iteratorNormalCompletion = true
- ) {
- const plugin = _step.value;
- const reservedInfo = RESERVED_KEY_PLUGINS.get(plugin.constructor) || {};
- const key = reservedInfo.key || getPluginKey(plugin, globalConfig);
- if (!key) {
- continue;
- }
- const forbiddenOverwriteMessage =
- reservedInfo.forbiddenOverwriteMessage;
- watchPluginKeys.set(key, {
- forbiddenOverwriteMessage,
- overwritable: forbiddenOverwriteMessage == null,
- plugin
- });
- }
- } catch (err) {
- _didIteratorError = true;
- _iteratorError = err;
- } finally {
- try {
- if (!_iteratorNormalCompletion && _iterator.return != null) {
- _iterator.return();
- }
- } finally {
- if (_didIteratorError) {
- throw _iteratorError;
- }
- }
- }
- var _iteratorNormalCompletion2 = true;
- var _didIteratorError2 = false;
- var _iteratorError2 = undefined;
- try {
- for (
- var _iterator2 = globalConfig.watchPlugins[Symbol.iterator](), _step2;
- !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done);
- _iteratorNormalCompletion2 = true
- ) {
- const pluginWithConfig = _step2.value;
- let plugin;
- try {
- const ThirdPartyPlugin = require(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().default.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);
- }
- } catch (err) {
- _didIteratorError2 = true;
- _iteratorError2 = err;
- } finally {
- try {
- if (!_iteratorNormalCompletion2 && _iterator2.return != null) {
- _iterator2.return();
- }
- } finally {
- if (_didIteratorError2) {
- throw _iteratorError2;
- }
- }
- }
- }
- 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, _is_valid_path.default)(globalConfig, filePath)
- );
- if (validPaths.length) {
- const context = (contexts[index] = (0, _create_context.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
- ); // Clear cache for required modules
- _jestResolve().default.clearDefaultResolverCache();
- 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, _watch_plugins_helpers.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,
- _watch_plugins_helpers.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, _update_global_config.default)(globalConfig, {
- mode: 'watchAll',
- testNamePattern: '',
- testPathPattern: ''
- });
- startRun(globalConfig);
- break;
- case 'c':
- updateConfigAndRun({
- mode: 'watch',
- testNamePattern: '',
- testPathPattern: ''
- });
- break;
- case 'f':
- globalConfig = (0, _update_global_config.default)(globalConfig, {
- onlyFailures: !globalConfig.onlyFailures
- });
- startRun(globalConfig);
- break;
- case 'o':
- globalConfig = (0, _update_global_config.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-ignore: 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, _active_filters_message.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, _watch_plugins_helpers.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.');
|