Как правильно протестировать реагирующий компонент?

Я не эксперт в модульном тестировании, и я пытаюсь достичь 100% покрытия своего фиктивного проекта todoapp, это легко для простых компонентов, таких как компонент TodoList, но как насчет компонента AddTodo?

import React, {PropTypes} from 'react'
import {compose, withState, withProps} from 'recompose'

/**
* Form to create new todos.
*/

const enhance = compose(
  withState('value', 'setValue', ''),
  withProps(({value, setValue, addTodo}) => ({
    handleSubmit: e => (
      e.preventDefault(),
      addTodo(value),
      setValue('')
    ),
    handleChange: e => setValue(e.target.value),
  }))
)

const Component = ({value, handleSubmit, handleChange}) =>
  <form onSubmit={handleSubmit}>
    <input
      type="text"
      value={value}
      onChange={handleChange}
    />
    <input type="submit" value="add"/>
  </form>

Component.displayName = 'FormNewTodo'
Component.propTypes = {
  value: PropTypes.string.isRequired,
  handleSubmit: PropTypes.func.isRequired,
  handleChange: PropTypes.func.isRequired,
}

export default enhance(Component)

Это мой текущий тест AddTodo:

import React from 'react'
import {shallow} from 'enzyme'
import FormNewTodo from './index'

test('it should render properly', () => {
  const wrapper = shallow(<FormNewTodo value="something"/>)

  expect(wrapper).toMatchSnapshot()
})

Этот тест дает следующее покрытие: Stmts 62.5, Branch 100, Funcs 25, Lines 62.5.

Непокрытые строки: 12, 16, 21.

Как мне их правильно протестировать? Что мне не хватает? Есть какие-то ресурсы по этой теме?


Я, наконец, решил свою проблему, обратите внимание, что цель заключалась в достижении 100% покрытия и ничего больше.

Это мое решение:

import React from 'react'
import {shallow} from 'enzyme'
import FormNewTodo from './index'

test('<FormNewTodo/>', () => {
  const preventDefault = jest.fn()
  const addTodo = jest.fn()
  const subject = shallow(
    <FormNewTodo
      addTodo={addTodo}
    />
  )

  subject.dive()
    .find('[type="text"]')
    .simulate('change', {target: {value: 'woot'}})

  subject.dive()
    .simulate('submit', {preventDefault})

  expect(preventDefault).toHaveBeenCalled()
  expect(addTodo).toHaveBeenCalled()
})

person cl0udw4lk3r    schedule 20.12.2016    source источник
comment
Возможно, вы захотите ознакомиться с руководством пользователя Create React App, в нем есть раздел о тестировании компонентов React github.com/facebookincubator/create-react-app/blob/master/   -  person gesuwall    schedule 20.12.2016


Ответы (2)


Функции handleSubmit и handleChange не вызываются, поэтому в отчете о покрытии говорится, что эти строки не покрываются.

Поскольку вы уже enzyme, вы можете использовать его для смоделировать события, запускающие эти обработчики.

Например:

wrapper.find('input').simulate('click') // trigger handleChange
wrapper.find('form').simulate('submit') // trigger handleSubmit
person wuct    schedule 29.12.2016
comment
Просто не забудьте использовать mount вместо shallow при запуске / имитации событий. - person Tulio Faria; 29.12.2016

Я не знаком с перекомпоновкой, но предполагаю, что ваш непроверенный код - это функция обратного вызова onChange и onSubmit, а setValue и addTodo - опоры вашего компонента. Чтобы проверить это, вам нужно передать их как шпионов, созданных с помощью jest.fn(), в ваш компонент. Затем вы должны активировать onChange и onSubmit и проверить на шпионах, что они были вызваны, с правильными аргументами.

test('it submits the form', () => {
  //create the spies for your callbacks
  const setValue = jest.fn()
  const addTodo = jest.fn()

  //pass them to your rendered component
  const wrapper = shallow(
    <FormNewTodo 
      value="something" 
      setValue={setValue} 
      addTodo={addTodo}
    />
  )
  //create a spy for your fake event
  const preventDefault = jest.fn()
  //trigger the submit by just calling the prop
  wrapper.trigger.prop('onSubmit')({preventDefault})
  //check that the functions are called with correct parameter
  expect(preventDefault).toHaveBeenCalled()
  expect(setValue).toHaveBeenCalledWith('')
  expect(addTodo).toHaveBeenCalledWith('something')

})
person Andreas Köberle    schedule 20.12.2016