Noname
Noname

Reputation: 6073

How to mock class instance exported from file with another class instance

I have this file

// src/history
import { createBrowserHistory } from 'history'
const history = createBrowserHistory();
export default history;

history is an instance of BrowserHistory class. It is used inside of actual code:

// src/SampleCode.js
import history from '../../history';
export default function SampleCode = () => {
  const onClick = () => history.push(`/login`);
  return (<Button onCLick={onClick}>Click</Button>)
}

I want to mock this history with the instance of another class MemoryHistory. Something like this:

// src/sample.test.js
it('should redirect to /login', () => {
  const mockHistory = createMemoryHistory();
  const historyPush = jest.spyOn(mockHistory, 'push').mockResolvedValue({});
  jest.mock('./history', () => mockHistory);
  // Click button here
  await waitFor(() => expect(historyPush).toBeCalledWith('/login'));
}

But this approach is not working: historyPush wasn't called at all

Upvotes: 1

Views: 335

Answers (1)

Lin Du
Lin Du

Reputation: 102527

Use jest.doMock(moduleName, factory, options) to make sure mock the ./history module before importing the component.

E.g.

sample.jsx:

import React from 'react';
import history from './history';

export default function SampleCode() {
  const onClick = () => history.push(`/login`);
  return <button onClick={onClick}>Click</button>;
}

history.js:

import { createBrowserHistory } from 'history';
const history = createBrowserHistory();
export default history;

sample.test.jsx:

import { createMemoryHistory } from 'history';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';

describe('68311534', () => {
  beforeEach(() => {
    jest.resetModules();
  });
  it('should pass', () => {
    const memoryHistory = createMemoryHistory();
    const pushSpy = jest.spyOn(memoryHistory, 'push');
    jest.doMock('./history', () => memoryHistory);
    const { default: Sample } = require('./sample');
    render(<Sample />);
    const button = screen.getByText('Click');
    userEvent.click(button);
    expect(pushSpy).toBeCalledWith('/login');
  });
});

test result:

 PASS  examples/68311534/sample.test.jsx (15.495 s)
  68311534
    ✓ should pass (11006 ms)

------------|---------|----------|---------|---------|-------------------
File        | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
------------|---------|----------|---------|---------|-------------------
All files   |     100 |      100 |     100 |     100 |                   
 sample.jsx |     100 |      100 |     100 |     100 |                   
------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        17.53 s

Upvotes: 1

Related Questions