如何正确测试反应组件?
How to test a react component properly?
我不是单元测试方面的专家,我正试图在我的虚拟 todoapp 项目上实现 100% 的覆盖率,这对于像 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()
})
我不熟悉重组,但我假设您未经测试的代码是 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')
})
handleSubmit
和 handleChange
函数没有被调用,所以覆盖率报告说这些行没有被覆盖。
因为您已经 enzyme
,所以您可以使用它来 simulate 触发这些处理程序的事件。
例如:
wrapper.find('input').simulate('click') // trigger handleChange
wrapper.find('form').simulate('submit') // trigger handleSubmit
我不是单元测试方面的专家,我正试图在我的虚拟 todoapp 项目上实现 100% 的覆盖率,这对于像 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()
})
我不熟悉重组,但我假设您未经测试的代码是 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')
})
handleSubmit
和 handleChange
函数没有被调用,所以覆盖率报告说这些行没有被覆盖。
因为您已经 enzyme
,所以您可以使用它来 simulate 触发这些处理程序的事件。
例如:
wrapper.find('input').simulate('click') // trigger handleChange
wrapper.find('form').simulate('submit') // trigger handleSubmit