web-dev-qa-db-fra.com

Comment se moquer du crochet UseHistory en plaisantant?

J'utilise le hook UseHistory dans le routeur React v5.1.2 avec un script dactylographié? Lors de l'exécution du test unitaire, j'ai un problème.

TypeError: Impossible de lire la propriété "historique" de non défini.

import { mount } from 'enzyme';
import React from 'react';
import {Action} from 'history';
import * as router from 'react-router';
import { QuestionContainer } from './QuestionsContainer';

describe('My questions container', () => {
    beforeEach(() => {
        const historyHistory= {
            replace: jest.fn(),
            length: 0,
            location: { 
                pathname: '',
                search: '',
                state: '',
                hash: ''
            },
            action: 'REPLACE' as Action,
            Push: jest.fn(),
            go: jest.fn(),
            goBack: jest.fn(),
            goForward: jest.fn(),
            block: jest.fn(),
            listen: jest.fn(),
            createHref: jest.fn()
        };//fake object 
        jest.spyOn(router, 'useHistory').mockImplementation(() =>historyHistory);// try to mock hook
    });

    test('should match with snapshot', () => {
        const tree = mount(<QuestionContainer />);

        expect(tree).toMatchSnapshot();
    });
});

J'ai aussi essayé d'utiliser jest.mock('react-router', () =>({ useHistory: jest.fn() })); mais cela ne fonctionne toujours pas.

16
Ivan Martinyuk

J'avais besoin de la même chose pour superposer un composant fonctionnel React qui utilise useHistory.

Résolu avec la maquette suivante dans mon fichier de test:

jest.mock('react-router-dom', () => ({
  useHistory: () => ({
    Push: jest.fn(),
  }),
}));
18
Proustibat

Celui-ci a fonctionné pour moi:

jest.mock('react-router-dom', () => ({
  ...jest.requireActual('react-router-dom'),
  useHistory: () => ({
    Push: jest.fn()
  })
}));
12
Erhan

Dans le repo de github react-router, j'ai trouvé que le crochet useHistory utilise le contexte singleton, lorsque j'ai commencé à l'utiliser dans le montage MemoryRouter, il a trouvé le contexte et a commencé à fonctionner. Alors corrige ça

import { MemoryRouter } from 'react-router-dom';
const tree =  mount(<MemoryRouter><QuestionContainer {...props} /> </MemoryRouter>);
4
Ivan Martinyuk

Voici un exemple plus détaillé, tiré du code de test fonctionnel (car j'ai eu du mal à implémenter le code ci-dessus):

Component.js

  import { useHistory } from 'react-router-dom';
  ...

  const Component = () => {
      ...
      const history = useHistory();
      ...
      return (
          <>
              <a className="selector" onClick={() => history.Push('/whatever')}>Click me</a>
              ...
          </>
      )
  });

Component.test.js

  import { Router } from 'react-router-dom';
  import { act } from '@testing-library/react-hooks';
  import { mount } from 'enzyme';
  import Component from './Component';
  it('...', () => {
    const historyMock = { Push: jest.fn(), location: {}, listen: jest.fn() };
    ...
    const wrapper = mount(
      <Router history={historyMock}>
        <Component isLoading={false} />
      </Router>,
    ).find('.selector').at(1);

    const { onClick } = wrapper.props();
    act(() => {
      onClick();
    });

    expect(historyMock.Push.mock.calls[0][0]).toEqual('/whatever');
  });
3
Alex W