> For AI agents: the complete documentation index is available at /llms.txt, the full documentation bundle is available at /llms-full.txt.

# browser (experimental)

- **Type:**

```ts
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;
  port?: number;
  viewport?: BrowserViewport;
  strictPort?: boolean;
  providerOptions?: Record<string, unknown>;
};
```

- **Default:**

```ts
const defaultBrowser = {
  enabled: false,
  provider: 'playwright',
  browser: 'chromium',
  headless: true, // CI environment; false for local development
  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

### enabled

- **Type:** `boolean`
- **Default:** `false`
- **CLI:** `--browser`, `--browser.enabled`

Enable Browser Mode.

```ts title="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.

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

:::

### provider

- **Type:** `'playwright'`
- **Default:** `'playwright'`

Browser driver provider. Currently only [Playwright](https://playwright.dev/) is supported.

Mixing multiple providers in the same test run is currently not supported.

```ts title="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

```ts title="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:

```bash
# 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**

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

export default defineConfig({
  browser: {
    enabled: true,
    provider: 'playwright',
    headless: true,
  },
});
```


**CI (GitHub Actions)**

```yaml
# .github/workflows/test.yml
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm install
      - run: npx playwright install chromium
      - run: npm test
```


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

:::tip Dynamic Configuration Based on Environment
If you want headed mode for local debugging and headless in CI, control it with environment variables:

```ts title="rstest.config.ts"
import { defineConfig } from '@rstest/core';

export default defineConfig({
  browser: {
    enabled: true,
    provider: 'playwright',
    headless: process.env.CI === 'true',
  },
});
```

:::

### viewport


[Added in v0.8.4](https://github.com/web-infra-dev/rstest/releases/tag/v0.8.4)

- **Type:** `BrowserViewport`
- **Default:** `undefined`

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

```ts
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:

```ts title="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:

```ts title="rstest.config.ts"
import { defineConfig } from '@rstest/core';

export default defineConfig({
  browser: {
    enabled: true,
    provider: 'playwright',
    viewport: 'iPhone12Pro',
  },
});
```

Supported presets:

| Preset                  | Size        |
| ----------------------- | ----------- |
| `iPhoneSE`              | 375 x 667   |
| `iPhoneXR`              | 414 x 896   |
| `iPhone12Pro`           | 390 x 844   |
| `iPhone14ProMax`        | 430 x 932   |
| `Pixel7`                | 412 x 915   |
| `SamsungGalaxyS8Plus`   | 360 x 740   |
| `SamsungGalaxyS20Ultra` | 412 x 915   |
| `iPadMini`              | 768 x 1024  |
| `iPadAir`               | 820 x 1180  |
| `iPadPro`               | 1024 x 1366 |
| `SurfacePro7`           | 912 x 1368  |
| `SurfaceDuo`            | 540 x 720   |
| `GalaxyZFold5`          | 344 x 882   |
| `AsusZenbookFold`       | 853 x 1280  |
| `SamsungGalaxyA51A71`   | 412 x 914   |
| `NestHub`               | 1024 x 600  |
| `NestHubMax`            | 1280 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`](#provider-options).
:::

### port

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

The port number for the Browser Mode Dev Server.

```ts title="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

```ts title="rstest.config.ts"
import { defineConfig } from '@rstest/core';

export default defineConfig({
  browser: {
    enabled: true,
    provider: 'playwright',
    port: 5173,
    strictPort: true,
  },
});
```

### providerOptions


[Added in v0.9.3](https://github.com/web-infra-dev/rstest/releases/tag/v0.9.3)

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

Provider-specific options passed through to the selected browser provider. Rstest does not validate or interpret the contents of this object — it is forwarded as-is to the provider at both browser launch and context creation time.

The structure of `providerOptions` is defined by each provider. See the [Provider options](#provider-options) section below for details.

```ts title="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 provider options from the CLI:

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

## 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`

This means mixing multiple providers, or running Chromium/Firefox/WebKit together in the same run, is not supported yet.

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

```bash
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`.

```ts title="rstest.config.ts"
import { defineConfig } from '@rstest/core';

export default defineConfig({
  projects: ['./project-b/rstest.config.ts', './project-a/rstest.config.ts'],
});
```

```ts title="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:

```ts title="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()`](https://playwright.dev/docs/api/class-browsertype#browser-type-launch). Controls how the browser process is started.
2. **`context`** — Passed to Playwright's [`browser.newContext()`](https://playwright.dev/docs/api/class-browser#browser-new-context). 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:

```ts title="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,
  },
});
```

## Related links

- [Browser Mode Guide](/guide/browser-testing/index.md) - Introduction and usage guide for Browser Mode
- [Getting Started](/guide/browser-testing/getting-started.md) - Configure Browser Mode tests
- [User interactions](/guide/browser-testing/user-interactions.md#locator-api) - Write semantic tests with `page` + `expect.element`
