
Vitest Testing
- 442 installs
- 74 repo stars
- Updated July 21, 2026
- existential-birds/beagle
vitest-testing is a beagle agent skill that teaches Vitest unit and integration testing patterns including vitest.config setup, vi.mock mocking, snapshots, coverage, and async assertions for TypeScript and JavaScript cod
About
vitest-testing is an existential-birds/beagle skill bundled in the beagle-react plugin for Vitest testing framework patterns and best practices. It triggers on describe, it, expect, vi.mock, vi.fn, beforeEach, afterEach, and vitest.config work. The main SKILL.md covers async testing with await on resolves/rejects matchers and a quick mock reference, while three deeper references split mocking, vitest.config.ts setup with v8 or istanbul coverage, and patterns for timers and snapshots. Developers reach for vitest-testing when setting up Vitest in TypeScript or JavaScript projects, debugging flaky async tests, configuring jsdom or node environments, or preparing CI-friendly coverage reports. Verification gates in the skill help catch silent false positives from missing await on async matchers.
- Vitest config and Vite integration
- Unit, component, and integration test patterns
- Mocking, spies, and fixture setup
- Coverage thresholds and watch mode
- CI-ready test scripts and failure triage
Vitest Testing by the numbers
- 442 all-time installs (skills.sh)
- Ranked #633 of 2,153 Testing & QA skills by installs in the Skillselion catalog
- Data as of Jul 28, 2026 (Skillselion catalog sync)
npx skills add https://github.com/existential-birds/beagle --skill vitest-testingAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 442 |
|---|---|
| repo stars | ★ 74 |
| Last updated | July 21, 2026 |
| Repository | existential-birds/beagle ↗ |
How do you set up Vitest mocks and coverage in TypeScript?
Set up Vitest, write unit and integration tests for TypeScript/JavaScript codebases, configure mocks, coverage, and CI-friendly test runs before release.
Who is it for?
TypeScript and JavaScript developers writing or fixing Vitest unit and integration tests before release.
Skip if: Jest-only codebases, end-to-end browser test suites, or teams not using the Vitest runner.
When should I use this skill?
A developer writes describe/it tests, configures vitest.config, uses vi.mock or vi.fn, or sets up Vitest coverage and async assertions.
What you get
Vitest test suites, vitest.config.ts files, mock setups, and coverage reports ready for CI runs.
- Unit test files
- vitest.config.ts
- Coverage configuration
By the numbers
- Includes 3 reference documents: mocking.md, config.md, and patterns.md
Files
Vitest Best Practices
Quick Reference
import { describe, it, expect, beforeEach, vi } from 'vitest'
describe('feature name', () => {
beforeEach(() => {
vi.clearAllMocks()
})
it('should do something specific', () => {
expect(actual).toBe(expected)
})
it.todo('planned test')
it.skip('temporarily disabled')
it.only('run only this during dev')
})Common Assertions
// Equality
expect(value).toBe(42) // Strict (===)
expect(obj).toEqual({ a: 1 }) // Deep equality
expect(obj).toStrictEqual({ a: 1 }) // Strict deep (checks types)
// Truthiness
expect(value).toBeTruthy()
expect(value).toBeFalsy()
expect(value).toBeNull()
expect(value).toBeUndefined()
// Numbers
expect(0.1 + 0.2).toBeCloseTo(0.3)
expect(value).toBeGreaterThan(5)
// Strings/Arrays
expect(str).toMatch(/pattern/)
expect(str).toContain('substring')
expect(array).toContain(item)
expect(array).toHaveLength(3)
// Objects
expect(obj).toHaveProperty('key')
expect(obj).toHaveProperty('nested.key', 'value')
expect(obj).toMatchObject({ subset: 'of properties' })
// Exceptions
expect(() => fn()).toThrow()
expect(() => fn()).toThrow('error message')
expect(() => fn()).toThrow(/pattern/)Async Testing
// Async/await (preferred)
it('fetches data', async () => {
const data = await fetchData()
expect(data).toEqual({ id: 1 })
})
// Promise matchers - ALWAYS await these
await expect(fetchData()).resolves.toEqual({ id: 1 })
await expect(fetchData()).rejects.toThrow('Error')
// Wrong - creates false positive
expect(promise).resolves.toBe(value) // Missing await!Quick Mock Reference
const mockFn = vi.fn()
mockFn.mockReturnValue(42)
mockFn.mockResolvedValue({ data: 'value' })
expect(mockFn).toHaveBeenCalled()
expect(mockFn).toHaveBeenCalledWith('arg1', 'arg2')
expect(mockFn).toHaveBeenCalledTimes(2)Verification gates
Use this sequence when you add or change tests; each step has an objective pass condition.
1. Run the test suite — From the package or workspace root, run the same command CI uses (check package.json scripts; often vitest run, pnpm test, or npm test). Pass: exit code is 0 and the report shows zero failing tests. 2. Async matchers — Pass: every expect(…).resolves and expect(…).rejects is prefixed with await (await expect(...)), as in Async Testing. A line where resolves or rejects appears without await fails this gate.
Additional Documentation
- Mocking: See references/mocking.md for module mocking, spying, cleanup
- Configuration: See references/config.md for vitest.config, setup files, coverage
- Patterns: See references/patterns.md for timers, snapshots, anti-patterns
Test Methods Quick Reference
| Method | Purpose |
|---|---|
it() / test() | Define test |
describe() | Group tests |
beforeEach() / afterEach() | Per-test hooks |
beforeAll() / afterAll() | Per-suite hooks |
.skip | Skip test/suite |
.only | Run only this |
.todo | Placeholder |
.concurrent | Parallel execution |
.each([...]) | Parameterized tests |
Configuration
Basic Config
// vitest.config.ts
import { defineConfig } from 'vitest/config'
export default defineConfig({
test: {
globals: true, // Use global test APIs (describe, it, expect)
environment: 'node', // 'node' | 'jsdom' | 'happy-dom'
setupFiles: './test/setup.ts',
coverage: {
provider: 'v8', // 'v8' | 'istanbul'
reporter: ['text', 'json', 'html'],
exclude: ['**/*.test.ts', '**/node_modules/**']
},
include: ['**/*.test.ts'],
exclude: ['node_modules', 'dist'],
testTimeout: 10000,
}
})Global Setup
// test/setup.ts
import { beforeEach, afterEach, vi } from 'vitest'
// Global beforeEach/afterEach
beforeEach(() => {
vi.clearAllMocks()
})
// Extend matchers
import { expect } from 'vitest'
expect.extend({
toBeWithinRange(received, floor, ceiling) {
const pass = received >= floor && received <= ceiling
return {
pass,
message: () => `expected ${received} to be within ${floor}-${ceiling}`
}
}
})DOM Testing
// vitest.config.ts
export default defineConfig({
test: {
environment: 'jsdom',
setupFiles: './test/setup.ts'
}
})
// Tests
it('updates DOM', () => {
document.body.innerHTML = '<div id="app"></div>'
const app = document.querySelector('#app')
expect(app).toBeTruthy()
expect(app?.textContent).toBe('')
})Concurrent Tests
// Run tests in parallel
describe.concurrent('suite', () => {
it('test 1', async () => { /* ... */ })
it('test 2', async () => { /* ... */ })
})
// Individual concurrent tests
it.concurrent('test 1', async () => { /* ... */ })
it.concurrent('test 2', async () => { /* ... */ })
// Use local expect for concurrent tests
it.concurrent('test', async ({ expect }) => {
expect(value).toBe(1)
})Test Isolation
export default defineConfig({
test: {
isolate: false, // Share environment between tests (faster)
pool: 'threads', // 'threads' | 'forks' | 'vmThreads'
poolOptions: {
threads: {
singleThread: true // Run tests in single thread
}
}
}
})Type Testing
import { expectTypeOf, assertType } from 'vitest'
// Compile-time type assertions
expectTypeOf({ a: 1 }).toEqualTypeOf<{ a: number }>()
expectTypeOf('string').toBeString()
expectTypeOf(promise).resolves.toBeNumber()
assertType<string>('hello') // Type guardEnvironment Variables
// vitest.config.ts
export default defineConfig({
test: {
env: {
TEST_VAR: 'test-value'
}
}
})
// Or use .env.test file
// Tests can access via process.env.TEST_VARCoverage Configuration
export default defineConfig({
test: {
coverage: {
provider: 'v8',
reporter: ['text', 'json', 'html', 'lcov'],
reportsDirectory: './coverage',
include: ['src/**/*.ts'],
exclude: [
'node_modules',
'test',
'**/*.d.ts',
'**/*.test.ts',
'**/types.ts'
],
thresholds: {
lines: 80,
functions: 80,
branches: 80,
statements: 80
}
}
}
})Mocking Patterns
Module Mocking
// Mock entire module (hoisted automatically)
vi.mock('./module', () => ({
namedExport: vi.fn(() => 'mocked'),
default: vi.fn()
}))
// Partial mock with importActual
vi.mock('./utils', async () => {
const actual = await vi.importActual('./utils')
return {
...actual,
specificFunction: vi.fn()
}
})
// Access mocked module
import { specificFunction } from './utils'
vi.mocked(specificFunction).mockReturnValue('value')
// Mock with spy (keeps implementation)
vi.mock('./calculator', { spy: true })Function Mocking
// Create mock function
const mockFn = vi.fn()
const mockFnWithImpl = vi.fn((x) => x * 2)
// Mock return values
mockFn.mockReturnValue(42)
mockFn.mockReturnValueOnce(1).mockReturnValueOnce(2)
// Mock async returns
mockFn.mockResolvedValue({ data: 'value' })
mockFn.mockRejectedValue(new Error('failed'))
// Mock implementation
mockFn.mockImplementation((arg) => arg + 1)
mockFn.mockImplementationOnce(() => 'once')Mock Assertions
expect(mockFn).toHaveBeenCalled()
expect(mockFn).toHaveBeenCalledTimes(2)
expect(mockFn).toHaveBeenCalledWith('arg1', 'arg2')
expect(mockFn).toHaveBeenLastCalledWith('arg')
expect(mockFn).toHaveReturnedWith(42)
// Access mock state
mockFn.mock.calls // [['arg1'], ['arg2']]
mockFn.mock.results // [{ type: 'return', value: 42 }]
mockFn.mock.lastCall // ['arg2']Spying
// Spy on object methods
const obj = { method: () => 'real' }
const spy = vi.spyOn(obj, 'method')
// Spy with custom implementation
vi.spyOn(obj, 'method').mockImplementation(() => 'mocked')
// Spy on getters/setters
vi.spyOn(obj, 'property', 'get').mockReturnValue('value')
vi.spyOn(obj, 'property', 'set')
// Restore original
spy.mockRestore()Mock Cleanup
import { vi, beforeEach, afterEach } from 'vitest'
beforeEach(() => {
vi.clearAllMocks() // Clear mock history
vi.resetAllMocks() // Clear history + reset implementations
vi.restoreAllMocks() // Restore original implementations (spies)
})
// Or configure in vitest.config.ts
export default defineConfig({
test: {
clearMocks: true, // Auto-clear before each test
mockReset: true, // Auto-reset before each test
restoreMocks: true, // Auto-restore before each test
}
})Mock Methods Quick Reference
| Method | Purpose |
|---|---|
vi.fn() | Create mock function |
vi.spyOn() | Spy on method |
vi.mock() | Mock module |
vi.importActual() | Import real module |
vi.mocked() | Type helper for mocks |
vi.clearAllMocks() | Clear call history |
vi.resetAllMocks() | Reset implementations |
vi.restoreAllMocks() | Restore originals |
Common Patterns
Fake Timers
import { vi, beforeEach, afterEach } from 'vitest'
beforeEach(() => {
vi.useFakeTimers()
})
afterEach(() => {
vi.useRealTimers()
})
it('executes after timeout', () => {
const callback = vi.fn()
setTimeout(callback, 1000)
vi.advanceTimersByTime(1000)
expect(callback).toHaveBeenCalled()
})
// Timer methods
vi.runAllTimers()
vi.runOnlyPendingTimers()
vi.advanceTimersByTime(1000)
vi.advanceTimersToNextTimer()
vi.setSystemTime(new Date('2024-01-01'))Waiting Utilities
// Wait for condition
await vi.waitFor(() => {
expect(element).toBeTruthy()
}, { timeout: 1000, interval: 50 })
// Wait until truthy
const element = await vi.waitUntil(
() => document.querySelector('.loaded'),
{ timeout: 1000 }
)Snapshots
// Basic snapshot
it('matches snapshot', () => {
const data = { foo: 'bar' }
expect(data).toMatchSnapshot()
})
// Inline snapshot (updates test file)
it('matches inline snapshot', () => {
expect(render()).toMatchInlineSnapshot(`
<div>
<h1>Title</h1>
</div>
`)
})
// File snapshot
it('matches file snapshot', async () => {
const html = renderHTML()
await expect(html).toMatchFileSnapshot('./expected.html')
})
// Property matchers for dynamic values
expect(data).toMatchSnapshot({
id: expect.any(Number),
timestamp: expect.any(Date),
uuid: expect.stringMatching(/^[a-f0-9-]+$/)
})
// Update snapshots: vitest -uTesting Errors
// Sync errors
expect(() => throwError()).toThrow()
expect(() => throwError()).toThrow('specific message')
expect(() => throwError()).toThrow(/pattern/)
expect(() => throwError()).toThrowError(CustomError)
// Async errors
await expect(asyncThrow()).rejects.toThrow()
await expect(asyncThrow()).rejects.toThrow('message')Anti-Patterns to Avoid
// Don't nest describes excessively
describe('A', () => {
describe('B', () => {
describe('C', () => {
describe('D', () => { /* too nested */ })
})
})
})
// Don't forget await on async expects
expect(promise).resolves.toBe(value) // Wrong - false positive!
await expect(promise).resolves.toBe(value) // Correct
// Don't test implementation details
expect(component.state.internalFlag).toBe(true) // Brittle
// Don't share state between tests
let sharedVariable
it('test 1', () => { sharedVariable = 'value' })
it('test 2', () => { expect(sharedVariable).toBe('value') }) // Flaky!
// Don't vi.mock inside tests (hoisting issues)
it('test', () => {
vi.mock('./module') // Won't work!
})Best Practices
// Keep describes shallow
describe('UserService', () => {
it('creates user with valid data')
it('throws on invalid email')
})
// Always await async expects
await expect(promise).resolves.toBe(value)
// Test behavior, not implementation
expect(getUserName()).toBe('John Doe')
// Use beforeEach for isolation
beforeEach(() => {
state = createFreshState()
})
// vi.mock at top level (before imports)
vi.mock('./module')
import { fn } from './module'Environment Methods
| Method | Purpose |
|---|---|
vi.useFakeTimers() | Enable fake timers |
vi.useRealTimers() | Restore real timers |
vi.setSystemTime() | Mock system time |
vi.stubGlobal() | Mock global variable |
vi.stubEnv() | Mock environment variable |
Configuration
Contents
- Basic Config
- Global Setup
- DOM Testing
- Concurrent Tests
- Test Isolation
- Type Testing
- Environment Variables
- Coverage Configuration
---
Basic Config
// vitest.config.ts
import { defineConfig } from 'vitest/config'
export default defineConfig({
test: {
globals: true, // Use global test APIs (describe, it, expect)
environment: 'node', // 'node' | 'jsdom' | 'happy-dom'
setupFiles: './test/setup.ts',
coverage: {
provider: 'v8', // 'v8' | 'istanbul'
reporter: ['text', 'json', 'html'],
exclude: ['**/*.test.ts', '**/node_modules/**']
},
include: ['**/*.test.ts'],
exclude: ['node_modules', 'dist'],
testTimeout: 10000,
}
})Global Setup
// test/setup.ts
import { beforeEach, afterEach, vi } from 'vitest'
// Global beforeEach/afterEach
beforeEach(() => {
vi.clearAllMocks()
})
// Extend matchers
import { expect } from 'vitest'
expect.extend({
toBeWithinRange(received, floor, ceiling) {
const pass = received >= floor && received <= ceiling
return {
pass,
message: () => `expected ${received} to be within ${floor}-${ceiling}`
}
}
})DOM Testing
// vitest.config.ts
export default defineConfig({
test: {
environment: 'jsdom',
setupFiles: './test/setup.ts'
}
})
// Tests
it('updates DOM', () => {
document.body.innerHTML = '<div id="app"></div>'
const app = document.querySelector('#app')
expect(app).toBeTruthy()
expect(app?.textContent).toBe('')
})Concurrent Tests
// Run tests in parallel
describe.concurrent('suite', () => {
it('test 1', async () => { /* ... */ })
it('test 2', async () => { /* ... */ })
})
// Individual concurrent tests
it.concurrent('test 1', async () => { /* ... */ })
it.concurrent('test 2', async () => { /* ... */ })
// Use local expect for concurrent tests
it.concurrent('test', async ({ expect }) => {
expect(value).toBe(1)
})Test Isolation
export default defineConfig({
test: {
isolate: false, // Share environment between tests (faster)
pool: 'threads', // 'threads' | 'forks' | 'vmThreads'
poolOptions: {
threads: {
singleThread: true // Run tests in single thread
}
}
}
})Type Testing
import { expectTypeOf, assertType } from 'vitest'
// Compile-time type assertions
expectTypeOf({ a: 1 }).toEqualTypeOf<{ a: number }>()
expectTypeOf('string').toBeString()
expectTypeOf(promise).resolves.toBeNumber()
assertType<string>('hello') // Type guardEnvironment Variables
// vitest.config.ts
export default defineConfig({
test: {
env: {
TEST_VAR: 'test-value'
}
}
})
// Or use .env.test file
// Tests can access via process.env.TEST_VARCoverage Configuration
export default defineConfig({
test: {
coverage: {
provider: 'v8',
reporter: ['text', 'json', 'html', 'lcov'],
reportsDirectory: './coverage',
include: ['src/**/*.ts'],
exclude: [
'node_modules',
'test',
'**/*.d.ts',
'**/*.test.ts',
'**/types.ts'
],
thresholds: {
lines: 80,
functions: 80,
branches: 80,
statements: 80
}
}
}
})Mocking Patterns
Contents
---
Module Mocking
// Mock entire module (hoisted automatically)
vi.mock('./module', () => ({
namedExport: vi.fn(() => 'mocked'),
default: vi.fn()
}))
// Partial mock with importActual (two ways)
// Option 1: Use vi.importActual directly
vi.mock('./utils', async () => {
const actual = await vi.importActual<typeof import('./utils')>('./utils')
return {
...actual,
specificFunction: vi.fn()
}
})
// Option 2: Use the importOriginal helper parameter
vi.mock('./utils', async (importOriginal) => {
const actual = await importOriginal<typeof import('./utils')>()
return {
...actual,
specificFunction: vi.fn()
}
})
// Access mocked module
import { specificFunction } from './utils'
vi.mocked(specificFunction).mockReturnValue('value')
// Mock with spy (keeps implementation)
vi.mock('./calculator', { spy: true })Function Mocking
// Create mock function
const mockFn = vi.fn()
const mockFnWithImpl = vi.fn((x) => x * 2)
// Mock return values
mockFn.mockReturnValue(42)
mockFn.mockReturnValueOnce(1).mockReturnValueOnce(2)
// Mock async returns
mockFn.mockResolvedValue({ data: 'value' })
mockFn.mockRejectedValue(new Error('failed'))
// Mock implementation
mockFn.mockImplementation((arg) => arg + 1)
mockFn.mockImplementationOnce(() => 'once')Mock Assertions
expect(mockFn).toHaveBeenCalled()
expect(mockFn).toHaveBeenCalledTimes(2)
expect(mockFn).toHaveBeenCalledWith('arg1', 'arg2')
expect(mockFn).toHaveBeenLastCalledWith('arg')
expect(mockFn).toHaveReturnedWith(42)
// Access mock state
mockFn.mock.calls // [['arg1'], ['arg2']]
mockFn.mock.results // [{ type: 'return', value: 42 }]
mockFn.mock.lastCall // ['arg2']Spying
// Spy on object methods
const obj = { method: () => 'real' }
const spy = vi.spyOn(obj, 'method')
// Spy with custom implementation
vi.spyOn(obj, 'method').mockImplementation(() => 'mocked')
// Spy on getters/setters
vi.spyOn(obj, 'property', 'get').mockReturnValue('value')
vi.spyOn(obj, 'property', 'set')
// Restore original
spy.mockRestore()Mock Cleanup
import { vi, beforeEach, afterEach } from 'vitest'
beforeEach(() => {
vi.clearAllMocks() // Clear mock history
vi.resetAllMocks() // Clear history + reset implementations
vi.restoreAllMocks() // Restore original implementations (spies)
})
// Or configure in vitest.config.ts
export default defineConfig({
test: {
clearMocks: true, // Auto-clear before each test
mockReset: true, // Auto-reset before each test
restoreMocks: true, // Auto-restore before each test
}
})Mock Methods Quick Reference
| Method | Purpose |
|---|---|
vi.fn() | Create mock function |
vi.spyOn() | Spy on method |
vi.mock() | Mock module |
vi.importActual() | Import real module |
vi.mocked() | Type helper for mocks |
vi.clearAllMocks() | Clear call history |
vi.resetAllMocks() | Reset implementations |
vi.restoreAllMocks() | Restore originals |
Common Patterns
Contents
- Fake Timers
- Waiting Utilities
- Snapshots
- Testing Errors
- Anti-Patterns to Avoid
- Best Practices
- Environment Methods
---
Fake Timers
import { vi, beforeEach, afterEach } from 'vitest'
beforeEach(() => {
vi.useFakeTimers()
})
afterEach(() => {
vi.useRealTimers()
})
it('executes after timeout', () => {
const callback = vi.fn()
setTimeout(callback, 1000)
vi.advanceTimersByTime(1000)
expect(callback).toHaveBeenCalled()
})
// Timer methods
vi.runAllTimers()
vi.runOnlyPendingTimers()
vi.advanceTimersByTime(1000)
vi.advanceTimersToNextTimer()
vi.setSystemTime(new Date('2024-01-01'))Waiting Utilities
// Wait for condition
await vi.waitFor(() => {
expect(element).toBeTruthy()
}, { timeout: 1000, interval: 50 })
// Wait until truthy
const element = await vi.waitUntil(
() => document.querySelector('.loaded'),
{ timeout: 1000 }
)Snapshots
// Basic snapshot
it('matches snapshot', () => {
const data = { foo: 'bar' }
expect(data).toMatchSnapshot()
})
// Inline snapshot (updates test file)
it('matches inline snapshot', () => {
expect(render()).toMatchInlineSnapshot(`
<div>
<h1>Title</h1>
</div>
`)
})
// File snapshot
it('matches file snapshot', async () => {
const html = renderHTML()
await expect(html).toMatchFileSnapshot('./expected.html')
})
// Property matchers for dynamic values
expect(data).toMatchSnapshot({
id: expect.any(Number),
timestamp: expect.any(Date),
uuid: expect.stringMatching(/^[a-f0-9-]+$/)
})
// Update snapshots: vitest -uTesting Errors
// Sync errors
expect(() => throwError()).toThrow()
expect(() => throwError()).toThrow('specific message')
expect(() => throwError()).toThrow(/pattern/)
expect(() => throwError()).toThrowError(CustomError)
// Async errors
await expect(asyncThrow()).rejects.toThrow()
await expect(asyncThrow()).rejects.toThrow('message')Anti-Patterns to Avoid
// Don't nest describes excessively
describe('A', () => {
describe('B', () => {
describe('C', () => {
describe('D', () => { /* too nested */ })
})
})
})
// Don't forget await on async expects
expect(promise).resolves.toBe(value) // Wrong - false positive!
await expect(promise).resolves.toBe(value) // Correct
// Don't test implementation details
expect(component.state.internalFlag).toBe(true) // Brittle
// Don't share state between tests
let sharedVariable
it('test 1', () => { sharedVariable = 'value' })
it('test 2', () => { expect(sharedVariable).toBe('value') }) // Flaky!
// Don't vi.mock inside tests (hoisting issues)
it('test', () => {
vi.mock('./module') // Won't work!
})Best Practices
// Keep describes shallow
describe('UserService', () => {
it('creates user with valid data')
it('throws on invalid email')
})
// Always await async expects
await expect(promise).resolves.toBe(value)
// Test behavior, not implementation
expect(getUserName()).toBe('John Doe')
// Use beforeEach for isolation
beforeEach(() => {
state = createFreshState()
})
// vi.mock at top level (before imports)
vi.mock('./module')
import { fn } from './module'Environment Methods
| Method | Purpose |
|---|---|
vi.useFakeTimers() | Enable fake timers |
vi.useRealTimers() | Restore real timers |
vi.setSystemTime() | Mock system time |
vi.stubGlobal() | Mock global variable |
vi.stubEnv() | Mock environment variable |
Related skills
How it compares
Use vitest-testing for Vitest-specific vi.mock and vitest.config patterns; pick Jest-oriented skills when the project has not migrated to Vitest.
FAQ
What Vitest APIs does vitest-testing document?
vitest-testing documents describe, it, expect, vi.mock, vi.fn, vi.spyOn, beforeEach, afterEach, and vitest.config setup. The beagle skill includes separate references for mocking, configuration, and timer or snapshot patterns.
Does vitest-testing cover async test pitfalls?
vitest-testing emphasizes awaiting resolves and rejects matchers to avoid silent false positives in async Vitest tests. The skill includes verification gates and a dedicated async testing section in the main SKILL.md.