Playwright
@rstest/playwright provides Playwright fixtures and Playwright-style assertions for Rstest tests that run in Node.js workers. Use it for E2E tests against a complete page or app, such as a local dev server, a preview server, or a deployed URL. The test runs in Node.js and uses Playwright to drive the page.
Rstest browser mode vs playwright
The main difference is the testing scenario: Rstest browser mode prepares a browser runtime for your test modules, while @rstest/playwright controls a page that is already prepared by your app or server.
Because @rstest/playwright controls an external page instead of running the test in Rstest's browser runner, it does not use the Browser UI preview iframe. For visual debugging, use headed mode with RSTEST_PLAYWRIGHT_DEBUG=true.
Rstest playwright vs native playwright
@rstest/playwright and native Playwright use different runners and configuration files:
Use @rstest/playwright when you want Playwright-driven E2E tests to run in the same Rstest workflow as the rest of your tests. Use native Playwright when you want the full Playwright Test runner workflow and its configuration model.
Install
Install both packages:
- @rstest/playwright adds the Rstest fixtures and assertions.
- playwright provides the browser automation runtime.
Basic usage
Import test and expect from @rstest/playwright instead of @rstest/core:
Regular lifecycle helpers are also available from @rstest/playwright:
Fixtures
@rstest/playwright provides these fixtures:
Use request when you only need Playwright's API client and do not need to launch a browser:
Assertions
expect keeps normal Rstest assertions. When the actual value is a Playwright Locator or Page, it also provides retrying Playwright-style async assertions.
Locator assertions are aligned with the element assertions already supported by @rstest/browser where possible:
toBeVisible(options?)toBeHidden(options?)toBeEnabled(options?)toBeDisabled(options?)toBeChecked(options?)toBeUnchecked(options?)toBeAttached(options?)toBeDetached(options?)toBeEditable(options?)toBeFocused(options?)toBeEmpty(options?)toBeInViewport(options?)toContainText(expected, options?)toHaveAttribute(name, expected?, options?)toHaveClass(expected, options?)toHaveCSS(propertyName, expected, options?)toHaveCount(expected, options?)toHaveId(expected, options?)toHaveJSProperty(name, expected, options?)toHaveText(expected, options?)toHaveValue(expected, options?)
Page assertions:
toHaveTitle(expected, options?)toHaveURL(expected, options?)
String text assertions normalize whitespace. Playwright assertions retry until they pass or the timeout option is reached. The default timeout is 5000 milliseconds.
.not and expect.soft are also supported:
Configuration
Global playwright configuration is not supported yet. Override the playwright fixture when a test file needs custom Playwright options:
The playwright fixture supports these options:
For Playwright E2E projects, set isolate: false in rstest.config.ts to reuse the worker module cache across test files and avoid repeated Playwright startup cost:
Local app server
Use the serve fixture when a test needs to serve a built app. It starts a static server for the entry file and automatically stops the server after the test.
When RSTEST_PLAYWRIGHT_DEBUG=true is enabled, serve keeps the server alive by default so the opened page remains available for inspection. Set keepAliveOnDebug: false if you want the server to close even in debug mode.
Headed debugging
Set RSTEST_PLAYWRIGHT_DEBUG=true to launch Chromium in headed mode while debugging locally:
This environment variable keeps your tests unchanged and applies these defaults:
headless: falseslowMo: 100devtools: true
You can also override the debug defaults from the test:
To stop on a page while debugging, use Playwright's page.pause() with a zero test timeout:
In debug mode, failed tests automatically call page.pause() before closing the page and context. Set pauseOnFailure: false in debug options, or RSTEST_PLAYWRIGHT_PAUSE=false, to disable this behavior.
For non-interactive debugging in CI or local runs, capture a screenshot when a test fails:
This keeps the test runner non-blocking while preserving the failed page state as an artifact. See examples/playwright for a complete Rsbuild + Playwright example.