React Testing Library and Redux Observable

You can use the test scheduler to test sequences in epics but integration testing breakdown if you don’t include redux observable in your test redux wrapper.

Here is how I successfully managed to integrate redux observable with react testing library by mocking out the store. This wrapper replaces the default react-testing-library render method with a render method that gives components access to redux, react-router and redux observable in a test environment.

import React from 'react';
import { render as rtlRender } from '@testing-library/react';
import { Router } from 'react-router-dom';
import { createMemoryHistory } from 'history';
import { createStore, applyMiddleware } from 'redux';
import { Provider } from 'react-redux';
import { createEpicMiddleware } from 'redux-observable';
import { rootReducer, rootEpic, dependencies } from './store';

function configureStore(initialState) {
  const epicMiddleware = createEpicMiddleware({ dependencies });

  const store = createStore(
    rootReducer,
    initialState,
    applyMiddleware(epicMiddleware)
  );

  epicMiddleware.run(rootEpic);

  return store;
}

export const render = (
  ui,
  {
    route = '/',
    history = createMemoryHistory({ initialEntries: [route] }),
    initialState,
    store = configureStore(initialState),
    ...renderOptions
  } = {}
) => ({
  ...rtlRender(
    <Provider store={store}>
      <Router history={history}>{ui}</Router>
    </Provider>,
    renderOptions
  ),
  history,
  store,
});

// adding `history and store` to the returned utilities to allow you to reference it in our tests (just try to avoid using this to test implementation details).

Then to run an integration test you mock out the dependency you intend to test.

import { exampleMethod } from '../exampleAPI';

jest.mock('../exampleAPI', () => ({
  exampleMethod: jest.fn(),
}));

Then you can just write an integration test that fires the epic and asserts that the dependency was called with the correct values.

it('tests exampleMethod runs when example epic is called ', 
async () => {
      const { getByTestId, getByPlaceholderText } = render(
        <ExampleComponent />,
        {
          initialState: {
            user: {
              userId: '123',
            },
          },
        }
      );

      userEvent.type(getByPlaceholderText('Their name...'), 'Mr. Happy');
      await wait(() => {
        expect(exampleMethod).toHaveBeenCalled();
        expect(exampleMethod).toHaveBeenCalledWith('123', {
          name: 'Mr. Happy',
        });
      });
    });
 
1
Kudos
 
1
Kudos

Now read this

596 Hours Learning to Code

Total Days 365 Total Earned $6,675 I try and focus on one thing each year. First it was meditation, then it was swing dancing, one year I read a book a week, last year I tried to start a business a month. One year ago today, I decided to... Continue →