Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
168 changes: 105 additions & 63 deletions docs/Configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -1889,15 +1889,17 @@ More about serializers API can be found [here](https://github.com/jestjs/jest/tr

:::

### `testEnvironment` \[string]
### `testEnvironment` \[node | jsdom | string]

Default: `"node"`
Default: `node`

The test environment that will be used for testing. The default environment in Jest is a Node.js environment. If you are building a web app, you can use a browser-like environment through [`jsdom`](https://github.com/jsdom/jsdom) instead.

By adding a `@jest-environment` docblock at the top of the file, you can specify another environment to be used for all tests in that file:

```js
- With built-in environments:

```js tab title="my-test.spec.js"
/**
* @jest-environment jsdom
*/
Expand All @@ -1908,99 +1910,116 @@ test('use jsdom in this test file', () => {
});
```

You can create your own module that will be used for setting up the test environment. The module must export a class with `setup`, `teardown` and `getVmContext` methods. You can also pass variables from this module to your test suites by assigning them to `this.global` object – this will make them available in your test suites as global variables. The constructor is passed [`globalConfig`](https://github.com/jestjs/jest/blob/v29.2.1/packages/jest-types/src/Config.ts#L358-L422) and [`projectConfig`](https://github.com/jestjs/jest/blob/v29.2.1/packages/jest-types/src/Config.ts#L424-L481) as its first argument, and [`testEnvironmentContext`](https://github.com/jestjs/jest/blob/491e7cb0f2daa8263caccc72d48bdce7ba759b11/packages/jest-environment/src/index.ts#L13) as its second.

The class may optionally expose an asynchronous `handleTestEvent` method to bind to events fired by [`jest-circus`](https://github.com/jestjs/jest/tree/main/packages/jest-circus). Normally, `jest-circus` test runner would pause until a promise returned from `handleTestEvent` gets fulfilled, **except for the next events**: `start_describe_definition`, `finish_describe_definition`, `add_hook`, `add_test` or `error` (for the up-to-date list you can look at [SyncEvent type in the types definitions](https://github.com/jestjs/jest/tree/main/packages/jest-types/src/Circus.ts)). That is caused by backward compatibility reasons and `process.on('unhandledRejection', callback)` signature, but that usually should not be a problem for most of the use cases.
```ts tab title="my-test.spec.ts"
/**
* @jest-environment jsdom
*/

Any docblock pragmas in test files will be passed to the environment constructor and can be used for per-test configuration. If the pragma does not have a value, it will be present in the object with its value set to an empty string. If the pragma is not present, it will not be present in the object.
test('use jsdom in this test file', () => {
const element = document.createElement('div');
expect(element).not.toBeNull();
});
```

To use this class as your custom environment, refer to it by its full path within the project. For example, if your class is stored in `my-custom-environment.js` in some subfolder of your project, then the annotation might look like this:
- With custom environment:

```js
```js tab title="my-test.spec.js"
/**
* @jest-environment ./src/test/my-custom-environment
* @jest-environment ./my-custom-environment.js
*/
```

:::info

TestEnvironment is sandboxed. Each test suite will trigger setup/teardown in their own TestEnvironment.
test('use jsdom in this test file', () => {
const element = document.createElement('div');
expect(element).not.toBeNull();
});
```

:::
```ts tab title="my-test.spec.ts"
/**
* @jest-environment ./my-custom-environment.ts
*/

Example:
test('use jsdom in this test file', () => {
const element = document.createElement('div');
expect(element).not.toBeNull();
});
```

```js
// my-custom-environment
const NodeEnvironment = require('jest-environment-node').TestEnvironment;
You can also define custom environment. When non-builtin environment is used, Jest will try to load either the file path or the package name defined as value for `testEnvironment`. That file or the package should export an object with the shape of `JestEnvironment`:

class CustomEnvironment extends NodeEnvironment {
```js tab title="environment.js"
/**
* @implements {import('@jest/environment').JestEnvironment}
*/
class CustomEnvironment {
constructor(config, context) {
super(config, context);
console.log(config.globalConfig);
console.log(config.projectConfig);
this.testPath = context.testPath;
this.docblockPragmas = context.docblockPragmas;
}

async setup() {
await super.setup();
await someSetupTasks(this.testPath);
this.global.someGlobalObject = createGlobalObject();

// Will trigger if docblock contains @my-custom-pragma my-pragma-value
if (this.docblockPragmas['my-custom-pragma'] === 'my-pragma-value') {
// ...
}
}

async teardown() {
this.global.someGlobalObject = destroyGlobalObject();
await someTeardownTasks();
await super.teardown();
const {projectConfig} = config;
// Implement the constructor
}

// Example of a method
getVmContext() {
return super.getVmContext();
}

async handleTestEvent(event, state) {
if (event.name === 'test_start') {
// ...
}
return null;
}
// Implement the required methods here
}

module.exports = CustomEnvironment;
```

```js
// my-test-suite
/**
* @jest-environment ./my-custom-environment
*/
let someGlobalObject;
```ts tab title="environment.ts"
import type {
EnvironmentContext,
JestEnvironment,
JestEnvironmentConfig,
} from '@jest/environment';

beforeAll(() => {
someGlobalObject = globalThis.someGlobalObject;
});
export default class CustomEnvironment implements JestEnvironment {
constructor(config: JestEnvironmentConfig, context: EnvironmentContext) {
const {projectConfig} = config;
// Implement the constructor
}

// Example of a method
getVmContext() {
return null;
}
// Implement the required methods here
}
```

Jest also exposes `builtinEnvironments` through `jest-environment-node` and `jest-environment-jsdom` packages, in case you just want to extend it. You can read more about extending environments in [our guide](TestEnvironment.md).

### `testEnvironmentOptions` \[Object]

Default: `{}`

Test environment options that will be passed to the `testEnvironment`. The relevant options depend on the environment.
Test environment options that will be passed to the `testEnvironment`. The relevant options depend on the environment being used.

#### Node Environment Options

When using the `node` environment, you can configure various options that are passed to `runInContext`. These options include:

For example, you can override options passed to [`jsdom`](https://github.com/jsdom/jsdom):
- **`globalsCleanup`** (**'on'** | **'soft'** | **'off'**): Controls cleanup of global variables between tests. Default: `'soft'`.
- All the options listed in the [vm.runInContext](https://nodejs.org/api/vm.html#scriptrunincontextcontextifiedobject-options) documentation

#### JSDOM Environment Options

When using the `jsdom` environment, you can configure various options that are passed to [jsdom](https://github.com/jsdom/jsdom). These options include:

- **`url`** - The URL of the page (affects `window.location` and relative URLs). Default: `"http://localhost"`
- **`userAgent`** - The user agent string. Default: a generic user agent
- All the options listed in the [jsdom](https://github.com/jsdom/jsdom)

For example, you can override options passed to `jsdom`:

```js tab title="jest.config.js"
const {defineConfig} = require('jest');

module.exports = defineConfig({
testEnvironment: 'jsdom',
testEnvironmentOptions: {
html: '<html lang="zh-cmn-Hant"></html>',
html: '<html lang="en-US"></html>',
url: 'https://jestjs.io/',
userAgent: 'Agent/007',
},
Expand All @@ -2013,14 +2032,23 @@ import {defineConfig} from 'jest';
export default defineConfig({
testEnvironment: 'jsdom',
testEnvironmentOptions: {
html: '<html lang="zh-cmn-Hant"></html>',
html: '<html lang="en-US"></html>',
url: 'https://jestjs.io/',
userAgent: 'Agent/007',
},
});
```

Both `jest-environment-jsdom` and `jest-environment-node` allow specifying `customExportConditions`, which allow you to control which versions of a library are loaded from `exports` in `package.json`. `jest-environment-jsdom` defaults to `['browser']`. `jest-environment-node` defaults to `['node', 'node-addons']`.
#### Custom Export Conditions

The `testEnvironmentOptions` allow specifying `customExportConditions`, which control which versions of a library are loaded from `exports` in `package.json`.

The built-in environments have the following defaults:

- `jest-environment-jsdom` defaults to `['browser']`
- `jest-environment-node` defaults to `['node', 'node-addons']`

For example, you can override `customExportConditions` passed to `jsdom`:

```js tab title="jest.config.js"
const {defineConfig} = require('jest');
Expand Down Expand Up @@ -2057,6 +2085,20 @@ test('use jsdom and set the URL in this test file', () => {
});
```

You can combine multiple options:

```js
/**
* @jest-environment jsdom
* @jest-environment-options {"url": "https://example.com/", "userAgent": "Custom Agent"}
*/

test('use custom URL and user agent', () => {
expect(window.location.href).toBe('https://example.com/');
expect(window.navigator.userAgent).toContain('Custom Agent');
});
```

### `testFailureExitCode` \[number]

Default: `1`
Expand Down
Loading
Loading