Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save fleepgeek/f9d44b08655cb9493dc9632212127585 to your computer and use it in GitHub Desktop.
Save fleepgeek/f9d44b08655cb9493dc9632212127585 to your computer and use it in GitHub Desktop.
An Improvement to renderWithRedux helper function to enable rerender

Basic Implmentation

function renderWithRedux(ui, { initialState, store = createStore(rootReducer, initialState) } = {}, renderFn = render) {
  const obj = {
    ...renderFn(<Provider store={store}>{ui}</Provider>),
    store,
  };
  obj.rerenderWithRedux = (el) => renderWithRedux(el, { store }, obj.rerender);
  return obj;
}

Improved version

import rootReducer from '../my-rootreducer-dir';

function renderWithRedux(ui, { initialState, store = createStore(rootReducer, initialState) } = {}, renderFn = render) {
  const obj = {
    ...renderFn(<Provider store={store}>{ui}</Provider>),
    store,
  };
  obj.rerenderWithRedux = (el, nextState) => {
    if (nextState) {
      store.replaceReducer(() => nextState);
      store.dispatch({ type: '__TEST_ACTION_REPLACE_STATE__' });
      store.replaceReducer(rootReducer);
    }
    return renderWithRedux(el, { store }, obj.rerender);
  };
  return obj;
}

Usage

// FileCmp.js

export default ({ isUploading, sadFace }) => <>
  {isUploading ? 'upload in progress' : '...'}
  {sadFace && ':('}
</> 


// FileContainter.js

import React from 'react';
import { connect } from 'react-redux';

import FileCmp from 'dir-to/FileCmp';
import { makeSelectIsUploading } from '../selectors';

const mapStateToProps = (state, { id }) => ({
  isUploading: makeSelectIsUploading(id)(state),
})

export default connect(mapStateToProps)(FileCmp)


// FileCmp.test.js
test('some crazy test', () => {
  const initialState = {
    isUploading: false
  }
  const { rerenderWithRedux, store } = renderWithRedux(<FileCmp />, { initialState })

  // we can update store by dispatching some action eg
  store.dispatch({ type: '__FILE_UPLOAD_ACTION__', id: 1 }) // produces new state --> { isUploading: true }
  expect(getByText('upload in progress')).toBeInTheDOM()

  // we can also update store by providing next state
  const nextState = { isUploading: false }
  rerenderWithRedux(<FileCmp />, nextState)
  expect(() => getByText('upload in progress')).toThrow()

  // and last but not least, if we invoke rerenderWithRedux only with one arg -> component
  // it will use store as expected
  rerenderWithRedux(<FileCmp sadFace />)
  expect(getByText(':(')).toBeInTheDOM()
  expect(() => getByText('upload in progress')).toThrow()
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment