跳转至主内容

Jest 15.0: New Defaults for Jest

· 8 分钟阅读

We spent the past year making Jest faster, easier to configure, added tons of features and built snapshot testing. However, there were two areas where we invested very little: the CLI output and user experience. With Jest 15 we are changing the framework radically to make it easier to use both for beginners and experienced users. We are excited that our investment in Jest is now paying off: we can move fast and improve the framework for Facebook and the open source community at light-speed. Jest's goal is to come with batteries included and to require as little configuration as necessary. We recently got a chance to explain our philosophy on a create-react-app issue.

The most important change to talk about is a set of new defaults. If you are an existing Jest user you will very likely need to update your configuration for Jest 15. In most cases it will simplify your setup and Jest will provide useful error messages during the upgrade. All of the new defaults can be disabled to suit your needs, but we still consider the disabled features critical for Jest in certain situations and will continue to use and support them at Facebook long-term. Our API documentation was also completely rewritten to reflect these changes. This pull request for React highlights some of the changes necessary for existing projects.

New CLI error messages and summaries

As part of our effort to remove Jasmine incrementally within Jest, replacing all Jasmine matchers was almost completed. A lot of time was spent tweaking every error message for every matcher to give the best signal to users when a test is failing – the time when Jest should provide the most value to you. In addition to printing the expected and received values, a diff is printed for the toBe and toEqual matchers to help spot mistakes. More colors were added and relevant files from stack traces are highlighted more prominently.

Here is a comparison of the before and after on a light terminal: failure1 It also works well with darker colors: failure2

New watch command

We completely rewrote jest --watch to be more interactive. It can now switch between running all tests or only test files related to changed files by pressing a or o. By pressing p a prompt appears that allows to specify a test pattern to focus on a specific set of files. Snapshot tests can be updated by pressing u.

watch

jest-react-native improvements

Mocks for ListView, TextInput, ActivityIndicator, ScrollView and more were added. The existing mocks were updated to use the real implementations and existing snapshots likely have to be updated when upgrading to Jest 15. A mockComponent function was added to jest-react-native that can be used to mock native components:

jest.mock('MyNativeComponent', () => {
const jestReactNative = require('jest-react-native');
return jestReactNative.mockComponent('MyNativeComponent');
});

There have also been a number of improvements around mocking images, the fetch module and other native APIs.

Buffered Console Messages

Jest parallelizes test runs across workers to maximize performance. Previously Jest used to forward console messages from workers to the parent and printed them immediately. When running multiple tests in parallel, it was often hard to find out which test and which module was calling a log function. In Jest 15, all console messages are buffered and printed together with individual test results. In addition the file and line number of the log call is printed so the code can easily be inspected.

Compare the output of the previous version of Jest and Jest 15: console

Disabled Automocking

Automocking is now disabled by default in Jest. This is by far the most confusing feature for new users and in many ways it doesn't make sense for small projects. We introduced automocking at Facebook and it worked great for us when unit testing was adopted in a large existing code base with few existing tests, but over time it felt like people spent more time fighting with mocked/unmocked modules than it would have taken them to write a test normally. We also noticed that library authors often require a huge number of basic modules that always have to be manually unmocked. Even for Jest itself we realized that the majority of tests had automocking disabled manually. We still believe that explicit automocking can be incredibly valuable. This change simply trades implicit mocks for explicit mocks via calls to jest.mock(moduleName).

If you would still like to use automocking by default, enable the automock setting in your configuration or manually call jest.enableAutomock() in your test or setup file.

Test File Patterns

Not everyone uses the same convention of using a __tests__ folder to store tests. Jest 15 also looks for files ending in .spec.js or .test.js, two popular community standards. Jest 15 also removes the testDirectoryName and testFileExtensions configuration options and asks users to switch to the testRegex option when the old configuration options are used.

Module Registry Persistence

Jest used to implicitly reset all modules before each test and we recommended requiring modules in beforeEach or inside of tests. This is useful when modules have local state that shouldn't be shared between tests. However, two big shifts happened: ES modules with the top-level import syntax and a renewed interest in writing stateless functional modules.

This has lead to numerous incompatibilities. We also noticed that at Facebook we weren't even using this implicit reset. Instead we relied on explicit calls to jest.resetModules() which puts engineers in control on when to wipe away all state.

Here is an example:

const React1 = require('react');
jest.resetModules();
const React2 = require('react');

React1 !== React2; // These two are separate copies of React.

The call to resetModules wipes away the require cache. A second call to require the same module will result in a new instantiation of the same module and all of its dependencies. This feature is especially useful when dealing with modules that have side effects, like jest-haste-map.

We believe it is better to put users in control so we disabled the implicit reset. Modules can be reset using jest.resetModules() in code and the resetModules option can be enabled in the configuration to bring back the previous behavior.

Real vs Fake Timers

By default Jest used to mock all timer functions like setTimeout or process.nextTick and provided an API jest.runAllTimers() to advance timers programatically. This is useful when a piece of code sets a long timeout that we don't want to wait for in a test.

However we found that most of the time the use cases are quite isolated. Async programming has also become much simpler in our test runner. Jest now uses the real timers by default.

You can still override this by specifying "timers": "fake" in the configuration or by calling jest.useRealTimers() and jest.useFakeTimers() global switches.

setupEnvScriptFile vs setupFiles

The setupEnvScriptFile configuration option has been deprecated for a while. Jest 15 removes it completely and replaces it with setupFiles. This option expects an array of file paths that are loaded in order before a test file is executed.

Rewritten Code Coverage Support

Code coverage in Jest can be used through jest --coverage and requires no additional packages or configuration. Code coverage support was completely rewritten and a new collectCoverageFrom option was added to collect code coverage information from entire projects, including untested files. Note that this option uses globs as we are hoping to further simplify configuration options in the future and provide a simpler alternative to regular expressions. See Jest's package.json for an example.

Other Improvements

A huge number of other improvements were also made:

  • Improved performance of small test runs.
  • Jest now uses verbose mode when only a single test file is executed.
  • Added an --env option to override the configured test environment.
  • moduleNameMapper now uses a resolution algorithm.
  • Jest now works with paths that have special characters in them, like parenthesis.
  • Added global.global to the node environment.
  • Fixed babel-plugin-jest-hoist's invalid error when a random user function was called mock.
  • Fix testEnvironment resolution to prefer jest-environment-{name} instead of {name} only. This prevents a module collision when using jsdom as test environment.
  • Improvements to Jest's own test infra by merging integration and unit tests. Code coverage is now collected for Jest.

We are happy when looking back at all the changes we have made together with the help from the community and couldn't be more excited to make Jest even better over the course of the next few months. Please file an issue if something isn't working as expected and send us pull requests.

Next up: Concurrent Reporter.