From v27 to v28
Upgrading Jest from v27 to v28? This guide aims to help refactoring your configuration and tests.
info
See changelog for the full list of changes.
Compatibility
The supported Node versions are 12.13, 14.15, 16.10 and above.
If you plan to use type definitions of Jest (or any of its packages), make sure to install TypeScript version 4.3 or above.
Configuration Options
extraGlobals
The extraGlobals
option was renamed to sandboxInjectedGlobals:
- extraGlobals: ['Math']
+ sandboxInjectedGlobals: ['Math']
timers
The timers
option was renamed to fakeTimers. See Fake Timers section below for details.
testURL
The testURL
option is removed. Now you should use testEnvironmentOptions to pass url
option to JSDOM environment:
- testURL: 'https://jestjs.io'
+ testEnvironmentOptions: {
+ url: 'https://jestjs.io'
+ }
Babel config
babel-jest
now passes root: config.rootDir
to Babel when resolving configuration. This improves compatibility when using projects
with differing configuration, but it might mean your babel config isn’t picked up in the same way anymore. You can override this option by passing options to babel-jest
in your configuration.
expect
In versions prior to Jest 28, toHaveProperty
checked for equality instead of existence, which means that e.g. expect({}).toHaveProperty('a', undefined)
is a passing test. This has been changed in Jest 28 to fail.
Additionally, if you import expect
directly, it has been changed from default export to a named export.
- import expect from 'expect';
+ import {expect} from 'expect';
- const expect = require('expect');
+ const {expect} = require('expect');
假的定时器
Fake timers were refactored to allow passing options to the underlying @sinonjs/fake-timers.
fakeTimers
The timers
configuration option was renamed to fakeTimers and now takes an object with options:
- timers: 'real'
+ fakeTimers: {
+ enableGlobally: false
+ }
- timers: 'fake'
+ fakeTimers: {
+ enableGlobally: true
+ }
- timers: 'modern'
+ fakeTimers: {
+ enableGlobally: true
+ }
- timers: 'legacy'
+ fakeTimers: {
+ enableGlobally: true,
+ legacyFakeTimers: true
+ }
jest.useFakeTimers()
An object with options now should be passed to jest.useFakeTimers() as well:
- jest.useFakeTimers('modern')
+ jest.useFakeTimers()
- jest.useFakeTimers('legacy')
+ jest.useFakeTimers({
+ legacyFakeTimers: true
+ })
If legacy fake timers are enabled in Jest config file, but you would like to disable them in a particular test file:
- jest.useFakeTimers('modern')
+ jest.useFakeTimers({
+ legacyFakeTimers: false
+ })
Test Environment
Custom Environment
The constructor of test environment class now receives an object with Jest’s globalConfig
and projectConfig
as its first argument. The second argument is now mandatory.
class CustomEnvironment extends NodeEnvironment {
- constructor(config) {
- super(config);
+ constructor({globalConfig, projectConfig}, context) {
+ super({globalConfig, projectConfig}, context);
+ const config = projectConfig;
In addition, test environments are now exported with the name TestEnvironment
, instead of simply exporting the class directly:
- const TestEnvironment = require('jest-environment-node');
+ const {TestEnvironment} = require('jest-environment-node');
- const TestEnvironment = require('jest-environment-jsdom');
+ const {TestEnvironment} = require('jest-environment-jsdom');
jsdom
If you are using JSDOM test environment, jest-environment-jsdom
package now must be installed separately:
- npm
- Yarn
npm install --save-dev jest-environment-jsdom
yarn add --dev jest-environment-jsdom
Test Runner
If you are using Jasmine test runner, jest-jasmine2
package now must be installed separately:
- npm
- Yarn
npm install --save-dev jest-jasmine2
yarn add --dev jest-jasmine2
Transformer
process()
and processAsync()
methods of a custom transformer module cannot return a string anymore. They must always return an object:
process(sourceText, sourcePath, options) {
- return `module.exports = ${JSON.stringify(path.basename(sourcePath))};`;
+ return {
+ code: `module.exports = ${JSON.stringify(path.basename(sourcePath))};`,
+ };
}
package.json
exports
Jest now includes full support for package exports, which might mean that files you import are not resolved correctly.
Additionally, Jest now supplies more conditions. jest-environment-node
has node
and node-addons
, while jest-environment-jsdom
has browser
. As a result, you might e.g. get browser code which assumes ESM, when Jest provides ['require', 'browser']
. You can either report a bug to the library (or Jest, the implementation is new and might have bugs!), override the conditions Jest passes (by passing the customExportConditions
option to the test environment), or use a custom resolver or moduleMapper
. Lots of options, and you’ll need to pick the correct one for your project.
Known examples of packages that fails in Jest 28 are uuid and nanoid when using the jest-environment-jsdom
environment. For an analysis, and a potential workaround, see this comment.
TypeScript
info
The TypeScript examples from this page will only work as documented if you import jest
from '@jest/globals'
:
import {jest} from '@jest/globals';
jest.fn()
jest.fn()
now takes only one generic type argument. See Mock Functions API page for more usage examples.
import add from './add';
- const mockAdd = jest.fn<ReturnType<typeof add>, Parameters<typeof add>>();
+ const mockAdd = jest.fn<typeof add>();
- const mock = jest.fn<number, []>()
+ const mock = jest.fn<() => number>()
.mockReturnValue(42)
.mockReturnValueOnce(12);
- const asyncMock = jest.fn<Promise<string>, []>()
+ const asyncMock = jest.fn<() => Promise<string>>()
.mockResolvedValue('default')
.mockResolvedValueOnce('first call');