Jest 15.0: New Defaults for Jest
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: It also works well with darker colors:
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
.
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:
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 calledmock
. - Fix
testEnvironment
resolution to preferjest-environment-{name}
instead of{name}
only. This prevents a module collision when usingjsdom
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.