Subchapter 13.13
references/features-context.mdMarkdown5 KBView on GitHub
Every test receives context as its first argument:
test('context', ({ task, expect, skip, signal, annotate }) => {
console.log(task.name) // Test metadata (readonly)
expect(1).toBe(1) // Expect bound to this test
skip(condition, 'reason') // Skip dynamically
})Properties:
task — test metadata (name, file, etc.)expect — expect bound to this test (required for concurrent snapshot tests)skip(condition?, message?) — skip the testsignal (3.2+) — AbortSignal aborted on timeout/cancel/bailannotate(message, type?, attachment?) (3.2+) — attach reporter annotationsonTestFinished(fn) / onTestFailed(fn) — per-test cleanup/handlersbench (v5) — benchmark fixture (only in *.bench.ts files).extend(name, options?, fixture) infers types automatically. Use onCleanup for teardown:
import { test as baseTest } from 'vitest'
export const test = baseTest
// Plain value — type inferred as { port: number; host: string }
.extend('config', { port: 3000, host: 'localhost' })
// Function fixture — can read previously defined fixtures
.extend('server', async ({ config }, { onCleanup }) => {
const server = await startServer(config)
onCleanup(() => server.close()) // runs after test/scope ends
return server
})
test('uses server', ({ config, server }) => {
expect(server.url).toContain(String(config.port))
})
onCleanupcan be called once per fixture. For multiple resources, split into separate fixtures.
const test = baseTest
.extend('metrics', { auto: true }, () => new Metrics()) // runs for every test
.extend('config', { scope: 'worker' }, () => loadConfig()) // once per worker
.extend('db', { scope: 'file' }, async ({ config }, { onCleanup }) => {
const db = await createDatabase(config)
onCleanup(() => db.close())
return db
})
.extend('baseUrl', { injected: true }, () => 'http://localhost:3000') // overridable via configUses the use() callback; types must be declared manually:
const test = baseTest.extend<{ page: Page; baseUrl: string }>({
page: async ({}, use) => {
const page = await browser.newPage()
await use(page) // test runs here
await page.close() // cleanup after
},
baseUrl: 'http://localhost:3000',
})Tuple form sets options: fixture: [async ({}, use) => {…}, { scope: 'file' }].
| Scope | Lifetime | Can access |
|---|---|---|
test (default) | each test | worker + file + test fixtures + built-in context |
file | once per file | worker + file fixtures |
worker | once per worker process | only worker fixtures |
Only test-scoped fixtures can access the built-in context (task, expect, …). In file/worker fixtures use expect.getState().testPath for the file path. By default every file is its own worker, so file and worker behave the same unless isolation is disabled.
// fixtures.ts
const test = baseTest.extend('url', { injected: true }, '/default')
// vitest.config.ts — provide per project
defineConfig({
test: {
projects: [
{ test: { name: 'prod', provide: { url: 'https://prod' } } },
],
},
})Read raw provided values without fixtures via import { inject } from 'vitest'.
test.override replaces fixture values for a suite and its children (replaces the deprecated test.scoped):
describe('production', () => {
test
.override('config', { port: 8080, host: 'api.example.com' })
.override('debug', false) // chainable
test('uses prod config', ({ server }) => {
expect(server.url).toBe('http://api.example.com:8080')
})
})
// Function override (reads other fixtures) with cleanup
test.override('db', async ({ config }, { onCleanup }) => {
const db = await createTestDatabase(config)
onCleanup(() => db.drop())
return db
})You cannot introduce new fixtures or change scope/auto via override; use test.extend for new fixtures.
Extend an already-extended test, and use type-aware hooks on the extended test:
import { test as dbTest } from './db-test'
export const test = dbTest.extend('user', ({ db }) => db.createUser())
test.beforeEach(({ db }) => db.seed()) // sees fixtures
test.beforeAll(({ db }) => db.migrate()) // file/worker fixtures only (4.1+)
test.aroundAll(async (run, { db }) => db.tx(run))onCleanup{ db } (not context.db){ scope: 'file' | 'worker' } for expensive shared resourcestest.override (not test.scoped) to vary fixture values per suite{ injected: true } + project provide for per-project values