For AI agents: the complete documentation index is available at /llms.txt, the full documentation bundle is available at /llms-full.txt, and this page is available as Markdown at /blog/announcing-0-12.md.
close
  • English
  • Announcing Rstest 0.12

    September 14, 2026

    9aoy
    9aoy
    @9aoy
    Max
    Max
    @fi3ework
    Rstest 0.12

    We are excited to announce the release of Rstest 0.12!

    Rstest 0.12 adds E2E and Module Federation testing support, speeds up large test suites with VM pools and test environment prebundle, and officially introduces a new JavaScript API.

    The main improvements in 0.12 are:

    E2E testing support

    Rstest 0.12 supports E2E testing through @rstest/playwright, which integrates Playwright, so unit tests, component tests, and E2E tests can share one set of Rstest config, commands, and reporters.

    You can write E2E tests directly in Rstest: open a real page with Playwright and verify the full flow against a local dev server, a preview server, or a deployed URL. See the Rstest E2E example for a complete project.

    To start writing E2E tests, import test and expect from @rstest/playwright:

    e2e.test.ts
    import { expect, test } from '@rstest/playwright';
    
    test('page title', async ({ page }) => {
      await page.goto('https://example.com');
    
      await expect(page).toHaveTitle(/Example/);
      await expect(page.locator('h1')).toHaveText('Example Domain');
    });

    With definePlaywrightConfig, you get the same defaults as Playwright and can customize Playwright options as needed. For example, set a default viewport and record a trace on retries in CI:

    rstest.config.ts
    import { defineConfig } from '@rstest/core';
    import { definePlaywrightConfig } from '@rstest/playwright/config';
    
    export default defineConfig({
      retry: process.env.CI ? 1 : 0,
      extends: definePlaywrightConfig({
        contextOptions: {
          viewport: { width: 1440, height: 900 },
        },
        trace: process.env.CI ? 'on-first-retry' : 'off',
      }),
    });

    An existing Playwright Test project can be migrated with the migrate-to-rstest skill, which includes guidance for Playwright configuration, fixtures, and behavior differences.

    See E2E testing to learn more.

    Module Federation testing support

    Rstest 0.12 supports testing Module Federation applications. Test code imports remote modules the same way a consumer application does. Rstest loads the real exposed modules and resolves the shared dependencies, so integration problems between consumer and producer show up in unit tests instead of during integration or after release.

    Module Federation is supported in Rstest's Node, jsdom, happy-dom, and browser mode. See the Node example and the browser mode example for complete projects.

    To add Module Federation testing to a project, use the @module-federation/rstest plugin: register it in the config and declare the remotes and shared dependencies:

    rstest.config.ts
    import { federation } from '@module-federation/rstest';
    import { defineConfig } from '@rstest/core';
    
    export default defineConfig({
      testEnvironment: 'jsdom',
      plugins: [
        federation({
          name: 'host',
          remotes: {
            'component-app': 'component_app@http://localhost:3001/remoteEntry.cjs',
          },
          shared: {
            react: { singleton: true },
            'react-dom': { singleton: true },
          },
        }),
      ],
    });

    Then import the exposed modules just as application code does:

    remote.test.ts
    import { expect, it } from '@rstest/core';
    
    it('loads a federated remote', async () => {
      const remote = await import('component-app/Button');
      expect(remote.default).toBeDefined();
    });

    See Module Federation to learn more.

    New vmThreads and vmForks pools

    For suites with many jsdom / happy-dom test files, the new vmThreads / vmForks pools in Rstest 0.12 cut worker startup and module loading costs substantially. They reuse workers across test files and create a fresh vm.Context for each file. Every file still has its own JavaScript realm and module graph, while worker startup, dependency resolution, and V8 compilation are shared by many files.

    On a jsdom benchmark project of 2,400 files and 20,000 tests (15 workers, every process starting from an empty cache):

    forks315.17s
    vmThreads9.5× faster33.22s

    Rstest now offers four pools. Choose by scenario:

    PoolSuitable forLimitations
    forksThe default; suits native addons, process.chdir(), and similar needsHigh startup cost for large DOM test suites
    threadsMany light test filesSome process-level capabilities are unavailable
    vmThreadsMany jsdom / happy-dom tests; the fastest optionCross-realm and custom loader limitations
    vmForksVM pool speed plus process-level capabilitiesProcess-level state must not leak between files

    Before switching, confirm that the bottleneck is worker startup or module loading. Costs such as database initialization or network requests in setup files do not shrink with a different pool. Enable a pool through pool.type:

    rstest.config.ts
    import { defineConfig } from '@rstest/core';
    
    export default defineConfig({
      pool: {
        type: 'vmThreads',
        memoryLimit: '256MB',
      },
    });

    For suites with many test files, you can use pool.memoryLimit to limit the memory usage of a single worker. Once the threshold is exceeded, Rstest automatically replaces it with a new worker.

    See Choose a pool type for the full selection guidance and what the VM pools support.

    Faster jsdom / happy-dom loading

    Besides cutting worker costs with VM pools, 0.12 also supports and enables by default test environment prebundle, which reduces the repeated loading cost of jsdom / happy-dom.

    Previously every worker loaded jsdom or happy-dom through Node.js's own module system, resolving and executing every module file in the environment one by one. With prebundle enabled, Rstest first builds the environment into one ESM bundle that all workers share, which removes most of that repeated work. On a benchmark of 100 files and 1,000 tests:

    jsdom 30.0.1

    Native16.99s
    Prebundle-37.8%10.57s

    happy-dom 20.11.1

    Native6.35s
    Prebundle-53.0%2.98s

    Starting from 0.12, testEnvironment.prebundle defaults to 'auto', and Rstest applies prebundle to jsdom 15–26 and 29–30, and happy-dom 20. Other versions keep native loading, and a prebundle that fails to build, load, or validate falls back to the native entry as well. If your environment behaves differently after bundling, turn it off explicitly:

    rstest.config.ts
    import { defineConfig } from '@rstest/core';
    
    export default defineConfig({
      testEnvironment: {
        name: 'jsdom',
        prebundle: false,
      },
    });

    See Environment prebundle to learn more.

    A new JavaScript API

    Rstest 0.12 provides a new createRstest API, a rewrite of the JavaScript API before 1.0 that makes it easier to integrate Rstest into tools, IDEs, and other Node.js programs. It shares the same core execution capabilities as the rstest command, so you can run tests, watch, list tests, and merge blob reports from code.

    Use createRstest() to create an instance, then call methods such as run, watch, listTests, and mergeReports to use the corresponding Rstest features.

    import { createRstest } from '@rstest/core/api';
    
    const rstest = await createRstest({
      cwd: './packages/app',
      config: {
        include: ['src/**/*.test.ts'],
        reporters: [],
      },
    });
    
    const result = await rstest.run();
    console.log(result.status, result.summary);

    Output:

    pass {
      tests: { total: 1, passed: 1, failed: 0, skipped: 0, todo: 0 },
      files: { total: 1, failed: 0 },
    }

    See Rstest instance to learn more.

    Other improvements

    • File- and worker-scoped fixtures. Fixtures from test.extend can share one instance per file or per worker, so expensive setup such as a database connection or a browser instance is not repeated for every test. See test.extend.
    • --onlyFailures re-runs only failed files. Rstest remembers which files failed last time and runs just those after a fix, instead of the whole suite. The same record also schedules failed and slow files first, so feedback arrives sooner. See onlyFailures.
    • Rspack native watcher. Watch mode now uses Rspack's Rust file watcher, which detects changes incrementally and stays stable and responsive when many files change at once. See rstest watch.
    • context.signal on timeout. Every test attempt receives an AbortSignal, so a timed-out test can cancel pending fetch calls and similar work instead of holding the worker. See signal.
    • Task metadata. Tests, suites, and files can carry custom metadata, which makes it easy to group results by owner, module, or any other dimension. See Metadata.
    • Defaults for expect.poll. Set the polling timeout and interval once in the config instead of passing them to every expect.poll() call. See expect.poll.
    • Rsbuild plugins can read and modify Rstest config. A framework or tooling plugin can integrate with Rstest on its own, so users no longer edit the test config by hand. See Modify Rstest config in Rsbuild plugins.
    • Project-level silent. Each project in a multi-project config can set its own silent, so you can mute a noisy project while keeping output from the others. See silent.
    • VS Code extension. Right-click a test or file and choose "Run in Terminal" to run it as an rstest command in the integrated terminal, with the full command and raw output visible. New debugging settings pin the inspector port, pass environment variables to the worker, and skip Node internals while debugging. See VS Code extension.
    • Full reporter replay for --merge-reports. Merging blob reports replays every reporter hook in its original order, so a merged report from sharded runs matches a single-machine run and custom reporter counts stay complete. See rstest merge-reports.
    • Browser mode catches up with Node mode. Browser projects now support native V8 coverage, rs.mock, includeSource, globalSetup, Module Federation, and the watch shortcuts, used the same way as in Node mode. See Browser mode.

    Upgrade to Rstest 0.12

    Upgrade the @rstest/* packages to 0.12. The release includes breaking changes to the JavaScript API and some reporter types. If your project uses @rstest/core/api directly or has custom reporters, review those changes before upgrading. See A new JavaScript API and Rstest instance for details.

    For a full list of changes, see the v0.12.0 release notes.