mockServerFn
Mocks a server function for testing client components in isolation. Creates a replacement function that uses the provided implementation and records all calls for assertions.
Import
import { mockServerFn } from 'catmint/testing'
Signature
function mockServerFn<TInput, TOutput>(
original: (input: TInput) => Promise<TOutput>,
implementation: (input: TInput) => Promise<TOutput>,
): MockedServerFn<TInput, TOutput>
interface MockedServerFn<TInput, TOutput> {
(input: TInput): Promise<TOutput>
calls: Array<{ input: TInput; result: TOutput }>
reset: () => void
}
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
original | (input: TInput) => Promise<TOutput> | Yes | The original server function to mock. Used for type inference; not called at runtime. |
implementation | (input: TInput) => Promise<TOutput> | Yes | The mock implementation that will be called instead of the original. |
Return Value
Returns a MockedServerFn that is callable like the original function and has additional properties:
| Property | Type | Description |
|---|---|---|
calls | Array<{ input: TInput; result: TOutput }> | Array of all recorded calls, each containing the input that was passed and the result that was returned. |
reset | () => void | Clears the call history. |
Examples
Basic mock
import { mockServerFn } from 'catmint/testing'
import { getUser } from './queries'
const mockGetUser = mockServerFn(getUser, async (input) => {
return { id: input.id, name: 'Test User', email: 'test@example.com' }
})
test('fetches a user', async () => {
const user = await mockGetUser({ id: '123' })
expect(user.name).toBe('Test User')
expect(mockGetUser.calls).toHaveLength(1)
expect(mockGetUser.calls[0].input).toEqual({ id: '123' })
})
Asserting multiple calls
const mockSave = mockServerFn(saveItem, async (input) => {
return { ...input, savedAt: new Date().toISOString() }
})
await mockSave({ title: 'First' })
await mockSave({ title: 'Second' })
expect(mockSave.calls).toHaveLength(2)
expect(mockSave.calls[0].input.title).toBe('First')
expect(mockSave.calls[1].input.title).toBe('Second')
Resetting between tests
const mockDelete = mockServerFn(deleteItem, async (input) => {
return { deleted: true }
})
afterEach(() => {
mockDelete.reset()
})
test('first test', async () => {
await mockDelete({ id: '1' })
expect(mockDelete.calls).toHaveLength(1)
})
test('second test', async () => {
// calls are reset — starts fresh
expect(mockDelete.calls).toHaveLength(0)
})
