0
# Browser Testing
1
2
Vitest provides native browser testing capabilities for running tests in real browser environments. Import from `vitest/browser`.
3
4
## Capabilities
5
6
### Browser Commands
7
8
File system commands available in browser context.
9
10
```typescript { .api }
11
interface BrowserCommands {
12
/**
13
* Read file from file system
14
* @param path - File path
15
* @param options - Read options
16
* @returns Promise resolving to file contents
17
*/
18
readFile(
19
path: string,
20
options?: { encoding?: BufferEncoding }
21
): Promise<string>;
22
23
/**
24
* Write file to file system
25
* @param path - File path
26
* @param content - File content
27
* @param options - Write options
28
* @returns Promise resolving when write completes
29
*/
30
writeFile(
31
path: string,
32
content: string,
33
options?: { encoding?: BufferEncoding }
34
): Promise<void>;
35
36
/**
37
* Remove file from file system
38
* @param path - File path
39
* @returns Promise resolving when file is removed
40
*/
41
removeFile(path: string): Promise<void>;
42
}
43
```
44
45
**Usage:**
46
47
```typescript
48
import { test, expect } from 'vitest';
49
import { readFile, writeFile, removeFile } from 'vitest/browser';
50
51
test('file operations', async () => {
52
await writeFile('./test.txt', 'Hello World');
53
54
const content = await readFile('./test.txt');
55
expect(content).toBe('Hello World');
56
57
await removeFile('./test.txt');
58
});
59
```
60
61
### Browser Coverage
62
63
Coverage collection APIs for browser tests.
64
65
```typescript { .api }
66
/**
67
* Start coverage collection in browser worker
68
* @returns Promise resolving when coverage starts
69
*/
70
function startCoverageInsideWorker(): Promise<void>;
71
72
/**
73
* Stop coverage collection in browser worker
74
* @returns Promise resolving when coverage stops
75
*/
76
function stopCoverageInsideWorker(): Promise<void>;
77
78
/**
79
* Take coverage snapshot in browser worker
80
* @returns Promise resolving to coverage data
81
*/
82
function takeCoverageInsideWorker(): Promise<Coverage>;
83
```
84
85
**Usage:**
86
87
```typescript
88
import { test, expect } from 'vitest';
89
import {
90
startCoverageInsideWorker,
91
takeCoverageInsideWorker,
92
stopCoverageInsideWorker
93
} from 'vitest/browser';
94
95
test('with coverage', async () => {
96
await startCoverageInsideWorker();
97
98
// Test code
99
100
const coverage = await takeCoverageInsideWorker();
101
expect(coverage).toBeDefined();
102
103
await stopCoverageInsideWorker();
104
});
105
```
106
107
### Browser Utilities
108
109
Utility functions for browser testing.
110
111
```typescript { .api }
112
/**
113
* Format values for display
114
*/
115
function format(...args: any[]): string;
116
117
/**
118
* Inspect objects
119
*/
120
function inspect(value: any, options?: InspectOptions): string;
121
122
/**
123
* Stringify values
124
*/
125
function stringify(value: any, options?: StringifyOptions): string;
126
127
/**
128
* Process error objects
129
*/
130
function processError(error: unknown): Error;
131
132
/**
133
* Get JavaScript type of value
134
*/
135
function getType(value: any): string;
136
137
/**
138
* Get safe timer functions
139
*/
140
function getSafeTimers(): SafeTimers;
141
142
/**
143
* Set safe timer functions
144
*/
145
function setSafeTimers(timers: SafeTimers): void;
146
147
/**
148
* Get original position from source map
149
*/
150
function getOriginalPosition(map: DecodedMap, pos: Position): Position | null;
151
152
/**
153
* Decoded source map class
154
*/
155
class DecodedMap {
156
// Source map utilities
157
}
158
159
/**
160
* Collect tests in browser
161
*/
162
function collectTests(): Promise<void>;
163
164
/**
165
* Start tests in browser
166
*/
167
function startTests(): Promise<void>;
168
```
169
170
## Browser Configuration
171
172
Configure browser testing in vitest.config.ts:
173
174
```typescript
175
import { defineConfig } from 'vitest/config';
176
177
export default defineConfig({
178
test: {
179
browser: {
180
enabled: true,
181
name: 'chrome', // or 'firefox', 'safari', 'edge'
182
provider: 'playwright', // or 'webdriverio', 'preview'
183
headless: true,
184
screenshotFailures: true,
185
viewport: {
186
width: 1280,
187
height: 720
188
}
189
}
190
}
191
});
192
```
193
194
### Browser Providers
195
196
Three browser providers available:
197
198
1. **playwright** - Uses Playwright for browser automation
199
2. **webdriverio** - Uses WebdriverIO for browser automation
200
3. **preview** - Lightweight preview mode
201
202
```typescript
203
// Install provider
204
npm install -D @vitest/browser-playwright
205
// or
206
npm install -D @vitest/browser-webdriverio
207
```
208
209
### Browser Configuration Options
210
211
```typescript { .api }
212
interface BrowserConfigOptions {
213
/** Enable browser mode */
214
enabled?: boolean;
215
216
/** Browser name */
217
name?: 'chrome' | 'firefox' | 'safari' | 'edge';
218
219
/** Browser provider */
220
provider?: 'playwright' | 'webdriverio' | 'preview';
221
222
/** Run in headless mode */
223
headless?: boolean;
224
225
/** Take screenshots on failure */
226
screenshotFailures?: boolean;
227
228
/** Viewport size */
229
viewport?: {
230
width: number;
231
height: number;
232
};
233
234
/** Browser instance options */
235
providerOptions?: Record<string, any>;
236
237
/** API server configuration */
238
api?: {
239
port?: number;
240
host?: string;
241
};
242
243
/** Scripts to load in browser */
244
scripts?: BrowserScript[];
245
246
/** Isolate tests */
247
isolate?: boolean;
248
249
/** File parallelism */
250
fileParallelism?: boolean;
251
}
252
253
interface BrowserScript {
254
/** Script content or path */
255
content?: string;
256
src?: string;
257
258
/** Load timing */
259
async?: boolean;
260
type?: string;
261
}
262
```
263
264
## Browser-Specific Matchers
265
266
### Screenshot Matching
267
268
```typescript { .api }
269
interface Assertion<T> {
270
/**
271
* Match screenshot against baseline
272
* @param options - Screenshot comparison options
273
*/
274
toMatchScreenshot(options?: ToMatchScreenshotOptions): Promise<void>;
275
}
276
277
interface ToMatchScreenshotOptions {
278
/** Threshold for image comparison (0-1) */
279
threshold?: number;
280
281
/** Baseline screenshot path */
282
name?: string;
283
284
/** Include only specific element */
285
element?: HTMLElement;
286
287
/** Viewport size for screenshot */
288
viewport?: {
289
width: number;
290
height: number;
291
};
292
}
293
```
294
295
**Usage:**
296
297
```typescript
298
import { test, expect } from 'vitest';
299
300
test('visual regression', async () => {
301
const element = document.querySelector('.my-component');
302
303
await expect(element).toMatchScreenshot({
304
threshold: 0.1,
305
name: 'my-component'
306
});
307
});
308
```
309
310
## Common Patterns
311
312
### DOM Testing
313
314
```typescript
315
import { test, expect } from 'vitest';
316
317
test('DOM manipulation', () => {
318
const button = document.createElement('button');
319
button.textContent = 'Click me';
320
button.onclick = () => {
321
button.textContent = 'Clicked!';
322
};
323
324
document.body.appendChild(button);
325
326
button.click();
327
328
expect(button.textContent).toBe('Clicked!');
329
330
button.remove();
331
});
332
```
333
334
### Browser API Testing
335
336
```typescript
337
import { test, expect } from 'vitest';
338
339
test('localStorage', () => {
340
localStorage.setItem('key', 'value');
341
342
expect(localStorage.getItem('key')).toBe('value');
343
344
localStorage.removeItem('key');
345
expect(localStorage.getItem('key')).toBeNull();
346
});
347
348
test('fetch API', async () => {
349
const response = await fetch('/api/data');
350
const data = await response.json();
351
352
expect(data).toBeDefined();
353
});
354
```
355
356
### Component Testing
357
358
```typescript
359
import { test, expect } from 'vitest';
360
import { render } from '@testing-library/react';
361
import MyComponent from './MyComponent';
362
363
test('renders component', () => {
364
const { container } = render(<MyComponent />);
365
366
expect(container.querySelector('.my-component')).toBeTruthy();
367
});
368
```
369
370
### Multi-Browser Testing
371
372
Configure multiple browser projects using the `projects` option:
373
374
```typescript
375
// vitest.config.ts
376
import { defineConfig } from 'vitest/config';
377
378
export default defineConfig({
379
test: {
380
projects: [
381
{
382
test: {
383
name: 'chrome',
384
browser: {
385
enabled: true,
386
name: 'chrome'
387
}
388
}
389
},
390
{
391
test: {
392
name: 'firefox',
393
browser: {
394
enabled: true,
395
name: 'firefox'
396
}
397
}
398
},
399
{
400
test: {
401
name: 'safari',
402
browser: {
403
enabled: true,
404
name: 'safari'
405
}
406
}
407
}
408
]
409
}
410
});
411
```
412
413
## Running Browser Tests
414
415
```bash
416
# Run browser tests
417
vitest --browser
418
419
# Run in specific browser
420
vitest --browser.name=chrome
421
422
# Run with UI
423
vitest --browser --ui
424
```
425
426
## Type Definitions
427
428
```typescript { .api }
429
interface Coverage {
430
functions: FunctionCoverage[];
431
statements: StatementCoverage[];
432
branches: BranchCoverage[];
433
}
434
435
interface FunctionCoverage {
436
name: string;
437
count: number;
438
line: number;
439
column: number;
440
}
441
442
interface SafeTimers {
443
setTimeout: typeof setTimeout;
444
setInterval: typeof setInterval;
445
clearTimeout: typeof clearTimeout;
446
clearInterval: typeof clearInterval;
447
setImmediate: typeof setImmediate;
448
clearImmediate: typeof clearImmediate;
449
}
450
451
interface Position {
452
line: number;
453
column: number;
454
}
455
456
interface InspectOptions {
457
depth?: number;
458
colors?: boolean;
459
compact?: boolean;
460
}
461
462
interface StringifyOptions {
463
indent?: number;
464
maxLength?: number;
465
}
466
```
467
468
## Environment Setup
469
470
Browser tests can use different DOM implementations:
471
472
1. **Real Browser** (browser mode)
473
2. **JSDOM** (jsdom environment)
474
3. **Happy DOM** (happy-dom environment)
475
476
```typescript
477
// Real browser
478
export default defineConfig({
479
test: {
480
browser: {
481
enabled: true,
482
name: 'chrome'
483
}
484
}
485
});
486
487
// JSDOM (simulated)
488
export default defineConfig({
489
test: {
490
environment: 'jsdom'
491
}
492
});
493
494
// Happy DOM (simulated, faster)
495
export default defineConfig({
496
test: {
497
environment: 'happy-dom'
498
}
499
});
500
```
501