.agents/skills/vitest/references/advanced-environments.md
node (default) - Node.js environmentjsdom - Browser-like with DOM APIshappy-dom - Faster alternative to jsdomedge-runtime - Vercel Edge Runtime// vitest.config.ts
defineConfig({
test: {
environment: 'jsdom',
// Environment-specific options
environmentOptions: {
jsdom: {
url: 'http://localhost',
},
},
},
})
# jsdom
npm i -D jsdom
# happy-dom (faster, fewer APIs)
npm i -D happy-dom
Use magic comment at top of file:
// @vitest-environment jsdom
import { expect, test } from 'vitest'
test('DOM test', () => {
const div = document.createElement('div')
expect(div).toBeInstanceOf(HTMLDivElement)
})
Full browser environment simulation:
// @vitest-environment jsdom
test('DOM manipulation', () => {
document.body.innerHTML = '<div id="app"></div>'
const app = document.getElementById('app')
app.textContent = 'Hello'
expect(app.textContent).toBe('Hello')
})
test('window APIs', () => {
expect(window.location.href).toBeDefined()
expect(localStorage).toBeDefined()
})
defineConfig({
test: {
environmentOptions: {
jsdom: {
url: 'http://localhost:3000',
html: '<!DOCTYPE html><html><body></body></html>',
userAgent: 'custom-agent',
resources: 'usable',
},
},
},
})
Faster but fewer APIs:
// @vitest-environment happy-dom
test('basic DOM', () => {
const el = document.createElement('div')
el.className = 'test'
expect(el.className).toBe('test')
})
Use projects for different environments:
defineConfig({
test: {
projects: [
{
test: {
name: 'unit',
include: ['tests/unit/**/*.test.ts'],
environment: 'node',
},
},
{
test: {
name: 'dom',
include: ['tests/dom/**/*.test.ts'],
environment: 'jsdom',
},
},
],
},
})
Create custom environment package:
// vitest-environment-custom/index.ts
import type { Environment } from 'vitest/runtime'
export default <Environment>{
name: 'custom',
viteEnvironment: 'ssr', // or 'client'
setup() {
// Setup global state
globalThis.myGlobal = 'value'
return {
teardown() {
delete globalThis.myGlobal
},
}
},
}
Use with:
defineConfig({
test: {
environment: 'custom',
},
})
For full isolation:
export default <Environment>{
name: 'isolated',
viteEnvironment: 'ssr',
async setupVM() {
const vm = await import('node:vm')
const context = vm.createContext()
return {
getVmContext() {
return context
},
teardown() {},
}
},
setup() {
return { teardown() {} }
},
}
For real browser testing, use Vitest Browser Mode:
defineConfig({
test: {
browser: {
enabled: true,
name: 'chromium', // or 'firefox', 'webkit'
provider: 'playwright',
},
},
})
In jsdom/happy-dom, configure CSS handling:
defineConfig({
test: {
css: true, // Process CSS
// Or with options
css: {
include: /\.module\.css$/,
modules: {
classNameStrategy: 'non-scoped',
},
},
},
})
If external deps fail with CSS/asset errors:
defineConfig({
test: {
server: {
deps: {
inline: ['problematic-package'],
},
},
},
})
node - no browser APIsjsdom for full browser simulationhappy-dom for faster tests with basic DOM// @vitest-environment comment