Как смоделировать history.listen? - PullRequest
1 голос
/ 04 апреля 2019

history.js

import { createBrowserHistory } from 'history';

export default createBrowserHistory();

В моем .js так я использую history.listen

import history from './history';

Следующее в конструкторе:

history.listen(location => {
  if (location.pathname === '/second') {
    this.setState({
      pathStep: 1,
    });
  } else if (location.pathname === '/') {
    this.setState({
      pathStep: 0,
    });
  }
});

Сейчас я пытаюсь получить действительный тест для этого:

    I tried to do the following:
    jest.mock('./history', () => ({
      listen: () => () => {
        '/second';
      },
    }));

    it('changes activeStep when called', () => {
      expect(component.state().pathStep).toBe(1);
    });

Но даже добавив console.log после history.listen(location => {, я не достиг своего history.listen. Поэтому мне любопытно, что я делаю неправильно

Я также пытался добавить spyOn к history.listen, но хотел услышать, что является лучшим методом для этого конкретного теста

Ответы [ 2 ]

1 голос
/ 06 апреля 2019

Если вы имитируете history.listen, вы можете получить обратный вызов, который ваш компонент передает ему .

Затем вы можете вызвать обратный вызов напрямую , чтобы проверитьчто ваш компонент отвечает правильно.

Вот полный рабочий пример:

history.js

import { createBrowserHistory } from 'history';

export default createBrowserHistory();

code.js

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

export class SimpleComponent extends React.Component {
  constructor(...args) {
    super(...args);
    this.state = { pathStep: 0 };
  }
  componentDidMount() {
    this.unlisten = history.listen(location => {
      if (location.pathname === '/second') {
        this.setState({
          pathStep: 1,
        });
      } else if (location.pathname === '/') {
        this.setState({
          pathStep: 0,
        });
      }
    });
  }
  componentWillUnmount() {
    this.unlisten();
  }
  render() { return null; }
}

код.test.js

import * as React from 'react';
import history from './history';
import { mount } from 'enzyme';

import { SimpleComponent } from './code';

test('SimpleComponent', () => {
  const listenMock = jest.spyOn(history, 'listen');
  const unlistenMock = jest.fn();
  listenMock.mockReturnValue(unlistenMock);

  const component = mount(<SimpleComponent />);
  expect(component.state().pathStep).toBe(0);  // Success!

  const callback = listenMock.mock.calls[0][0];  // <= get the callback passed to history.listen

  callback({ pathname: '/second' });
  expect(component.state().pathStep).toBe(1);  // Success!

  callback({ pathname: '/' });
  expect(component.state().pathStep).toBe(0);  // Success!

  component.unmount();
  expect(unlistenMock).toHaveBeenCalled();  // Success!
})
0 голосов
/ 05 апреля 2019

То, что я закончил, было чем-то вроде этого.На самом первом монтировании он возвращает /, на втором монтировании возвращает /second и оттуда возвращается в состояние по умолчанию 0 (/)

jest.mock('./history', () => ({
  listen: jest
    .fn()
   .mockImplementationOnce(cb => {
      cb({ pathname: '/' });
    })
    .mockImplementationOnce(cb => {
      cb({ pathname: '/second' });
    }),
}));

И сам тест(чтобы протестировать /second и / в 1 одном тесте)

it('changes pathStep when called', () => {
    expect(component.state().pathStep).toBe(0);

    component = mount(<MyComponent />);

    expect(component.state().pathStep).toBe(1);

    component = mount(<MyComponent />);

    expect(component.state().pathStep).toBe(0);
  });

Но для выполнения теста, который я изначально задал, будет достаточно:

jest.mock('./history', () => ({
  listen: cb => {
    cb({ pathname: '/second' });
  },
}));

Мне просто нужно было передать обратный вызов при издевательстве, настолько близком к тому, что у меня было раньше, но с некоторым сопряжением удалось заставить его работать:)

Надеюсь, что это имеет смысл и поможет кому-то в будущем

...