963 markdown files reformatted with the repository's pinned prettier so pnpm format:check covers the folded tree like every other repo file. The formatter's embedded-language pass also normalized code fences (TS semicolons, closed HTML tags in examples, lowercased CSS hex colors, one renumbered list that skipped an index). Alphanumeric token deltas vs the fold commit were audited file-by-file; all are formatter-equivalent markup normalizations plus the four sanitized skills.
4.3 KiB
4.3 KiB
name, description
| name | description |
|---|---|
| test-context-fixtures | Test context, custom fixtures with test.extend |
Test Context & Fixtures
Built-in Context
Every test receives context as first argument:
test('context', ({ task, expect, skip }) => {
console.log(task.name); // Test name
expect(1).toBe(1); // Context-bound expect
skip(); // Skip test dynamically
});
Context Properties
task- Test metadata (name, file, etc.)expect- Expect bound to this test (important for concurrent tests)skip(condition?, message?)- Skip the testonTestFinished(fn)- Cleanup after testonTestFailed(fn)- Run on failure only
Custom Fixtures with test.extend
Create reusable test utilities:
import { test as base } from 'vitest';
// Define fixture types
interface Fixtures {
db: Database;
user: User;
}
// Create extended test
export const test = base.extend<Fixtures>({
// Fixture with setup/teardown
db: async ({}, use) => {
const db = await createDatabase();
await use(db); // Provide to test
await db.close(); // Cleanup
},
// Fixture depending on another fixture
user: async ({ db }, use) => {
const user = await db.createUser({ name: 'Test' });
await use(user);
await db.deleteUser(user.id);
},
});
Using fixtures:
test('query user', async ({ db, user }) => {
const found = await db.findUser(user.id);
expect(found).toEqual(user);
});
Fixture Initialization
Fixtures only initialize when accessed:
const test = base.extend({
expensive: async ({}, use) => {
console.log('initializing'); // Only runs if test uses it
await use('value');
},
});
test('no fixture', () => {}); // expensive not called
test('uses fixture', ({ expensive }) => {}); // expensive called
Auto Fixtures
Run fixture for every test:
const test = base.extend({
setup: [
async ({}, use) => {
await globalSetup();
await use();
await globalTeardown();
},
{ auto: true }, // Always run
],
});
Scoped Fixtures
File Scope
Initialize once per file:
const test = base.extend({
connection: [
async ({}, use) => {
const conn = await connect();
await use(conn);
await conn.close();
},
{ scope: 'file' },
],
});
Worker Scope
Initialize once per worker:
const test = base.extend({
sharedResource: [
async ({}, use) => {
await use(globalResource);
},
{ scope: 'worker' },
],
});
Injected Fixtures (from Config)
Override fixtures per project:
// test file
const test = base.extend({
apiUrl: ['/default', { injected: true }],
});
// vitest.config.ts
defineConfig({
test: {
projects: [
{
test: {
name: 'prod',
provide: { apiUrl: 'https://api.prod.com' },
},
},
],
},
});
Scoped Values per Suite
Override fixture for specific suite:
const test = base.extend({
environment: 'development',
});
describe('production tests', () => {
test.scoped({ environment: 'production' });
test('uses production', ({ environment }) => {
expect(environment).toBe('production');
});
});
test('uses default', ({ environment }) => {
expect(environment).toBe('development');
});
Extended Test Hooks
Type-aware hooks with fixtures:
const test = base.extend<{ db: Database }>({
db: async ({}, use) => {
const db = await createDb();
await use(db);
await db.close();
},
});
// Hooks know about fixtures
test.beforeEach(({ db }) => {
db.seed();
});
test.afterEach(({ db }) => {
db.clear();
});
Composing Fixtures
Extend from another extended test:
// base-test.ts
export const test = base.extend<{ db: Database }>({
db: async ({}, use) => {
/* ... */
},
});
// admin-test.ts
import { test as dbTest } from './base-test';
export const test = dbTest.extend<{ admin: User }>({
admin: async ({ db }, use) => {
const admin = await db.createAdmin();
await use(admin);
},
});
Key Points
- Use
{ }destructuring to access fixtures - Fixtures are lazy - only initialize when accessed
- Return cleanup function from fixtures
- Use
{ auto: true }for setup fixtures - Use
{ scope: 'file' }for expensive shared resources - Fixtures compose - extend from extended tests