---
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
-->
