Mocking Modules in Jest: Three Powerful Techniques
Tags: jest, testing, javascript
Published: 2024-04-02 10:58:13

Jest offers three effective methods to mock modules in your tests, enabling you to isolate and control external dependencies for focused testing. Here's a detailed breakdown of each approach:

1. Direct Mocking in the Test File (Using `jest.mock`):

- Ideal for mocking specific modules within the context of a single test file.

- Syntax:

```
jest.mock('module-to-mock', () => ({
  // Mock implementation for the module
}));
```

Example:

```
import { useSite } from 'src/context/SiteContext'; // Import the mocked module
jest.mock('src/context/SiteContext', () => ({
  useSite: jest.fn(),
}));
const useSiteMockImpelmetation = (market: string) => {
  (useSite as any).mockImplementation(() => {
    return {
      config: {
        market,
      },
    };
  });
};
 it('should show 4 list item if is spanish market', () => {
    mockMarket('es');
    renderComponent();
    const items = screen.getAllByRole('listitem');
    expect(items).toHaveLength(4);
  });
```
 

2. Global Mocking in jest.setup.ts:

- Suitable for globally mocking modules across all test files.

- Location: Create a file named jest.setup.ts (or .js) in your project's root directory.

Syntax:

```
jest.mock('module-to-mock', () => ({
  // Mock implementation for the module
}));
Example (in jest.setup.ts):



jest.mock('next-i18next', () => ({
  useTranslation: () => ({
    t: (key: string) => key,
  }),
}));
```
 

3. Manual Mocking in the `__mocks__` Folder: (Manual Mocks · Jest )

- Useful when the mocked module has complex logic or requires custom configuration.

- Steps:

  * Create a directory named __mocks__ within the same directory as the module you want to mock.

  * Inside `__mocks__`, create a file with the same name as the module (including extension). This file will contain your mock implementation.

- Example (assuming `src/context/SiteContext.tsx` is the module to mock):

  * Create __mocks__/src/context/SiteContext.tsx.

  * Implement your mock logic in this file.



```
jest.mock('src/context/SiteContext', () => ({
  useSite: jest.fn(() => ({ 
    config: {
      market:'us'
      }
  })),
}));
```

Then in the test file, we can use it:

```
jest.mock('src/context/SiteConfigContext');
```

 - The useSite mock will automatically have the mock value that defined in the `__mocks__/src/context/SiteContext.tsx` file

 

---


### Props and cons:

| Method        | Pros          | Cons  |
| ------------- |:-------------:| -----:|
| Direct Mocking (`jest.mock` in Test File)| Targeted: Mocks apply only to a specific test file. - Simple: Easy to set up for basic mocking needs. - Clear: Mock behavior stays within the test case. | Limited Scope: Mocks are not shared across other tests. - Repetition: May lead to code duplication if mocking the same module in multiple tests.
| Global Mocking (jest.setup.ts) |Consistency: Mocks are applied consistently across all tests. - Convenience: No need to repeat mock definitions for each test.|Global Impact: Accidental side effects in mocks can affect all tests. - Less Control: Less granular control over mock behavior compared to direct mocking.
| Manual Mocking (__mocks__ Folder)      | Flexibility: Suitable for complex mocking logic or custom configurations. - Organization: Keeps mock code separate for better maintainability.      |  Setup: Requires creating a dedicated folder structure. - Potential Issues: May be harder to debug if mock logic becomes intricate.|

---

### Choosing the Right Method:
- For basic mocks within a single test: Direct mocking with jest.mock is straightforward and keeps code focused.

- For consistent global mocking: Use jest.setup.ts when you need the same mock behavior across all tests.

- For complex or reusable mock logic: Manual mocking with the __mocks__ folder offers flexibility and organization.

- We always can use jest.mock('path') to unmock the mock file