jest: a quick intro to custom runners

2021-05-02

 | 

~3 min read

 | 

564 words

Jest is best known as a test runner, however, it can be used to run all sorts of things, including custom runners, Go, Python, etc.

As part of Kent C. Dodds’ course on Testing Javascript, I learned about this feature as a way to incorporate linting into the test workflow.1 The way to do this is by using a community defined runner and plugging that into your project’s Jest configuration. Once accomplished, we’ll get immediate feedback on any linting issues (though Jest is much more powerful than just using it for linting).

The steps involved include:

  1. Adding the runner
  2. Configuring jest to look for the runner
  3. (Optional) Configuring our runner

Add A Runner

The first step (after determining which runner you want to use) is installing it:

% yarn add --dev jest-runner-eslint

Configuring Jest To Use The Custom Runner

Once the runner’s installed, we need to tell Jest how to use it with its own configuration:

const path = require("path")

module.exports = {
    rootDir: path.join(__dirname, ".."),
    displayName: "lint",
    runner: "jest-runner-eslint", // which runner to use
    testMatch: ["<rootDir>/**/*.js"], // which files to run against
}

Technically, this is all that we need and we can start using the runner from the command line with:

% npx jest --config ./test/jest.lint.js

However, if we want to tell Jest to use it we can modify our jest.config.js by adding a new project:

module.exports = {
  ...require('./test/jest-common'),
  projects: [
+     './test/jest.lint.js',
    './test/jest.client.js',
    './test/jest.server.js',
  ],
}

One benefit to doing this approach is that we can clearly see which tests are passing/failing based on the project, and we don’t need to have separate scripts to run each config.

That said, if we want more control over which tests run when using watch mode, we might want to look into jest-watch-select-projects

Configuring Our Runner

In the case of our eslint runner, it’s currently configured to run against all Javascript files - even those that we didn’t define. One way to fix that would be to make a more specific testMatch, but in the case of jest-runner-eslint, we can actually create a configuration within package.json:

{
    "jest-runner-eslint": {
        "cliOptions": {
            "ignorePath": "./.gitignore"
        }
    }
}

This configuration is the same as if we were running eslint from the command line and wanted to use .gitignore as a source of files to ignore, i.e.

% eslint --ignore-path .gitignore

Conclusion

In this blog I walked through how to configure Jest to run eslint in addition to Jest tests using a custom runner. While it’s just one example of a custom runner, it demonstrates the power of Jest as a runner of lots of things, not just tests.

One non-obvious benefit to using Jest’s eslint runner rather than just using eslint directly is that it’s more configurable. For example, by using Jest to lint, we can take advantage of the fact that Jest natively only runs against modified files - therefore reducing the number of files that are linted each time it’s run.

Footnotes

  • 1 You can imagine that it’s beneficial to get the feedback of a linting error as soon as possible. Using a Jest runner continues to pull that feedback earlier and earlier from having it on CI, to using lint-staged/husky, to now using Jest’s watch mode to get continuous feedback.

Hi there and thanks for reading! My name's Stephen. I live in Chicago with my wife, Kate, and dog, Finn. Want more? See about and get in touch!