Pulled ALL skills from 15 source repositories: - anthropics/skills: 16 (docs, design, MCP, testing) - obra/superpowers: 14 (TDD, debugging, agents, planning) - coreyhaines31/marketingskills: 25 (marketing, CRO, SEO, growth) - better-auth/skills: 5 (auth patterns) - vercel-labs/agent-skills: 5 (React, design, Vercel) - antfu/skills: 16 (Vue, Vite, Vitest, pnpm, Turborepo) - Plus 13 individual skills from various repos Mosaic Stack is not limited to coding — the Orchestrator and subagents serve coding, business, design, marketing, writing, logistics, analysis, and more. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
250 lines
4.5 KiB
Markdown
250 lines
4.5 KiB
Markdown
---
|
|
name: vi-utilities
|
|
description: vi helper for mocking, timers, utilities
|
|
---
|
|
|
|
# Vi Utilities
|
|
|
|
The `vi` helper provides mocking and utility functions.
|
|
|
|
```ts
|
|
import { vi } from 'vitest'
|
|
```
|
|
|
|
## Mock Functions
|
|
|
|
```ts
|
|
// Create mock
|
|
const fn = vi.fn()
|
|
const fnWithImpl = vi.fn((x) => x * 2)
|
|
|
|
// Check if mock
|
|
vi.isMockFunction(fn) // true
|
|
|
|
// Mock methods
|
|
fn.mockReturnValue(42)
|
|
fn.mockReturnValueOnce(1)
|
|
fn.mockResolvedValue(data)
|
|
fn.mockRejectedValue(error)
|
|
fn.mockImplementation(() => 'result')
|
|
fn.mockImplementationOnce(() => 'once')
|
|
|
|
// Clear/reset
|
|
fn.mockClear() // Clear call history
|
|
fn.mockReset() // Clear history + implementation
|
|
fn.mockRestore() // Restore original (for spies)
|
|
```
|
|
|
|
## Spying
|
|
|
|
```ts
|
|
const obj = { method: () => 'original' }
|
|
|
|
const spy = vi.spyOn(obj, 'method')
|
|
obj.method()
|
|
|
|
expect(spy).toHaveBeenCalled()
|
|
|
|
// Mock implementation
|
|
spy.mockReturnValue('mocked')
|
|
|
|
// Spy on getter/setter
|
|
vi.spyOn(obj, 'prop', 'get').mockReturnValue('value')
|
|
```
|
|
|
|
## Module Mocking
|
|
|
|
```ts
|
|
// Hoisted to top of file
|
|
vi.mock('./module', () => ({
|
|
fn: vi.fn(),
|
|
}))
|
|
|
|
// Partial mock
|
|
vi.mock('./module', async (importOriginal) => ({
|
|
...(await importOriginal()),
|
|
specificFn: vi.fn(),
|
|
}))
|
|
|
|
// Spy mode - keep implementation
|
|
vi.mock('./module', { spy: true })
|
|
|
|
// Import actual module inside mock
|
|
const actual = await vi.importActual('./module')
|
|
|
|
// Import as mock
|
|
const mocked = await vi.importMock('./module')
|
|
```
|
|
|
|
## Dynamic Mocking
|
|
|
|
```ts
|
|
// Not hoisted - use with dynamic imports
|
|
vi.doMock('./config', () => ({ key: 'value' }))
|
|
const config = await import('./config')
|
|
|
|
// Unmock
|
|
vi.doUnmock('./config')
|
|
vi.unmock('./module') // Hoisted
|
|
```
|
|
|
|
## Reset Modules
|
|
|
|
```ts
|
|
// Clear module cache
|
|
vi.resetModules()
|
|
|
|
// Wait for dynamic imports
|
|
await vi.dynamicImportSettled()
|
|
```
|
|
|
|
## Fake Timers
|
|
|
|
```ts
|
|
vi.useFakeTimers()
|
|
|
|
setTimeout(() => console.log('done'), 1000)
|
|
|
|
// Advance time
|
|
vi.advanceTimersByTime(1000)
|
|
vi.advanceTimersByTimeAsync(1000) // For async callbacks
|
|
vi.advanceTimersToNextTimer()
|
|
vi.advanceTimersToNextFrame() // requestAnimationFrame
|
|
|
|
// Run all timers
|
|
vi.runAllTimers()
|
|
vi.runAllTimersAsync()
|
|
vi.runOnlyPendingTimers()
|
|
|
|
// Clear timers
|
|
vi.clearAllTimers()
|
|
|
|
// Check state
|
|
vi.getTimerCount()
|
|
vi.isFakeTimers()
|
|
|
|
// Restore
|
|
vi.useRealTimers()
|
|
```
|
|
|
|
## Mock Date/Time
|
|
|
|
```ts
|
|
vi.setSystemTime(new Date('2024-01-01'))
|
|
expect(new Date().getFullYear()).toBe(2024)
|
|
|
|
vi.getMockedSystemTime() // Get mocked date
|
|
vi.getRealSystemTime() // Get real time (ms)
|
|
```
|
|
|
|
## Global/Env Mocking
|
|
|
|
```ts
|
|
// Stub global
|
|
vi.stubGlobal('fetch', vi.fn())
|
|
vi.unstubAllGlobals()
|
|
|
|
// Stub environment
|
|
vi.stubEnv('API_KEY', 'test')
|
|
vi.stubEnv('NODE_ENV', 'test')
|
|
vi.unstubAllEnvs()
|
|
```
|
|
|
|
## Hoisted Code
|
|
|
|
Run code before imports:
|
|
|
|
```ts
|
|
const mock = vi.hoisted(() => vi.fn())
|
|
|
|
vi.mock('./module', () => ({
|
|
fn: mock, // Can reference hoisted variable
|
|
}))
|
|
```
|
|
|
|
## Waiting Utilities
|
|
|
|
```ts
|
|
// Wait for callback to succeed
|
|
await vi.waitFor(async () => {
|
|
const el = document.querySelector('.loaded')
|
|
expect(el).toBeTruthy()
|
|
}, { timeout: 5000, interval: 100 })
|
|
|
|
// Wait for truthy value
|
|
const element = await vi.waitUntil(
|
|
() => document.querySelector('.loaded'),
|
|
{ timeout: 5000 }
|
|
)
|
|
```
|
|
|
|
## Mock Object
|
|
|
|
Mock all methods of an object:
|
|
|
|
```ts
|
|
const original = {
|
|
method: () => 'real',
|
|
nested: { fn: () => 'nested' },
|
|
}
|
|
|
|
const mocked = vi.mockObject(original)
|
|
mocked.method() // undefined (mocked)
|
|
mocked.method.mockReturnValue('mocked')
|
|
|
|
// Spy mode
|
|
const spied = vi.mockObject(original, { spy: true })
|
|
spied.method() // 'real'
|
|
expect(spied.method).toHaveBeenCalled()
|
|
```
|
|
|
|
## Test Configuration
|
|
|
|
```ts
|
|
vi.setConfig({
|
|
testTimeout: 10_000,
|
|
hookTimeout: 10_000,
|
|
})
|
|
|
|
vi.resetConfig()
|
|
```
|
|
|
|
## Global Mock Management
|
|
|
|
```ts
|
|
vi.clearAllMocks() // Clear all mock call history
|
|
vi.resetAllMocks() // Reset + clear implementation
|
|
vi.restoreAllMocks() // Restore originals (spies)
|
|
```
|
|
|
|
## vi.mocked Type Helper
|
|
|
|
TypeScript helper for mocked values:
|
|
|
|
```ts
|
|
import { myFn } from './module'
|
|
vi.mock('./module')
|
|
|
|
// Type as mock
|
|
vi.mocked(myFn).mockReturnValue('typed')
|
|
|
|
// Deep mocking
|
|
vi.mocked(myModule, { deep: true })
|
|
|
|
// Partial mock typing
|
|
vi.mocked(fn, { partial: true }).mockResolvedValue({ ok: true })
|
|
```
|
|
|
|
## Key Points
|
|
|
|
- `vi.mock` is hoisted - use `vi.doMock` for dynamic mocking
|
|
- `vi.hoisted` lets you reference variables in mock factories
|
|
- Use `vi.spyOn` to spy on existing methods
|
|
- Fake timers require explicit setup and teardown
|
|
- `vi.waitFor` retries until assertion passes
|
|
|
|
<!--
|
|
Source references:
|
|
- https://vitest.dev/api/vi.html
|
|
-->
|