For AI agents: the complete documentation index is available at https://rstest.rs/llms.txt, the full documentation bundle is available at https://rstest.rs/llms-full.txt, and this page is available as Markdown at https://rstest.rs/config/test/browser.md.
close
  • English
  • browser (experimental)

    • Type:
    type BrowserViewport =
      | {
          width: number;
          height: number;
        }
      | DevicePreset;
    
    type DevicePreset =
      | 'iPhoneSE'
      | 'iPhoneXR'
      | 'iPhone12Pro'
      | 'iPhone14ProMax'
      | 'Pixel7'
      | 'SamsungGalaxyS8Plus'
      | 'SamsungGalaxyS20Ultra'
      | 'iPadMini'
      | 'iPadAir'
      | 'iPadPro'
      | 'SurfacePro7'
      | 'SurfaceDuo'
      | 'GalaxyZFold5'
      | 'AsusZenbookFold'
      | 'SamsungGalaxyA51A71'
      | 'NestHub'
      | 'NestHubMax';
    
    type BrowserModeConfig = {
      enabled?: boolean;
      provider: 'playwright';
      browser?: 'chromium' | 'firefox' | 'webkit';
      headless?: boolean;
      screenshotFailures?: boolean;
      port?: number;
      viewport?: BrowserViewport;
      strictPort?: boolean;
      providerOptions?: Record<string, unknown>;
      expect?: {
        toMatchScreenshot?: {
          comparatorOptions?: {
            threshold?: number;
            maxDiffPixels?: number;
            maxDiffPixelRatio?: number;
          };
          stabilityTimeout?: number;
          maskColor?: string;
          style?: string;
          caret?: 'hide' | 'initial';
          scale?: 'css' | 'device';
          omitBackground?: boolean;
          screenshotDirectory?: string;
          resolveScreenshotPath?: (options: BrowserScreenshotPathOptions) => string;
        };
      };
    };
    
    type BrowserScreenshotPathOptions = {
      testFilePath: string;
      projectName: string;
      testName: string;
      browserName: 'chromium' | 'firefox' | 'webkit';
      platform: string;
      screenshotAssertionOrdinal?: number;
    };
    • Default:
    const defaultBrowser = {
      enabled: false,
      provider: 'playwright',
      browser: 'chromium',
      headless: true, // CI environment; false for local development
      screenshotFailures: true, // Defaults to the headless setting
      port: undefined, // Random available port
      viewport: undefined, // Browser UI fills the preview panel
      strictPort: false,
      providerOptions: {},
    };

    Browser Mode configuration. When enabled, tests run in a real browser instead of the Node.js environment.

    Options

    screenshotFailures

    Capture a PNG screenshot for each failed browser test. Defaults to the headless setting. Screenshots are saved under .rstest/screenshots/ in the project root, with the test file and test name in the filename. Set this to false to disable capture.

    • Type: boolean
    • Default: browser.headless
    • CLI: --browser.screenshotFailures

    enabled

    • Type: boolean
    • Default: false
    • CLI: --browser, --browser.enabled

    Enable Browser Mode.

    rstest.config.ts
    import { defineConfig } from '@rstest/core';
    
    export default defineConfig({
      browser: {
        enabled: true,
        provider: 'playwright',
      },
    });
    Tip

    Enabling Browser Mode requires installing the @rstest/browser package and Playwright browsers.

    npm add @rstest/browser -D
    npx playwright install chromium

    provider

    • Type: 'playwright'
    • Default: 'playwright'

    Browser driver provider. Currently only Playwright is supported.

    rstest.config.ts
    import { defineConfig } from '@rstest/core';
    
    export default defineConfig({
      browser: {
        enabled: true,
        provider: 'playwright',
      },
    });

    browser

    • Type: 'chromium' | 'firefox' | 'webkit'
    • Default: 'chromium'
    • CLI: --browser.name <name>

    The browser type to use for testing.

    • chromium - Google Chrome, Microsoft Edge
    • firefox - Mozilla Firefox
    • webkit - Safari
    rstest.config.ts
    import { defineConfig } from '@rstest/core';
    
    export default defineConfig({
      browser: {
        enabled: true,
        provider: 'playwright',
        browser: 'firefox',
      },
    });

    You need to install the corresponding browser before use:

    # Install chromium
    npx playwright install chromium
    
    # Install Firefox
    npx playwright install firefox
    
    # Install WebKit
    npx playwright install webkit
    
    # Install all browsers
    npx playwright install

    headless

    • Type: boolean
    • Default: true in CI environments, false for local development
    • CLI: --browser.headless

    Whether to run the browser in headless mode (without UI).

    rstest.config.ts
    CI (GitHub Actions)
    import { defineConfig } from '@rstest/core';
    
    export default defineConfig({
      browser: {
        enabled: true,
        provider: 'playwright',
        headless: true,
      },
    });

    During local development, setting headless: false shows the browser window for easier debugging.

    Dynamic Configuration Based on Environment

    If you want headed mode for local debugging and headless in CI, control it with environment variables:

    rstest.config.ts
    import { defineConfig } from '@rstest/core';
    
    export default defineConfig({
      browser: {
        enabled: true,
        provider: 'playwright',
        headless: process.env.CI === 'true',
      },
    });

    viewport

    • Type: BrowserViewport
    • Default: undefined

    Set the default runner iframe viewport for Browser Mode tests. When not specified, the Browser UI fills the preview panel.

    type BrowserViewport =
      | {
          width: number;
          height: number;
        }
      | DevicePreset;

    Use an explicit size when you want all files in a browser project to run with the same viewport:

    rstest.config.ts
    import { defineConfig } from '@rstest/core';
    
    export default defineConfig({
      browser: {
        enabled: true,
        provider: 'playwright',
        viewport: { width: 390, height: 844 },
      },
    });

    You can also use a built-in device preset:

    rstest.config.ts
    import { defineConfig } from '@rstest/core';
    
    export default defineConfig({
      browser: {
        enabled: true,
        provider: 'playwright',
        viewport: 'iPhone12Pro',
      },
    });

    Supported presets:

    PresetSize
    iPhoneSE375 x 667
    iPhoneXR414 x 896
    iPhone12Pro390 x 844
    iPhone14ProMax430 x 932
    Pixel7412 x 915
    SamsungGalaxyS8Plus360 x 740
    SamsungGalaxyS20Ultra412 x 915
    iPadMini768 x 1024
    iPadAir820 x 1180
    iPadPro1024 x 1366
    SurfacePro7912 x 1368
    SurfaceDuo540 x 720
    GalaxyZFold5344 x 882
    AsusZenbookFold853 x 1280
    SamsungGalaxyA51A71412 x 914
    NestHub1024 x 600
    NestHubMax1280 x 800
    Tip

    browser.viewport controls the test runner iframe viewport. If you need Playwright context options such as locale, color scheme, or permissions, configure them through providerOptions.context.

    port

    • Type: number
    • Default: undefined (automatically selects an available port)
    • CLI: --browser.port <port>

    The port number for the Browser Mode Dev Server.

    rstest.config.ts
    import { defineConfig } from '@rstest/core';
    
    export default defineConfig({
      browser: {
        enabled: true,
        provider: 'playwright',
        port: 5173,
      },
    });

    If you set port and the port is already in use, the behavior is controlled by strictPort: when strictPort: true, Rstest throws an error and exits; when strictPort: false, it falls back to another available port. If port is not specified, an available port is always selected automatically.

    strictPort

    • Type: boolean
    • Default: false
    • CLI: --browser.strictPort

    When port is specified, whether the port must be available:

    • true: throw an error and exit if the port is in use
    • false: fall back to another available port if the port is in use
    rstest.config.ts
    import { defineConfig } from '@rstest/core';
    
    export default defineConfig({
      browser: {
        enabled: true,
        provider: 'playwright',
        port: 5173,
        strictPort: true,
      },
    });

    providerOptions

    • Type: Record<string, unknown>
    • Default: {}
    • CLI: --browser.providerOptions.*

    Playwright options passed through to browser launch and context creation. Rstest does not validate or interpret the contents of this object — it forwards the values as-is to Playwright.

    See Playwright provider options below for the supported fields.

    rstest.config.ts
    import { defineConfig } from '@rstest/core';
    
    export default defineConfig({
      browser: {
        enabled: true,
        provider: 'playwright',
        providerOptions: {
          launch: {
            timeout: 60_000,
          },
        },
      },
    });

    You can also pass nested Playwright options from the CLI:

    npx rstest --browser.providerOptions.launch.channel=chrome

    expect.toMatchScreenshot

    • Type: BrowserScreenshotMatcherConfig
    • Default:
    {
      comparatorOptions: {
        threshold: 0.1,
        maxDiffPixels: 0,
      },
      stabilityTimeout: 2000,
      maskColor: '#FF00FF',
      caret: 'hide',
      scale: 'device',
      omitBackground: false,
    }

    maxDiffPixelRatio also defaults to 0; configure it instead of maxDiffPixels when you want to set a ratio. style is not injected by default. mask is assertion-only and defaults to no masks.

    Configure defaults for toMatchScreenshot() across a Browser Mode project. Put pixel-comparison tolerances under comparatorOptions; capture and path options are siblings of it. Assertion-level values override the corresponding global values. mask remains assertion-specific because it uses browser Locator objects.

    The defaults below apply when an option is omitted. Playwright supplies the capture defaults for maskColor, caret, scale, and omitBackground.

    OptionDefaultDescription
    comparatorOptions.threshold0.1Per-pixel color distance threshold from 0 (strict) to 1 (loose).
    comparatorOptions.maxDiffPixels0Maximum number of pixels allowed to differ.
    comparatorOptions.maxDiffPixelRatio0Maximum fraction of pixels allowed to differ.
    stabilityTimeout2000Maximum time to wait for consecutive captures to match, in ms.
    maskColor#FF00FFColor used to cover masked content.
    styleNot setNo additional CSS is injected.
    carethideHides the text caret during capture.
    scaledeviceCaptures at the device pixel ratio.
    omitBackgroundfalseKeeps the page background in the screenshot.
    screenshotDirectory__screenshots__Directory for references beside each test file.
    resolveScreenshotPathBuilt-inUses the path layout described below.

    Set either comparatorOptions.maxDiffPixels or comparatorOptions.maxDiffPixelRatio, not both. A relative screenshotDirectory is resolved from each test file's directory. If omitted, it defaults to __screenshots__. A shared directory keeps references separate by project name and test file, so paths stay stable across checkouts. When the chosen directory is the test file's own directory, Rstest places references in its __screenshots__ subdirectory.

    By default, references are stored in this layout:

    <test-directory>/__screenshots__/<test-file>/<reference-name>-<browser>-<platform>.png

    The reference name comes from the explicit name or the test name, sanitized for use as a path. Names that could collide after sanitization receive a stable suffix. Every unnamed assertion gets a sequence number starting at 1, including a test's only screenshot (for example, <test-name>-1). Explicitly named assertions do not get this number.

    Project names are not part of the default path, so projects using the same test file, screenshot name, browser, and platform share a reference. Use resolveScreenshotPath to isolate project-specific references. Existing references from Rstest's previous hashed layout are not moved automatically; move them to the new paths or regenerate them with --update.

    Use resolveScreenshotPath when you need a different layout. It receives the absolute test file path, project and test names, browser, platform, and an optional ordinal for unnamed assertions. The first unnamed assertion receives no ordinal; later ones start at 2. Return an absolute path or a path relative to the project root. When configured, the resolver takes precedence over screenshotDirectory.

    rstest.config.ts
    import path from 'node:path';
    import { defineConfig } from '@rstest/core';
    
    export default defineConfig({
      browser: {
        enabled: true,
        provider: 'playwright',
        expect: {
          toMatchScreenshot: {
            comparatorOptions: {
              threshold: 0.1,
              maxDiffPixels: 10,
            },
            resolveScreenshotPath: ({
              testFilePath,
              projectName,
              testName,
              browserName,
              platform,
            }) =>
              path.join(
                'visual-baselines',
                projectName,
                path.relative(process.cwd(), testFilePath),
                `${testName}-${browserName}-${platform}.png`,
              ),
          },
        },
      },
    });

    Current limitation: browser launch options must match in one run

    In one rstest process, all Browser Mode projects must share the same browser launch options:

    • provider
    • browser
    • headless
    • providerOptions

    Each run uses one browser engine for all Browser Mode projects, so Chromium, Firefox, and WebKit must be run in separate executions.

    For cross-browser coverage, run tests in separate executions (for example, in a CI matrix):

    npx rstest --browser.name chromium
    npx rstest --browser.name firefox
    npx rstest --browser.name webkit

    Multi-project config isolation

    When using projects in Browser Mode, each project still compiles and executes with its own build config (for example plugins, include, and framework-specific setup).

    Browser launch options still need to stay aligned across browser projects: provider, browser, headless, and providerOptions.

    rstest.config.ts
    import { defineConfig } from '@rstest/core';
    
    export default defineConfig({
      projects: ['./project-b/rstest.config.ts', './project-a/rstest.config.ts'],
    });
    project-a/rstest.config.ts
    import { pluginReact } from '@rsbuild/plugin-react';
    import { defineConfig } from '@rstest/core';
    
    export default defineConfig({
      name: 'project-a',
      plugins: [pluginReact()],
      include: ['tests/**/*.test.tsx'],
      browser: {
        enabled: true,
        provider: 'playwright',
      },
    });

    Mixing with node tests

    You can configure both browser tests and Node.js tests together:

    rstest.config.ts
    import { defineConfig } from '@rstest/core';
    
    export default defineConfig({
      projects: [
        {
          name: 'browser',
          include: ['src/**/*.browser.test.ts'],
          browser: {
            enabled: true,
            provider: 'playwright',
          },
        },
        {
          name: 'node',
          include: ['src/**/*.node.test.ts'],
          testEnvironment: 'node',
        },
        {
          name: 'jsdom',
          include: ['src/**/*.test.ts'],
          exclude: ['src/**/*.browser.test.ts', 'src/**/*.node.test.ts'],
          testEnvironment: 'jsdom',
        },
      ],
    });

    Provider options

    Playwright

    When using provider: 'playwright', the Playwright provider recognizes the following fields in providerOptions:

    1. launch — Passed to Playwright's browserType.launch(). Controls how the browser process is started.
    2. context — Passed to Playwright's browser.newContext(). Controls the browser context created for each test file.

    Since providerOptions is typed as Record<string, unknown>, you won't get IntelliSense out of the box. To get type checking and autocompletion, import types directly from the playwright package and use TypeScript's satisfies operator:

    rstest.config.ts
    import type { LaunchOptions, BrowserContextOptions } from 'playwright';
    import { defineConfig } from '@rstest/core';
    
    type PlaywrightProviderOptions = {
      launch?: LaunchOptions;
      context?: BrowserContextOptions;
    };
    
    export default defineConfig({
      browser: {
        enabled: true,
        provider: 'playwright',
        providerOptions: {
          launch: {
            timeout: 60_000,
          },
          context: {
            locale: 'en-US',
            colorScheme: 'dark',
          },
        } satisfies PlaywrightProviderOptions,
      },
    });