# Module Mocking and Hoisting — Jest, Vitest & Testing Library

Source: https://www.skillbyai.com/en/javascript-testing/m-modules

> jest.mock and vi.mock, and why they run first.

## Replace an import for the whole test file

`jest.mock('./path')` / `vi.mock('./path')` replace a module everywhere it is imported by the file under test. With no factory, each export becomes an automatic mock; with a factory you return the replacement exports. These calls are **hoisted** to the top of the file, above your imports, so the mock is in place before the module loads. A consequence: a factory cannot use ordinary variables declared in the test file. In Vitest, use `vi.hoisted` to create values the factory may reference; in Jest, variables whose names start with `mock` are allowed in the factory. To keep most of the real module, spread the original (`vi.importActual` / `jest.requireActual`) and override one export. Mock **your own boundary modules** (an API client, analytics) rather than third-party internals.

## Mocking an analytics module

Vitest with vi.hoisted; the Jest equivalent is shown below.

```typescript
import { beforeEach, expect, it, vi } from 'vitest';
import { checkout } from './checkout';

const { track } = vi.hoisted(() => ({ track: vi.fn() }));

vi.mock('./analytics', () => ({ track }));          // hoisted above the imports

vi.mock('./config', async (importOriginal) => {
  const actual = await importOriginal<typeof import('./config')>();
  return { ...actual, featureFlags: { newCheckout: true } };   // override one export
});

beforeEach(() => track.mockClear());

it('tracks a completed checkout', async () => {
  await checkout({ cartId: 'c1' });
  expect(track).toHaveBeenCalledWith('checkout_completed', { cartId: 'c1' });
});

// Jest equivalent:
// const mockTrack = jest.fn();
// jest.mock('./analytics', () => ({ track: (...args: unknown[]) => mockTrack(...args) }));
```

## A stunt double

A module mock is a stunt double: it stands in for the real actor in risky scenes. Useful, but the audience must not mistake the double's performance for the star's; you still need some tests with the real module.

**Quiz:** Why can a vi.mock factory not use a normal const declared above it?

- [ ] Constants are frozen by Vitest
- [ ] Factories may only return strings
- [ ] Mocks run in a separate browser
- [x] vi.mock is hoisted above the declarations, so the variable is not initialised yet

*Answer:* vi.mock is hoisted above the declarations, so the variable is not initialised yet. Use vi.hoisted (or the mock prefix in Jest).
