> For AI agents: the complete documentation index is available at /llms.txt, the full documentation bundle is available at /llms-full.txt.

# Mock functions

Rstest provides some utility functions to help you mock functions powered by [tinyspy](https://github.com/tinylibs/tinyspy).

## rs.fn

- **Alias:** `rstest.fn`
- **Type:**

```ts
type FunctionLike = (...args: any) => any;

export interface Mock<
  T extends FunctionLike = FunctionLike,
> extends MockInstance<T> {
  new (...args: Parameters<T>): ReturnType<T>;
  (...args: Parameters<T>): ReturnType<T>;
}

export type MockFn = <T extends FunctionLike = FunctionLike>(fn?: T) => Mock<T>;
```

Creates a spy on a function.

See the [`Mock`](/api/javascript-api/types.md#mock) type for annotating callable mock functions.

```ts
const sayHi = rs.fn((name: string) => `hi ${name}`);

const res = sayHi('bob');

expect(res).toBe('hi bob');

expect(sayHi).toHaveBeenCalledTimes(1);
```

## rs.spyOn

- **Alias:** `rstest.spyOn`
- **Type:**

```ts
export type SpyFn = <T extends Record<string, any>, K extends keyof T>(
  obj: T,
  methodName: K,
  accessType?: 'get' | 'set',
) => MockInstance<T[K]>;
```

Creates a spy on a method of an object.

See the [`MockInstance`](/api/javascript-api/types.md#mockinstance) type for the control API returned by a spy.

```ts
const sayHi = () => 'hi';
const hi = {
  sayHi,
};

const spy = rs.spyOn(hi, 'sayHi');

expect(hi.sayHi()).toBe('hi');

expect(spy).toHaveBeenCalled();
```

If you call `rs.spyOn` multiple times for the same method, Rstest reuses the existing spy instead of redefining it.

```ts
const hi = {
  sayHi: () => 'hi',
};
rs.spyOn(hi, 'sayHi').mockImplementation(() => 'hello');

expect(hi.sayHi()).toBe('hello');
// should get the same spy instance
expect(rs.spyOn(hi, 'sayHi')).toBeCalled();
```

:::note Spying on re-exported or third-party exports

`rs.spyOn` works on an export defined in the module you import from, but not on one **re-exported** from another module (`export * from '...'`) or provided by a third-party dependency — there the spy may not take effect.

For those, mock the module with [`{ spy: true }`](/api/runtime-api/rstest/mock-modules.md#with-spy-true-option) instead. It spies every export while keeping its real implementation:

```ts
rs.mock('pkg', { spy: true });
```

:::

## rs.isMockFunction

- **Alias:** `rstest.isMockFunction`
- **Type:** `(fn: any) => fn is MockInstance`

Determines if the given function is a mocked function.

## rs.mockObject

- **Alias:** `rstest.mockObject`
- **Type:**

```ts
type MockObject = <T>(
  object: T,
  options?: { spy?: boolean },
) => MaybeMockedDeep<T>;
```

Creates a deep mock of an object. All methods are replaced with mock functions, while primitive values and plain objects are preserved.

### Basic usage

```ts
const original = {
  method() {
    return 42;
  },
  nested: {
    getValue() {
      return 'real';
    },
  },
  prop: 'foo',
};

const mocked = rs.mockObject(original);

// Methods return undefined by default
expect(mocked.method()).toBe(undefined);
expect(mocked.nested.getValue()).toBe(undefined);

// Primitive values are preserved
expect(mocked.prop).toBe('foo');

// Methods are mock functions
expect(rs.isMockFunction(mocked.method)).toBe(true);
```

### Mocking return values

You can configure mocked methods to return specific values:

```ts
const mocked = rs.mockObject({
  fetchData: () => 'real data',
});

mocked.fetchData.mockReturnValue('mocked data');

expect(mocked.fetchData()).toBe('mocked data');
```

### Spy mode

When `{ spy: true }` is passed as the second argument, the original implementations are preserved while still tracking calls:

```ts
const original = {
  add: (a: number, b: number) => a + b,
};

const spied = rs.mockObject(original, { spy: true });

// Original implementation is preserved
expect(spied.add(1, 2)).toBe(3);

// Calls are tracked
expect(spied.add).toHaveBeenCalledWith(1, 2);
expect(spied.add.mock.results[0]).toEqual({ type: 'return', value: 3 });
```

### Arrays

By default, arrays are replaced with empty arrays. With `{ spy: true }`, arrays keep their original values:

```ts
const mocked = rs.mockObject({ array: [1, 2, 3] });
expect(mocked.array).toEqual([]);

const spied = rs.mockObject({ array: [1, 2, 3] }, { spy: true });
expect(spied.array).toEqual([1, 2, 3]);
```

### Mocking classes

You can also mock class constructors. Use `{ spy: true }` to preserve the original class behavior while tracking calls:

```ts
class UserService {
  getUser() {
    return { id: 1, name: 'Alice' };
  }
}

// Use { spy: true } to keep original implementation
const MockedService = rs.mockObject(UserService, { spy: true });
const instance = new MockedService();

// Original method works
expect(instance.getUser()).toEqual({ id: 1, name: 'Alice' });

// Override the implementation
rs.mocked(instance.getUser).mockImplementation(() => ({ id: 2, name: 'Bob' }));
expect(instance.getUser()).toEqual({ id: 2, name: 'Bob' });
```

## rs.mocked

- **Alias:** `rstest.mocked`
- **Type:**

```ts
type MockedFn = <T>(
  item: T,
  deepOrOptions?: boolean | { partial?: boolean; deep?: boolean },
) =>
  | Mocked<T>
  | MaybeMockedDeep<T>
  | MaybePartiallyMocked<T>
  | MaybePartiallyMockedDeep<T>;
```

A type helper for TypeScript that wraps an object with mock types without changing its runtime behavior. This is useful when you have mocked a module and want proper type hints for the mock methods.

The inferred return type follows the options: `{ deep: true }` applies mock types recursively, while `{ partial: true }` uses the partial mock variants.

See the [`Mocked`](/api/javascript-api/types.md#mocked) type for annotating mocked objects and modules.

```ts
import { myModule } from './myModule';

rs.mock('./myModule', { spy: true });

// TypeScript now knows myModule.method is a MockInstance
const mockedModule = rs.mocked(myModule);

mockedModule.method.mockReturnValue('mocked');
```

The function simply returns the same object at runtime - it only affects TypeScript types.

## rs.clearAllMocks

- **Alias:** `rstest.clearAllMocks`
- **Type:** `() => RstestUtilities`

Clears the `mock.calls`, `mock.instances`, `mock.contexts` and `mock.results` properties of all mocks.

## rs.resetAllMocks

- **Alias:** `rstest.resetAllMocks`
- **Type:** `() => RstestUtilities`

Clears all mocks properties and reset each mock's implementation to its original.

## rs.restoreAllMocks

- **Alias:** `rstest.restoreAllMocks`
- **Type:** `() => RstestUtilities`

Reset all mocks and restore original descriptors of spied-on objects.

## More

- [Mock Matchers](/api/runtime-api/test-api/expect.md#mock-matchers)
- [MockInstance API](/api/runtime-api/rstest/mock-instance.md)
