From harness-claude
Mocks modules, functions, and timers in Vitest and Jest to isolate units under test. Covers vi.fn(), module mocking, spying, and time manipulation.
How this skill is triggered — by the user, by Claude, or both
Slash command
/harness-claude:test-mock-patternsThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
> Mock modules, functions, and timers in Vitest and Jest to isolate units under test
Mock modules, functions, and timers in Vitest and Jest to isolate units under test
vi.fn():import { vi, describe, it, expect } from 'vitest';
const sendEmail = vi.fn();
it('calls sendEmail with correct args', () => {
sendEmail('[email protected]', 'Welcome');
expect(sendEmail).toHaveBeenCalledWith('[email protected]', 'Welcome');
expect(sendEmail).toHaveBeenCalledTimes(1);
});
const getUser = vi.fn();
getUser.mockReturnValue({ id: '1', name: 'Alice' });
getUser.mockReturnValueOnce({ id: '2', name: 'Bob' }); // First call only
getUser.mockResolvedValue({ id: '1', name: 'Alice' }); // Async
getUser.mockRejectedValue(new Error('Not found')); // Async error
import { vi, describe, it, expect } from 'vitest';
vi.mock('./email-service', () => ({
sendEmail: vi.fn().mockResolvedValue(true),
}));
import { sendEmail } from './email-service';
import { createUser } from './user-service';
it('sends welcome email on user creation', async () => {
await createUser({ name: 'Alice', email: '[email protected]' });
expect(sendEmail).toHaveBeenCalledWith('[email protected]', expect.stringContaining('Welcome'));
});
const spy = vi.spyOn(console, 'log');
doSomething();
expect(spy).toHaveBeenCalledWith('Processing...');
spy.mockRestore(); // Restore original implementation
it('debounces rapid calls', () => {
vi.useFakeTimers();
const callback = vi.fn();
const debounced = debounce(callback, 300);
debounced();
debounced();
debounced();
expect(callback).not.toHaveBeenCalled();
vi.advanceTimersByTime(300);
expect(callback).toHaveBeenCalledTimes(1);
vi.useRealTimers();
});
it('uses current timestamp', () => {
vi.setSystemTime(new Date('2024-01-15T12:00:00Z'));
const record = createRecord();
expect(record.createdAt).toEqual(new Date('2024-01-15T12:00:00Z'));
vi.useRealTimers();
});
vi.mock('./utils', async () => {
const actual = await vi.importActual('./utils');
return {
...actual,
generateId: vi.fn().mockReturnValue('test-id-123'),
};
});
afterEach(() => {
vi.restoreAllMocks(); // Restores original implementations
// vi.clearAllMocks(); // Clears call history but keeps mock implementation
// vi.resetAllMocks(); // Resets implementation to vi.fn()
});
import type { UserService } from './user-service';
const mockUserService: Pick<UserService, 'findById' | 'create'> = {
findById: vi.fn(),
create: vi.fn(),
};
Mocking replaces real dependencies with controlled substitutes. This isolates the unit under test and lets you control inputs, verify outputs, and simulate error conditions.
Mock vs Spy vs Stub:
vi.fn()) — a fake function that records calls and can return configured valuesvi.spyOn()) — wraps a real function, recording calls while preserving the original behavior (unless overridden)mockReturnValue)Module mocking mechanics: vi.mock() is hoisted to the top of the file by Vitest's transformer. This means it executes before imports, replacing the module before any code uses it. The factory function is lazy — it runs when the module is first imported.
Common matchers for mock assertions:
toHaveBeenCalled() — called at least oncetoHaveBeenCalledTimes(n) — called exactly n timestoHaveBeenCalledWith(arg1, arg2) — called with specific argumentstoHaveBeenLastCalledWith(args) — last call had these argumentsexpect.any(Constructor) — matches any instance of the constructorexpect.stringContaining(str) — matches strings containing the substringTrade-offs:
https://vitest.dev/guide/mocking.html
npx claudepluginhub intense-visions/harness-engineering --plugin harness-claudeGuides Vitest test writing with mocking, MSW v2 HTTP mocking, snapshot testing, and test infrastructure. Use when writing or debugging Vitest tests.
Provides Vitest testing patterns with MSW for API mocking and typed mocks for dependency injection. Includes snapshot testing and spy utilities for TypeScript projects.
Provides Vitest testing patterns: assertions, mocking with vi.fn/vi.mock, async testing, and verification gates for writing and running tests.