w3resource

Watch Plugins


In this tutorial, we will give you an in depth understanding of Jest's Watch plugins. We will start with why we need these plugins and then delve into how we can use them.

Watch Plugins

The Jest watch plugin system will provide a way to hook into specific parts of Jest and to define watch mode menu prompts that will execute code on key press. Combined, these features will allow you to develop interactive experiences custom for your workflow.

Watch Plugin Interface

class MyWatchPlugin {
  // Adds hooks to Jest lifecycle events
  apply(jestHooks) {}

  // Gets the prompt information for interactive plugins
  getUsageInfo(globalConfig) {}

  // this is executed when the key from `getUsageInfo` is input
  run(globalConfig, updateConfigAndRun) {}
}

Hooking into Jest

If you want to connect your watch plugin to Jest, add its path under watchPlugins in your Jest configuration:

// jest.config.js

module.exports = {
  // ...
  watchPlugins: ['path/to/yourWatchPlugin'],
};

The custom watch plugins can add hooks to Jest events. You can either add these hooks with or without having an interactive key in your watch mode menu.

apply(jestHooks)

you can attach Jest hooks by implementing the apply method. This method will receive a jestHooks argument that will allow the plugin to hook into specific parts of the lifecycle of a test run.

class MyWatchPlugin {
  apply(jestHooks) {}
}

Here are the hooks that are available in Jest.

jestHooks.shouldRunTestSuite(testSuiteInfo)

This hook will return a boolean (or Promise for handling asynchronous operations) to specify if a test should be run or not.

For instance:

`class MyWatchPlugin {
  apply(jestHooks) {
    jestHooks.shouldRunTestSuite(testSuiteInfo => {
      return testSuiteInfo.testPath.includes('my-keyword');
    });

    // or a promise
   ``` jestHooks.shouldRunTestSuite(testSuiteInfo => {
      return Promise.resolve(testSuiteInfo.testPath.includes('my-keyword'));
    });
  }
}

jestHooks.onTestRunComplete(results)

This hook is called at the end of every test run. Its argument is the test result.

For instance:

class MyWatchPlugin {
  apply(jestHooks) {
    jestHooks.onTestRunComplete(results => {
      this._hasSnapshotFailure = results.snapshot.failure;
    });
  }
}

jestHooks.onFileChange({projects})

This is a hook that gets called whenever there is a change in the file system

  • projects: Array<config: ProjectConfig, testPaths: Array<string>: This includes all the test paths that Jest is watching.

For instance:

class MyWatchPlugin {
  apply(jestHooks) {
    jestHooks.onFileChange(({projects}) => {
      this._projects = projects;
    });
  }
}

Watch Menu Integration

Custom watch plugins can also override or add a functionality to the watch menu by specifying a key/prompt pair in getUsageInfo method and a run method used for the execution of the key.

getUsageInfo(globalConfig)

If you want to add a key to the watch menu, you need to implement the getUsageInfo method, returning the prompt and a key:

class MyWatchPlugin {
  getUsageInfo(globalConfig) {
    return {
      key: 's',
      prompt: 'do something',
    };
  }
}

This adds a line in the watch mode menu (> Press s to do something.)

Usage

 > Press p if you want to filter by a filename regex pattern.
 > Press t if you want to filter by a test name regex pattern.
 > Press q if you want to quit watch mode.
 > Press s if you want to do something. // <-- This is our plugin
 > Press Enter if you want to trigger a test run.

Note: In the case where the key for your plugin already exists as a default key, your plugin overrides that key.

run(globalConfig, updateConfigAndRun)

You can implement the run method if you want to handle key press events from the key that is returned by getUsageInfo.

This method will return a Promise<boolean> that can be resolved when the plugin wants to return control to Jest. The boolean will specify if Jest should rerun the tests after it gets the control back.

  • globalConfig: This is a representation of Jest's current global configuration
  • updateConfigAndRun: this will allow you to trigger a test run while the interactive plugin is running.
class MyWatchPlugin {
  run(globalConfig, updateConfigAndRun) {
    // do something.
  }
}

Note: If you call updateConfigAndRun, your run method does not resolve to a truthy value, as that triggers a double-run.

Authorized configuration keys

For safety and stability reasons, it is only part of the global configuration keys that can be updated with updateConfigAndRun. The current white list is as listed below:

  • bail
  • changedSince
  • collectCoverage
  • collectCoverageFrom
  • collectCoverageOnlyFrom
  • coverageDirectory
  • coverageReporters
  • notify
  • notifyMode
  • onlyFailures
  • reporters
  • testNamePattern
  • testPathPattern
  • updateSnapshot
  • verbose

Customization

You can customize plugins via your Jest configuration.

// jest.config.js

module.exports = {
  // ...
  watchPlugins: [
    [
      'path/to/yourWatchPlugin',
      {
        key: 'k', // <- your custom key
        prompt: 'show a custom prompt',
      },
    ],
  ],
};

Here are the recommended config names:

  • key: This will modify the plugin key.
  • prompt: This will allow user to customize the text in the plugin prompt.

In the case where the user provided a custom configuration, it is passed as an argument to the plugin constructor.

class MyWatchPlugin {
  constructor({config}) {}
}

Choosing a good key

Jest will allow third-party plugins to override some of its built-in feature keys, but not all. Specifically, the following keys cannot be overwritten :

c (clears filter patterns)
i (updates non-matching snapshots interactively)
q (quits)
u (updates all non-matching snapshots)
w (displays watch mode usage / available actions)

You can however, overwrite the following keys for built-in functionality :

p (test filename pattern)
t (test name pattern)

Any key that is not used by built-in functionality can be claimed, just as you would expect. You should try to avoid using keys that are difficult to obtain on various keyboards (e.g. ?, ?), or that are not visible by default (e.g. many Mac keyboards do not have visual hints for characters such as |, \, [, etc.)

When a conflict happens

If your plugin attempt to overwrite a reserved key, Jest errors out with a descriptive message, something like this:

Watch plugin YourFaultyPlugin attempted to register key ", that is reserved internally for quitting watch mode. Please change the configuration key for this plugin".

It is also forbidden for Third-party plugins to overwrite a key reserved already by another third-party plugin that is present earlier in the configured plugins list (watchPlugins array setting). If this happens, you will equally get an error message that tries to help you fix that:

Watch plugins YourFaultyPlugin and TheirFaultyPlugin both attempted to register key . Please change the key configuration for one of the conflicting plugins to avoid overlap.

Previous: Migrating to Jest
Next: Testing React Native Apps