Как протестировать компонент, используя hooks-redux? - программирование
Подтвердить что ты не робот

Как протестировать компонент, используя hooks-redux?

У меня есть простой компонент Todo, который использует перехватчики реакции-редукса, который я тестирую с использованием фермента, но я получаю либо ошибку, либо пустой объект с мелкой визуализацией, как указано ниже.

Как правильно тестировать компоненты с помощью хуков изact-redux?

Todos.js

const Todos = () => {
  const { todos } = useSelector(state => state);

  return (
    <ul>
      {todos.map(todo => (
        <li key={todo.id}>{todo.title}</li>
      ))}
    </ul>
  );
};

Todos.test.js v1

...

it('renders without crashing', () => {
  const wrapper = shallow(<Todos />);
  expect(wrapper).toMatchSnapshot();
});

it('should render a ul', () => {
  const wrapper = shallow(<Todos />);
  expect(wrapper.find('ul').length).toBe(1);
});

Ошибка v1:

...
Invariant Violation: could not find react-redux context value; 
please ensure the component is wrapped in a <Provider>
...

Todos.test.js v2

...
// imported Provider from react-redux 

it('renders without crashing', () => {
  const wrapper = shallow(
    <Provider store={store}>
      <Todos />
    </Provider>,
  );
  expect(wrapper).toMatchSnapshot();
});

it('should render a ul', () => {
  const wrapper = shallow(<Provider store={store}><Todos /></Provider>);
  expect(wrapper.find('ul').length).toBe(1);
});

Тесты v2 также не пройдены, поскольку wrapper является <Provider> и вызов dive() для wrapper вернет ту же ошибку, что и v1.

Заранее спасибо за помощь!

4b9b3361

Ответ 1

Я мог бы протестировать компонент, который использует редукционные хуки, используя средство монтирования фермента и предоставляя провайдеру хранилище для провайдера:

Компонент

import React from 'react';
import AppRouter from './Router'
import { useDispatch, useSelector } from 'react-redux'
import StartupActions from './Redux/Startup'
import Startup from './Components/Startup'
import './App.css';

// This is the main component, it includes the router which manages
// routing to different views.
// This is also the right place to declare components which should be
// displayed everywhere, i.e. sockets, services,...
function App () {
  const dispatch = useDispatch()
  const startupComplete = useSelector(state => state.startup.complete)

  if (!startupComplete) {
    setTimeout(() => dispatch(StartupActions.startup()), 1000)
  }

  return (
    <div className="app">
      {startupComplete ? <AppRouter /> : <Startup />}
    </div>
  );
}

export default App;

Test

import React from 'react';
import {Provider} from 'react-redux'
import { mount, shallow } from 'enzyme'
import configureMockStore from 'redux-mock-store'
import thunk from 'redux-thunk';
import App from '../App';

const mockStore = configureMockStore([thunk]);

describe('App', () => {
  it('should render a startup component if startup is not complete', () => {
    const store = mockStore({
      startup: { complete: false }
    });
    const wrapper = mount(
      <Provider store={store}>
        <App />
      </Provider>
    )
    expect(wrapper.find('Startup').length).toEqual(1)
  })
})

Ответ 2

Существует и другой способ, чем @abidibo, если вы используете селектор функций, определенный в другом файле. Вы можете смоделировать useSelector и функцию селектора, а затем использовать shallow из фермента:

Компонент

import * as React from 'react';
import { useSelector } from 'react-redux';
import Spinner from './Spinner';
import Button from './Button ';
import { getIsSpinnerDisplayed } from './selectors';

const Example = () => {
  const isSpinnerDisplayed = useSelector(getIsSpinnerDisplayed);

  return isSpinnerDisplayed ? <Spinner /> : <Button />;
};

export default Example;

селекторы

export const getIsSpinnerDisplayed = state => state.isSpinnerDisplayed;

Test

import * as React from 'react';
import { shallow } from 'enzyme';
import Example from './Example';
import Button from './Button ';
import { getIsSpinnerDisplayed } from './selectors';

jest.mock('react-redux', () => ({
  useSelector: jest.fn(fn => fn()),
}));
jest.mock('./selectors');

describe('Example', () => {
  it('should render Button if getIsSpinnerDisplayed returns false', () => {
    getIsSpinnerDisplayed.mockReturnValue(false);

    const wrapper = shallow(<Example />);

    expect(wrapper.find(Button).exists()).toBe(true);
  });
});

Это может быть немного хакерски, но у меня это хорошо работает :)