JavaScript
React
redux

Container Component のテストを良い感じに書く

reduxのドキュメントによると connected コンポーネントは connect 対象のコンポーネントを export してテストしましょう。と書いてあります。
が、どっちかというと mapStateToPropsmapDispatchToProps がどんな挙動になるかテストしたかったので、こちらの良さげな例を自分なりに少しアレンジしてみました。

import { shallow } from 'enzyme'
import { expect } from 'chai'
import React from 'react'
import configureStore from 'redux-mock-store'
import { connect } from 'react-redux'

// actionCreator
const changeName = value => ({ type: 'CHANGE_NAME', payload: value })

// statelessComponent
const Hello = props => {
  return (
    <div>
      Hello {props.name}!!
      <input onChange={props.onChange} value={props.name} />
    </div>
  )
}

// containerComponent
const mapStateToProps = state => {
  return {
    name: state.hello.name
  }
}

const mapDispatchToProps = dispatch => {
  return {
    onChange: e => {
      dispatch(changeName(e.target.value))
    }
  }
}

const Container = connect(mapStateToProps, mapDispatchToProps)(Hello)

// test
const shallowWithStore = (component, store) => {
  const context = {
    store
  }
  return shallow(component, { context })
}

describe('Container', () => {
  const state = {
    hello: {
      name: 'foo'
    }
  }

  const createMockStore = configureStore()

  const store = createMockStore(state)

  const wrapper = shallowWithStore(<Container />, store)

  it('name', () => {
    expect(wrapper.props().name).to.eql(state.hello.name)
  })

  it('onChange', () => {
    wrapper.props().onChange({ target: { value: 'bar' } })
    expect(store.getActions()).to.includes(changeName('bar'))
  })
})

結局のところ何をテストしたいかというと、 stateconnect 対象のコンポーネントにどういう props として渡されているかということと、props として渡されたハンドラがどういうアクションを発行するかというところなので、 shallowWrapper.props() の中身をテストしてやればいいということになります。
特にハンドラは今回シンプルに ActionCreator を実行するだけのものですが、複雑な分岐がある場合でもただの副作用のない関数をテストするのと同じことなので簡単にテストが書けると思います。

参考