Mock with spy option for exported functions
To bypass the module spying limitation in browser mode, use 'vi.mock('./module.js', { spy: true })'. This will automatically spy on every export in the module without replacing them with fake ones, allowing you to use 'vi.mocked()' to access and modify the mocked functions.
Spying on module exports with spy: true example
```ts
import { vi } from 'vitest'
import * as module from './module.js'
vi.mock('./module.js', { spy: true })
vi.mocked(module.method).mockImplementation(() => {
// ...
})
```
This example shows how to use the spy option in vi.mock to automatically spy on module exports and then modify their implementation using vi.mocked.
Mocking exported variables workaround
The only way to mock exported variables in browser mode is to export a method that will change the internal value. For example, export the variable and a function that changes it, then call the function in the test to modify the variable's value.
Exported variable mocking example
```js
// module.js
export let MODE = 'test'
export function changeMode(newMode) {
MODE = newMode
}
```
```js
// module.test.ts
import { expect } from 'vitest'
import { changeMode, MODE } from './module.js'
changeMode('production')
expect(MODE).toBe('production')
```
This example demonstrates how to export a variable and a function to change it, then use the function in tests to modify the variable's value.
DOM and browser APIs mocking environments
Vitest supports both happy-dom or jsdom for mocking DOM and browser APIs. These don't come with Vitest and must be installed separately. Configure the environment with the environment option in vitest.config.ts set to 'happy-dom', 'jsdom', or 'node'.
vi.spyOn limitations in Browser Mode
vi.spyOn does not work for spying on module exports in Browser Mode. Use alternative workarounds documented in the browser limitations section.
vi.spyOn not available in Browser Mode
vi.spyOn will not work in Browser Mode because it uses the browser's native ESM support to serve modules. The module namespace object is sealed and cannot be reconfigured. To work around this limitation, use the { spy: true } option in vi.mock instead.
vi.mock with spy: true option in Browser Mode
In Browser Mode, use { spy: true } option in vi.mock to automatically spy on every export in the module without replacing them with fake ones. After calling vi.mock with spy: true, use vi.mocked() to access the mocked functions. For example: `vi.mock('./example.js', { spy: true })` followed by `vi.mocked(exampleObject.answer).mockReturnValue(0)`.
Module mocking in Browser Mode implementation
Vitest uses native ESM in Browser Mode. Instead of replacing the module directly, Vitest intercepts fetch requests (via playwright's page.route or a Vite plugin API for preview or webdriverio) and serves transformed code if the module was mocked. For automocked modules, Vitest parses static exports and creates a placeholder module that holds mocked values. For custom factories, Vitest resolves the factory in the browser, passes the keys back to the server, and uses them to create a placeholder module that can be served back to the browser.
OpenTelemetry in browser mode
When running tests in browser mode, Vitest propagates trace context between Node.js and the browser. Node.js side traces (test orchestration, browser driver communication) are available without additional configuration. To capture traces from the browser runtime, provide a browser-compatible SDK via browserSdkPath.
OpenTelemetry browser SDK packages
For browser mode tracing, install: @opentelemetry/sdk-trace-web and @opentelemetry/exporter-trace-otlp-proto.
OpenTelemetry browser SDK configuration example
Example browser SDK file (otel-browser.js): import { BatchSpanProcessor, WebTracerProvider } from '@opentelemetry/sdk-trace-web'; import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-proto'; const provider = new WebTracerProvider({ spanProcessors: [new BatchSpanProcessor(new OTLPTraceExporter())], }); provider.register(); export default provider. Example vitest.config.js: import { defineConfig } from 'vitest/config'; export default defineConfig({ test: { browser: { enabled: true, provider: 'playwright', instances: [{ browser: 'chromium' }], }, experimental: { openTelemetry: { enabled: true, sdkPath: './otel.js', browserSdkPath: './otel-browser.js', }, }, }, });
OpenTelemetry browser async context pitfall
Unlike Node.js, browsers do not have automatic async context propagation. Vitest handles this internally for test execution, but custom spans in deeply nested async code may not propagate context automatically.