close

testEnvironment

  • Type: 'node' | 'jsdom' | 'happy-dom' | string | { name: EnvironmentName, options?: EnvironmentOptions, target?: 'node' | 'web' }
  • Default: 'node'
  • CLI: --testEnvironment=node

The environment that will be used for testing.

The default environment in Rstest is a Node.js environment. If you are building a web application, you can use a browser-like environment through jsdom or happy-dom instead.

Browser Mode

If you enable browser mode, tests run directly in a real browser (Chromium/Firefox/WebKit). In this case, the testEnvironment option is ignored because the real browser itself is the host environment.

CLI
rstest.config.ts
npx rstest --testEnvironment=jsdom

DOM testing

Rstest supports jsdom and happy-dom for mocking DOM and browser APIs.

If you want to enable DOM testing, you can use the following configuration:

rstest.config.ts
import { defineConfig } from '@rstest/core';

export default defineConfig({
  testEnvironment: 'jsdom', // or 'happy-dom'
});

You also need to install the corresponding package:

For jsdom

npm
yarn
pnpm
bun
deno
npm add jsdom -D

For happy-dom

npm
yarn
pnpm
bun
deno
npm add happy-dom -D

After enabling DOM testing, you can write tests that use browser APIs like document and window.

test('DOM test', () => {
  document.body.innerHTML = '<p class="content">hello world</p>';
  const paragraph = document.querySelector('.content');
  expect(paragraph?.innerHTML).toBe('hello world');
});

Environment options

You can also pass options to the test environment. This is useful for configuring jsdom or happy-dom. For example, you can set the url for jsdom:

rstest.config.ts
import { defineConfig } from '@rstest/core';

export default defineConfig({
  testEnvironment: {
    name: 'jsdom',
    options: {
      // jsdom-specific options
      url: 'https://example.com',
    },
  },
});

The options object is passed directly to the environment's constructor.

  • For jsdom, it's passed to the JSDOM constructor. You can find available options in the jsdom documentation.
  • For happy-dom, it's passed to the Window constructor. You can find available options in the happy-dom documentation.

Custom environments

Experimental API

Custom environment APIs are experimental before Rstest 1.0. Their core shape is expected to stay stable, but type signatures and config details may receive minor adjustments based on migration feedback.

Rstest also supports custom environments through testEnvironment.name.

  • Use a package name.
  • Use a relative or absolute JavaScript file path such as .js or .mjs.
  • For package names, testEnvironment: 'foo' also tries to resolve rstest-environment-foo.

Custom environments should export an environment object as the default export.

my-environment.mjs
import { builtinEnvironments } from '@rstest/core';

/** @type {import('@rstest/core').TestEnvironment<typeof globalThis, { marker: string }>} */
const environment = {
  name: 'custom-jsdom',
  async setup(global, options) {
    const base = await builtinEnvironments.jsdom.setup(global, {
      url: 'https://example.com',
    });

    global.__MARKER__ = options.marker;

    return {
      async teardown() {
        delete global.__MARKER__;
        await base.teardown();
      },
    };
  },
};

export default environment;
rstest.config.ts
import { defineConfig } from '@rstest/core';

export default defineConfig({
  testEnvironment: {
    name: './my-environment.mjs',
    options: {
      marker: 'custom-marker',
    },
  },
});

@rstest/core exports builtinEnvironments so you can extend node, jsdom, or happy-dom instead of rebuilding them from scratch.

Rstest currently loads custom environment files as JavaScript modules. Direct .ts custom environment file paths are not supported yet. If you want type checking, write the environment in TypeScript and compile it to .mjs or .js, or use JSDoc types in a JavaScript file.

target

  • Type: 'node' | 'web'
  • Default: 'node'

target controls whether a custom environment should use Node.js-oriented or web-oriented build and resolution defaults. Built-in environments infer this value automatically, so you usually only need this option when configuring a custom environment.

Use target: 'node' when the custom environment should use the same build defaults as the built-in node environment. In this mode, Rstest keeps Node-oriented resolution defaults and externalizes third-party dependencies from node_modules by default.

Use target: 'web' when the custom environment should use the shared web-oriented build defaults of the built-in jsdom and happy-dom environments. In this mode, Rstest resolves browser-oriented package entrypoints by adding the browser condition when resolve.conditionNames is not customized, and bundles third-party dependencies by default so browser field replacements and bundled assets can take effect.

rstest.config.ts
import { defineConfig } from '@rstest/core';

export default defineConfig({
  testEnvironment: {
    name: './my-environment.mjs',
    target: 'web',
    options: {
      url: 'https://example.com',
    },
  },
});

target does not create DOM APIs by itself and does not enable browser mode. It only selects the build and resolution defaults. The environment implementation is still responsible for installing globals such as window and document.

If you are migrating a custom environment from Jest or Vitest, see Migrating Jest custom environments or Migrating Vitest custom environments.

Custom environment vs setupFiles

Use a custom environment when you need to define or wrap the host runtime itself for each test file.

  • Switching or extending node, jsdom, or happy-dom.
  • Creating globals before test modules execute.
  • Managing environment-level teardown, such as closing a browser-like runtime or cleaning injected globals.

Use setupFiles when the environment is already correct and you only need to configure the test runtime inside it.

  • Registering matchers such as @testing-library/jest-dom.
  • Installing fake timers, serializers, mocks, or hooks.
  • Running project-level initialization code that depends on the selected environment already being available.

In short: testEnvironment decides what globals and host APIs exist; setupFiles configures how your tests use that environment.

Environment comments

You can override the environment for a single test file by adding an environment comment near the top of the file:

example.test.ts
// @rstest-environment jsdom

test('DOM test', () => {
  document.body.innerHTML = '<p>hello world</p>';
  expect(document.querySelector('p')?.textContent).toBe('hello world');
});

Use @rstest-environment-options to pass environment options for the annotated file. The options must be a single-line JSON object:

example.test.ts
// @rstest-environment jsdom
// @rstest-environment-options { "url": "https://example.com/" }

test('sets the jsdom url', () => {
  expect(window.location.href).toBe('https://example.com/');
});

Rstest also recognizes @vitest-environment and @jest-environment aliases, including their -options variants, to make migration easier.

Environment comments support the built-in Node runner environments: node, jsdom, and happy-dom. They do not apply to browser mode. If most files use the same environment, prefer configuring testEnvironment or separate projects in rstest.config.ts.

Examples