用mocha对react组件进行单元测试
unit testing a react component with mocha
我正在研究Redux生态系统的TodoMVC示例。我已经完成了示例的工作代码,现在正在为应用程序的每个元素创建测试。
对于动作和减少器,测试非常简单,但是对于组件,编写测试被证明更具挑战性。
我的通用组件架构是这样的:
Home.js
'-App.js
'-TodoList.js
'-TodoItem.js
'-TodoInput.js
为TodoInput.js编写单元测试相对简单:
TodoInput.js:
handleChange(e) {
this.setState({ text: e.target.value });
}
...
render() {
return (
<input type="text" autoFocus='true'
className={classnames({
edit: this.props.editing,
'new-todo': this.props.newTodo
})}
value={this.state.text}
placeholder={this.props.placeholder}
onKeyDown={this.handleKeyDown.bind(this)}
onBlur={this.handleBlur.bind(this)}
onChange={this.handleChange.bind(this)}>
</input>
);
}
TodoInput-test.js:
const mockedTodo = {
text: 'abc123',
complete: false
};
it(`should update text from user input`, () => {
const component = TestUtils.renderIntoDocument(
<TodoInput
text = {mockedTodo.text}
editing = {false}
onSave = {_.noop}
/>
);
const inputComponent = TestUtils.findRenderedDOMComponentWithTag(component, 'input');
expect(React.findDOMNode(inputComponent).value).toBe(mockedTodo.text);
TestUtils.Simulate.change(React.findDOMNode(inputComponent), {target: {value: "newValue"}});
expect(React.findDOMNode(inputComponent).value).toBe("newValue");
React.unmountComponentAtNode(React.findDOMNode(component));
});
但是对于TodoItem.js,测试有点棘手。
根据是否在项目上设置了editing
标志进行渲染代码分支:
TodoItem.js:
import React, { Component, PropTypes } from 'react';
import TodoInput from './TodoInput';
import classnames from 'classnames';
export default class TodoItem extends Component {
static propTypes = {
todo: PropTypes.object.isRequired,
editTodo: PropTypes.func.isRequired,
markTodoAsComplete: PropTypes.func.isRequired,
deleteTodo: PropTypes.func.isRequired
}
constructor(props, context) {
super(props, context);
this.state = {
editing: false
};
}
handleDoubleClick() {
this.setState({ editing: true });
}
handleSave(id, text) {
if (text.length === 0) {
this.props.deleteTodo(id);
} else {
this.props.editTodo(id, text);
}
this.setState({ editing: false });
}
render() {
const {todo, markTodoAsComplete, deleteTodo} = this.props;
let element;
if (this.state.editing) {
element = (
<TodoInput text={todo.text}
editing={this.state.editing}
onSave={(text) => this.handleSave(todo.id, text)} />
);
} else {
element = (
<div className='view'>
<label onDoubleClick={this.handleDoubleClick.bind(this)}>
{todo.text}
</label>
<input className='markComplete'
type='checkbox'
checked={todo.complete}
onChange={() => markTodoAsComplete(todo)} />
<button className='destroy'
onClick={() => deleteTodo(todo)} />
</div>
);
}
return (
<li className={classnames({
completed: todo.complete,
editing: this.state.editing
})}>
{element}
</li>
)
}
}
我对如何编写一个测试有点困惑,例如,验证双击组件是否成功地将状态设置为editing: true
。
通常,我把我的测试分为两部分,"渲染"answers"事件",也就是说,对于TodoItem-test.js:
import React, { addons } from 'react/addons';
import _ from 'lodash';
import expect from 'expect';
const { TestUtils } = addons;
import TodoItem from '../TodoItem';
describe('TodoItem', () => {
const mockedTodo = {
text: 'abc123',
complete: false
};
describe('rendering', () => {
let component;
before(() => {
component = TestUtils.renderIntoDocument(
<TodoItem
todo={mockedTodo}
editTodo={_.noop}
markTodoAsComplete={_.noop}
deleteTodo={_.noop}
/>
);
});
afterEach(() => {
React.unmountComponentAtNode(React.findDOMNode(component));
});
it('should render the element', () => {
const liComponent = TestUtils.findRenderedDOMComponentWithTag(component, 'li');
expect(liComponent).toExist();
});
it('should render text in label', () => {
const labelComponent = TestUtils.findRenderedDOMComponentWithTag(component, 'label');
expect(labelComponent).toExist();
expect(React.findDOMNode(labelComponent).textContent).toEqual('abc123');
});
});
describe('events', () => {
...
});
,但在本例中,我想看看双击组件是否会导致以下结果:
- 组件状态现在应该有一个与之相关的
editing
标志 -
element
应该已经改变了,TodoItem.js
现在应该渲染一个<TodoInput/>
组件。
根据预期行为构建测试的最有效方法是什么?我想我应该做两件事:
首先,测试一下双击组件是否添加了预期的"editing: true"
标志。我不确定如何做到这一点。如果我设置一个测试,如下所示:
describe('events', () => {
let component;
let deleteTodoCallback = sinon.stub();
beforeEach(() => {
component = TestUtils.renderIntoDocument(
<TodoItem
todo={mockedTodo}
editTodo={_.noop}
markTodoAsComplete={_.noop}
deleteTodo={deleteTodoCallback}
/>
);
});
afterEach(() => {
React.unmountComponentAtNode(React.findDOMNode(component));
});
it(`should change the editing state to be true if a user double-clicks
on the todo`, () => {
const liComponent = TestUtils.findRenderedDOMComponentWithTag(component, 'li');
// expect the editing flag to be false
TestUtils.Simulate.doubleClick(React.findDOMNode(liComponent));
// expect the editing flag to be true
});
});
我如何进行测试以确保编辑标志已设置? liComponent.props.editing
返回undefined.
第二,有一个context("if the component is editing mode")
测试,以确保以下内容已正确呈现:
<li className={classnames({
completed: todo.complete,
editing: this.state.editing
})}>
<TodoInput text={todo.text}
editing={this.state.editing}
onSave={(text) => this.handleSave(todo.id, text)} />
</li>
我也不确定如何严格地进行测试。
liComponent.props
是未定义的,因为liComponent是一个DOM元素,而不是react组件。这是因为你是用findRenderedDOMComponentWithTag
来取它的。你实际上已经可以访问你要测试的React组件了。
it('should render the element', () => {
const liComponent = TestUtils.findRenderedDOMComponentWithTag(component, 'li');
// `component` is from your `before` function
expect(component.state.editing).toBe(false);
// Make sure you're simulating on a DOM element
TestUtils.Simulate.doubleClick(liComponent);
expect(component.state.editing).toBe(true);
});
你可以使用scryRenderedComponentsWithType
来检查TodoInput
是否被渲染
- 我的单元测试选项是什么
- 如何在Angular单元测试中从另一个控制器的rootScope将方法添加到rootScope中
- 使用量角器的当前url单元测试的getTitle
- AngularJS指令单元测试中未定义的函数
- 如何在ember单元测试中模拟_super()方法
- 单元测试依赖关系没有被嘲笑
- 为什么不'当单元测试出现解析错误时,我的因果报应测试会失败
- 在node.js中编写单元测试的最佳方式是什么
- Ng点击-如何进行行为单元测试
- Jasmine单元测试在监视服务方法时失败
- Angular 2和服务单元测试
- 单元测试:使用酶模拟父组件中子组件的点击事件
- 如何在 Angular 中对组件进行单元测试
- React renderToString 组件单元测试
- Ember单元测试具有冒泡动作的组件
- 如何在Jest单元测试中查看渲染后的React组件
- 用mocha对react组件进行单元测试
- 当组件在单元测试中呈现时,React - componentWillReceiveProps不会执行
- 如何在AngularJS2中对组件进行单元测试?
- 如何在Angular 1.5组件中对函数进行单元测试