--- name: test-environments description: Configure environments like jsdom, happy-dom for browser APIs --- # Test Environments ## Available Environments - `node` (default) - Node.js environment - `jsdom` - Browser-like with DOM APIs - `happy-dom` - Faster alternative to jsdom - `edge-runtime` - Vercel Edge Runtime ## Configuration ```ts // vitest.config.ts defineConfig({ test: { environment: 'jsdom', // Environment-specific options environmentOptions: { jsdom: { url: 'http://localhost', }, }, }, }) ``` ## Installing Environment Packages ```bash # jsdom npm i -D jsdom # happy-dom (faster, fewer APIs) npm i -D happy-dom ``` ## Per-File Environment Use magic comment at top of file: ```ts // @vitest-environment jsdom import { expect, test } from 'vitest' test('DOM test', () => { const div = document.createElement('div') expect(div).toBeInstanceOf(HTMLDivElement) }) ``` ## jsdom Environment Full browser environment simulation: ```ts // @vitest-environment jsdom test('DOM manipulation', () => { document.body.innerHTML = '
' const app = document.getElementById('app') app.textContent = 'Hello' expect(app.textContent).toBe('Hello') }) test('window APIs', () => { expect(window.location.href).toBeDefined() expect(localStorage).toBeDefined() }) ``` ### jsdom Options ```ts defineConfig({ test: { environmentOptions: { jsdom: { url: 'http://localhost:3000', html: '', userAgent: 'custom-agent', resources: 'usable', }, }, }, }) ``` ## happy-dom Environment Faster but fewer APIs: ```ts // @vitest-environment happy-dom test('basic DOM', () => { const el = document.createElement('div') el.className = 'test' expect(el.className).toBe('test') }) ``` ## Multiple Environments per Project Use projects for different environments: ```ts defineConfig({ test: { projects: [ { test: { name: 'unit', include: ['tests/unit/**/*.test.ts'], environment: 'node', }, }, { test: { name: 'dom', include: ['tests/dom/**/*.test.ts'], environment: 'jsdom', }, }, ], }, }) ``` ## Custom Environment Create custom environment package: ```ts // vitest-environment-custom/index.ts import type { Environment } from 'vitest/runtime' export default { name: 'custom', viteEnvironment: 'ssr', // or 'client' setup() { // Setup global state globalThis.myGlobal = 'value' return { teardown() { delete globalThis.myGlobal }, } }, } ``` Use with: ```ts defineConfig({ test: { environment: 'custom', }, }) ``` ## Environment with VM For full isolation: ```ts export default { name: 'isolated', viteEnvironment: 'ssr', async setupVM() { const vm = await import('node:vm') const context = vm.createContext() return { getVmContext() { return context }, teardown() {}, } }, setup() { return { teardown() {} } }, } ``` ## Browser Mode (Separate from Environments) For real browser testing, use Vitest Browser Mode: ```ts defineConfig({ test: { browser: { enabled: true, name: 'chromium', // or 'firefox', 'webkit' provider: 'playwright', }, }, }) ``` ## CSS and Assets In jsdom/happy-dom, configure CSS handling: ```ts defineConfig({ test: { css: true, // Process CSS // Or with options css: { include: /\.module\.css$/, modules: { classNameStrategy: 'non-scoped', }, }, }, }) ``` ## Fixing External Dependencies If external deps fail with CSS/asset errors: ```ts defineConfig({ test: { server: { deps: { inline: ['problematic-package'], }, }, }, }) ``` ## Key Points - Default is `node` - no browser APIs - Use `jsdom` for full browser simulation - Use `happy-dom` for faster tests with basic DOM - Per-file environment via `// @vitest-environment` comment - Use projects for multiple environment configurations - Browser Mode is for real browser testing, not environment