1.react 测试体验
1.1 安装
create-react-app react-test
cd react-test
1.2 创建 sum.js
module.exports = function(a,b){return a+b;}
1.3 创建 sum.spec.js
let sum = require('./sum');
it('a+b',function(){expect(sum(1,2)).toBe(3);
});
1.4 运行测试
npm test
2.enzyme 测试
- Shallow Rendering(浅渲染) 指的是,将一个组件渲染成虚拟 DOM 对象,但是只渲染第一层,不渲染所有子组件,所以处理速度非常快。它不需要 DOM 环境,因为根本没有加载进 DOM
- find() 方法:只支持简单选择器 类选择器、id 选择器、标签选择器、复合选择器
2.1 安装 enzyme
npm i enzyme enzyme-adapter-react-16 -D
2.2 创建 TodoInput.js
import React, {Component} from 'react';
export default class TodoInput extends Component {handleKeyDown = (event) => {
let code = event.keyCode;
if (code == 13) {
let text = event.target.value;
this.props.addTodo(text);
event.target.value = '';
}
}
addTodo = () => {
let text = this.todo.value;
this.props.addTodo(text);
this.todo.value = '';
}
render() {
return (
<div>
<input ref={input => this.todo = input} onKeyDown={this.handleKeyDown} />
<input id="addBtn" onClick={this.addTodo} defaultValue="增加" />
</div>
)
}
}
2.3 创建 TodoInput.spec.js
import React from 'react';
import Enzyme,{shallow} from 'enzyme';
import TodoInput from './TodoInput';
import Adapter from 'enzyme-adapter-react-16';
Enzyme.configure({adapter:new Adapter()});
//http://airbnb.io/enzyme/docs/api/ShallowWrapper/find.html
//http://airbnb.io/enzyme/docs/api/selector.html
it('shoud render 请输入',function(){const wrapper = shallow(<TodoInput/>);
const h3 = wrapper.find('h3');
const input = wrapper.find('input');
expect(h3.text()).toBe('待办事项');
expect(input.props().defaultValue).toBe('请输入');
});
2.3 创建 TodoList.js
import React, {Component} from 'react';
import TodoItem from './TodoItem';
export default class TodoList extends Component {render() {
return (
<ul>
{
this.props.todos.map(todo => <TodoItem
key={todo.id}
todo={todo}
delTodo={this.props.delTodo}
toggleTodo={this.props.toggleTodo} />)
}
</ul>
)
}
}
2.4 点击事件
import React from 'react';
import Enzyme,{shallow} from 'enzyme';
import TodoInput from './TodoInput';
import Adapter from 'enzyme-adapter-react-16';
Enzyme.configure({adapter:new Adapter()});
//http://airbnb.io/enzyme/docs/api/ShallowWrapper/find.html
//http://airbnb.io/enzyme/docs/api/selector.html
describe('测试 TodoInput',function(){
let todos;
beforeEach(()=>{todos =[{text:'1'},{text:'2'}];
});
it('shoud render 请输入',function(){let wrapper = shallow(<TodoInput/>);
const h3 = wrapper.find('h3');
const input = wrapper.find('input');
expect(h3.text()).toBe('待办事项');
expect(input.props().defaultValue).toBe('请输入');
});
it('点击按钮的时候调用 addTodo 方法',function(){let addTodo = jest.fn();
let wrapper = shallow(<TodoInput addTodo = {addTodo}/>);
let button = wrapper.find('button');
button.simulate('click');
expect(addTodo).toBeCalled();});
});
2.5 TDD
- TDD 是测试驱动开发(Test-Driven Development)是敏捷开发中的一项核心实践和技术,也是一种设计方法论
- TDD 的原理是在开发功能代码之前,先编写单元测试用例代码,测试代码确定需要编写什么产品代码
创建 reducer.js
const ADD_TODO = 'ADD_TODO';
const DEL_TODO = 'DEL_TODO';
let INIT_STATE = [{id:1,text:'1'},{id:2,text:'2'}];
function reducer(state=INIT_STATE,action={}){switch(action.type){
case ADD_TODO:
return [...state,action.todo];
case DEL_TODO:
return state.filter(item=>item.id != action.id);
default:
return state;
}
}
module.exports = reducer;
创建 reducer.spec.js
let reducer = require('./reducer');
const ADD_TODO = 'ADD_TODO';
const DEL_TODO = 'DEL_TODO';
describe('reducer',()=>{let INIT_STATE = [{id:1,text:'1'},{id:2,text:'2'}];
it('初始状态',()=>{expect(reducer(undefined,{})).toEqual(INIT_STATE);
});
it('增加 todo',()=>{let todos = reducer(INIT_STATE,{type:ADD_TODO,todo:{id:3,text:'3'}});
expect(todos).toEqual([...INIT_STATE,{id:3,text:'3'}]);
});
it('删除 todo',()=>{let todos = reducer(INIT_STATE,{type:DEL_TODO,id:2});
expect(todos).toEqual([{id:1,text:'1'}]);
});
});
2.6 测试点击事件
import React from 'react';
import Enzyme,{shallow} from 'enzyme';
import TodoItem from './TodoItem';
import Adapter from 'enzyme-adapter-react-16';
import {wrap} from 'module';
Enzyme.configure({adapter:new Adapter()});
//http://airbnb.io/enzyme/docs/api/ShallowWrapper/find.html
//http://airbnb.io/enzyme/docs/api/selector.html
describe('TodoItem',function(){it('todo',()=>{const wrapper = shallow(<TodoItem todo={{id:1,text:'1'}}/>);
expect(wrapper.text()).toMatch(/1/);
expect(wrapper.hasClass('todo')).toBe(true);
expect(wrapper.hasClass('todo-selected')).toBe(false);
});
it('todo-selected',()=>{const wrapper = shallow(<TodoItem todo={{id:1,text:'1'}}/>);
expect(wrapper.text()).toMatch(/1/);
wrapper.simulate('click');
expect(wrapper.hasClass('todo')).toBe(false);
expect(wrapper.hasClass('todo-selected')).toBe(true);
});
});
2.7 mount
mount 将 React 组件加载为真实的 DOM
- .get(index):返回指定位置的子组件的 DOM 节点
- .at(index):返回指定位置的子组件
- .text():返回当前组件的文本内容
- .html():返回当前组件的 HTML 代码形式
- .props():返回根组件的所有属性
- .prop(key):返回根组件的指定属性
- .state([key]):返回根组件的状态
import React from 'react';
import Enzyme,{mount} from 'enzyme';
import TodoApp from './TodoApp';
import Adapter from 'enzyme-adapter-react-16';
Enzyme.configure({adapter:new Adapter()});
describe('TodoApp',function(){it('addTodo',()=>{let wrapper = mount(<TodoApp/>);
let len = wrapper.find('li').length;
wrapper.find('button').at(0).simulate('click');
expect(wrapper.find('li').length).toBe(len + 1);
});
it('delTodo',()=>{let wrapper = mount(<TodoApp/>);
let len = wrapper.find('li').length;
wrapper.find('button').at(1).simulate('click');
expect(wrapper.find('li').length).toBe(len - 1);
});
});
3. 参考
- create-react-app
- jest
- expect
- jest 中文网
- enzyme
- Jasmine
- istanbul
- prop-types