install
source · Clone the upstream repo
git clone https://github.com/Intense-Visions/harness-engineering
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/Intense-Visions/harness-engineering "$T" && mkdir -p ~/.claude/skills && cp -r "$T/agents/skills/claude-code/test-mock-patterns" ~/.claude/skills/intense-visions-harness-engineering-test-mock-patterns && rm -rf "$T"
manifest:
agents/skills/claude-code/test-mock-patterns/SKILL.mdsource content
Test Mock Patterns
Mock modules, functions, and timers in Vitest and Jest to isolate units under test
When to Use
- Isolating code from external dependencies (databases, APIs, file system)
- Controlling function return values for specific test scenarios
- Verifying that functions are called with correct arguments
- Testing time-dependent code without real delays
Instructions
- Mock a function with
:vi.fn()
import { vi, describe, it, expect } from 'vitest'; const sendEmail = vi.fn(); it('calls sendEmail with correct args', () => { sendEmail('alice@test.com', 'Welcome'); expect(sendEmail).toHaveBeenCalledWith('alice@test.com', 'Welcome'); expect(sendEmail).toHaveBeenCalledTimes(1); });
- Mock return values:
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
- Mock a module:
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: 'alice@test.com' }); expect(sendEmail).toHaveBeenCalledWith('alice@test.com', expect.stringContaining('Welcome')); });
- Spy on existing methods without replacing them:
const spy = vi.spyOn(console, 'log'); doSomething(); expect(spy).toHaveBeenCalledWith('Processing...'); spy.mockRestore(); // Restore original implementation
- Mock timers:
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(); });
- Mock dates:
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(); });
- Partial module mocking — mock some exports, keep others real:
vi.mock('./utils', async () => { const actual = await vi.importActual('./utils'); return { ...actual, generateId: vi.fn().mockReturnValue('test-id-123'), }; });
- Reset mocks between tests:
afterEach(() => { vi.restoreAllMocks(); // Restores original implementations // vi.clearAllMocks(); // Clears call history but keeps mock implementation // vi.resetAllMocks(); // Resets implementation to vi.fn() });
- Type-safe mocks:
import type { UserService } from './user-service'; const mockUserService: Pick<UserService, 'findById' | 'create'> = { findById: vi.fn(), create: vi.fn(), };
Details
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:
- Mock (
) — a fake function that records calls and can return configured valuesvi.fn() - Spy (
) — wraps a real function, recording calls while preserving the original behavior (unless overridden)vi.spyOn() - Stub — a mock configured to return a specific value (mock +
)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:
— called at least oncetoHaveBeenCalled()
— called exactly n timestoHaveBeenCalledTimes(n)
— called with specific argumentstoHaveBeenCalledWith(arg1, arg2)
— last call had these argumentstoHaveBeenLastCalledWith(args)
— matches any instance of the constructorexpect.any(Constructor)
— matches strings containing the substringexpect.stringContaining(str)
Trade-offs:
- Mocking isolates units — but mocked tests can pass even when the real integration is broken
- Module mocking is powerful — but tightly couples tests to import paths
- Timer mocking enables deterministic time tests — but can leak between tests if not cleaned up
- Over-mocking leads to tests that verify mock wiring rather than actual behavior
Source
https://vitest.dev/guide/mocking.html
Process
- Read the instructions and examples in this document.
- Apply the patterns to your implementation, adapting to your specific context.
- Verify your implementation against the details and edge cases listed above.
Harness Integration
- Type: knowledge — this skill is a reference document, not a procedural workflow.
- No tools or state — consumed as context by other skills and agents.
Success Criteria
- The patterns described in this document are applied correctly in the implementation.
- Edge cases and anti-patterns listed in this document are avoided.