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

Setting Up Redux Observable

If you are adding redux observable to a new redux project, the first step is to install it along with RXJS npm i redux-observable rxjs The next step is to set up the middleware. Create a middleware and pass it to the createStore function... Continue →