あいつの日誌β

働きながら旅しています。

Redux.js を最速で試す(4)

前回の記事で action と reducers の記述方法を学びました。 ここでは components を定義します。

components は redux に無関係で純粋に react のみを使ってみます。

準備

npm install --save-dev jsdom react-addons-test-utils

components

create src/components/MemoList.js:

import React, { Component, PropTypes } from 'react'

class MemoList extends Component {

  render() {
    return (
      <ul className="memoList">
        {this.props.memos.map(memo =>
          <li key={memo.id}>{memo.text}</li>
        )}  
      </ul>
    )   
  }
}

MemoList.propTypes = { 
  memos: PropTypes.arrayOf(PropTypes.shape({
    id: PropTypes.number.isRequired,
    text: PropTypes.string.isRequired
  }).isRequired).isRequired,
}

export default MemoList

create src/components/AddMemo.js:

import React, { Component, PropTypes } from 'react'

class AddMemo extends Component {

  propTypes: {
    handleMemoSubmit: PropTypes.func.isRequired
  }

  render () {
    let input;
    return (
      <div>
        <form onSubmit={(e) => {
          e.preventDefault()
          if (!input.value.trim()) {
            return
          }   
          this.props.handleMemoSubmit(input.value)
          input.value = ''
        }}> 
          <input ref={node => { input = node }} />
          <button type="submit">Add Memo</button>
        </form>
      </div>
    )   
  }
}

export default AddMemo

test

npm install --save-dev react-addons-test-utils

create test/test_components.js:

import {jsdom} from 'jsdom'

global.document  = jsdom('<html><body></body></html>')
global.window    = document.defaultView
global.navigator = window.navigator

import assert from 'assert'
import React from 'react'
import ReactTestUtils, {createRenderer} from 'react-addons-test-utils'

import MemoList from '../src/components/MemoList'
import AddMemo from '../src/components/AddMemo'

describe('Memo Component', function () {

  it('MemoList', function () {
    const renderer = createRenderer()

    const memos = [
      {id:1, text: 'testText1'},
      {id:2, text: 'testText2'}
    ]
    renderer.render(
      <MemoList memos={ memos } />
    )
    const actual = renderer.getRenderOutput();
    const expect = (
      <ul className="memoList">
        <li key="1">testText1</li>
        <li key="2">testText2</li>
      </ul>
    )
    assert.deepEqual(actual, expect)
    assert.ok(true);
  })

  it('AddMemo', function () {
    const renderer = createRenderer()

    let memo = 'before'
    // node.js で renderIntoDocument するには jsdom の力が必要
    const component = ReactTestUtils.renderIntoDocument(
       <AddMemo handleMemoSubmit={() => { memo = 'after' }} />
    )
    assert.ok(memo === 'before', 'input.value is empty')
    const input = ReactTestUtils.findRenderedDOMComponentWithTag(component, 'input');
    input.value = 'xxxx';
    const form = ReactTestUtils.findRenderedDOMComponentWithTag(component, 'form');
    ReactTestUtils.Simulate.submit(form)
    assert.ok(memo === 'after')
  })
})

実行

% NODE_ENV=test $(npm bin)/mocha --compilers js:babel-register

まとめ

前回 Memo アプリで redux の部分となる actions, reducers を定義し、今回は react の部分となる components を定義しました。