using-browser-mode
Set up Vitest browser mode with Playwright or WebDriverIO providers, use page and userEvent APIs, test components. Use when testing browser-specific code or UI components.
When & Why to Use This Skill
This Claude skill provides comprehensive guidance on setting up and utilizing Vitest browser mode to execute tests in real browser environments. It covers configuration with Playwright and WebDriverIO providers, the use of modern page and userEvent APIs for realistic interaction testing, and advanced patterns for component and visual regression testing.
Use Cases
- Testing browser-specific code: Execute tests that require real browser APIs such as DOM, fetch, and localStorage, which are not available in standard Node.js environments.
- Cross-browser component validation: Render and test React or Vue components in actual Chromium, Firefox, and WebKit instances to ensure UI consistency across different engines.
- Complex user interaction simulation: Use the userEvent API to automate and verify intricate user workflows, including form submissions, modal dialogs, and navigation patterns.
- Visual regression testing: Implement automated screenshot comparison to detect unintended visual changes in UI components during the development lifecycle.
- Debugging UI tests: Utilize non-headless mode and Playwright traces to visually inspect and troubleshoot failing test cases in a real browser window.
| name | using-browser-mode |
|---|---|
| description | Set up Vitest browser mode with Playwright or WebDriverIO providers, use page and userEvent APIs, test components. Use when testing browser-specific code or UI components. |
| allowed-tools | [Read, Write, Edit, Bash, Grep, Glob] |
Using Browser Mode
This skill teaches Vitest browser mode setup, configuration, and testing patterns.
Browser Mode Overview
Browser mode runs tests in actual browsers instead of Node.js environments, enabling:
- Real browser APIs (DOM, fetch, localStorage, etc.)
- Visual regression testing
- Component testing with real rendering
- User interaction testing
Provider Packages
Vitest 4.x requires separate provider packages:
Playwright Provider (Recommended)
npm install -D vitest @vitest/browser-playwright
Use when: Need Chromium, Firefox, and WebKit support with modern APIs
WebDriverIO Provider
npm install -D vitest @vitest/browser-webdriverio
Use when: Need broader browser compatibility or existing WebDriverIO infrastructure
Preview Provider
npm install -D vitest @vitest/browser-preview
Use when: Local development preview (not recommended for CI)
For detailed provider setup with all options, see references/provider-setup.md
Quick Setup
Basic Playwright Configuration
import { defineConfig } from 'vitest/config';
import { playwright } from '@vitest/browser-playwright';
export default defineConfig({
test: {
browser: {
enabled: true,
provider: playwright(),
instances: [{ browser: 'chromium' }],
headless: true,
},
},
});
Multiple Browsers
instances: [
{ browser: 'chromium' },
{ browser: 'firefox' },
{ browser: 'webkit' },
]
Browser Test APIs
Importing APIs
Correct (Vitest 4.x):
import { page, userEvent } from 'vitest/browser';
Incorrect (Vitest 3.x):
import { page, userEvent } from '@vitest/browser/context';
Page Locators
import { page } from 'vitest/browser';
const button = page.getByRole('button', { name: /submit/i });
const input = page.getByLabelText(/username/i);
const heading = page.getByRole('heading');
const text = page.getByText('Welcome');
User Interactions
import { userEvent } from 'vitest/browser';
await userEvent.fill(input, 'Bob');
await userEvent.click(checkbox);
await userEvent.selectOptions(select, 'value');
await userEvent.hover(element);
Element Assertions
import { expect } from 'vitest';
await expect.element(element).toBeInTheDocument();
await expect.element(element).toBeVisible();
await expect.element(element).toBeEnabled();
await expect.element(element).toHaveTextContent('text');
For complete browser API reference, see references/browser-apis.md
Component Testing
React Components
import { render } from 'vitest-browser-react';
test('submits form', async () => {
const screen = render(<LoginForm />);
await screen.getByLabelText(/email/i).fill('user@example.com');
await screen.getByRole('button').click();
});
For testing React components in browser mode with Vitest, use the testing-components skill for patterns integrating with @testing-library/react and React 19 APIs.
Vue Components
import { render } from 'vitest-browser-vue';
test('component renders', async () => {
const screen = render(Component, { props: { name: 'Alice' } });
await expect.element(screen.getByText('Hi, my name is Alice')).toBeInTheDocument();
});
Common Testing Patterns
Form Testing
test('form submission', async () => {
await userEvent.fill(page.getByLabelText(/email/i), 'user@example.com');
await userEvent.fill(page.getByLabelText(/password/i), 'password123');
await userEvent.click(page.getByRole('button', { name: /submit/i }));
await expect.element(page.getByText('Success')).toBeInTheDocument();
});
For browser-mode testing of Server Action forms, use the securing-server-actions skill for patterns on validation, authentication, and error handling in server actions.
Navigation Testing
test('navigation', async () => {
await userEvent.click(page.getByRole('link', { name: /about/i }));
await expect.element(page.getByRole('heading', { name: /about us/i })).toBeInTheDocument();
});
Modal Testing
test('modal dialog', async () => {
await userEvent.click(page.getByRole('button', { name: /open/i }));
const dialog = page.getByRole('dialog');
await expect.element(dialog).toBeVisible();
});
For complete testing patterns including forms, navigation, modals, and more, see references/testing-patterns.md
Visual Regression Testing
test('visual regression', async () => {
await page.goto('http://localhost:3000');
const main = page.getByRole('main');
await expect(main).toMatchScreenshot();
});
Running Browser Tests
CLI Commands
vitest --browser.enabled
vitest --browser.name chromium
vitest --browser.headless=false
Run Specific Project
vitest --project browser
Debugging
Visual Debugging
vitest --browser.headless=false
Enable Traces
vitest --browser.trace on
View traces in Playwright Trace Viewer.
Configuration Options
Headless Mode
browser: {
headless: process.env.CI ? true : false,
}
Traces
browser: {
trace: 'retain-on-failure',
}
Viewport
instances: [
{
browser: 'chromium',
context: {
viewport: { width: 1280, height: 720 },
},
},
]
Common Mistakes
- Using wrong import path: Use
vitest/browser, not@vitest/browser/context - Missing provider package: Install
@vitest/browser-playwrightor@vitest/browser-webdriverio - Wrong browser instance config: Use
instances: [{ browser: 'chromium' }], notname: 'chromium' - Not awaiting interactions: Always
awaituser events - Not using expect.element: Use
expect.element()for element assertions
Migration from Vitest 3.x
Old config:
browser: {
enabled: true,
name: 'chromium',
provider: 'playwright',
}
New config:
import { playwright } from '@vitest/browser-playwright';
browser: {
enabled: true,
provider: playwright(),
instances: [{ browser: 'chromium' }],
}
Old imports:
import { page } from '@vitest/browser/context';
New imports:
import { page } from 'vitest/browser';
References
For detailed browser mode documentation:
- Provider Setup - Playwright, WebDriverIO, Preview setup
- Browser APIs - Complete API reference with examples
- Testing Patterns - Common patterns for forms, modals, navigation
For configuration patterns, see @vitest-4/skills/configuring-vitest-4
For migration guide, see @vitest-4/skills/migrating-to-vitest-4
For complete API reference, see @vitest-4/knowledge/vitest-4-comprehensive.md