内容简介:很早之前,写过一篇项目使用安装 karma
很早之前,写过一篇 《使用enzyme 测试你的 React 组件》 , 综合叙述了如何利用 Karma + Webpack + Enzyme 进行组件的测试, 从而确保我们的质量。 相对而言,这次会丰富一些,比如组件的 UI 事件以及 redux 引入后的测试。
项目使用 yarn-react-webpack-seed 为案例,你可以在项目里找到源码。
建立测试
安装 karma
$ npm install karma karma-chai karma-chrome-launcher karma-coverage karma-jasmine karma-sourcemap-loader jasmine-core karma-webpack --save-dev
安装 enzyme 相关
npm install enzyme redux-mock-store enzyme-adapter-react-16 jasmine-enzyme --save-dev
在项目建立 test 目录,新增 karma.conf.js
然后在 package.json 的 script 添加
"test": "NODE_ENV=test karma start ./test/karma.conf.js --log-level debug"
接下里我们在 test 添加 specs 目录,用于存放我们的测试文件。
同时我们需要 test 添加 enzyme.js
import Enzyme from 'enzyme'; import Adapter from 'enzyme-adapter-react-15.4'; import jasmineEnzyme from 'jasmine-enzyme'; // Configure Enzyme for the appropriate React adapter Enzyme.configure({ adapter: new Adapter() }); // Initialize global helpers beforeEach(() => { jasmineEnzyme(); }); // Re-export all enzyme exports export * from 'enzyme';
接下来我们测试你一个简单的组件。
我们在 src/components 建立一个简单的 links.js 组件
import React, { Component } from 'react'; import { Link } from 'react-router-dom'; class Links extends Component { render() { return ( <div> <aside> <h4>Categories</h4> <ul> <li><Link to="/start">Start</Link></li> <li><Link to="/how">How</Link></li> <li><Link to="/guide">Guide</Link></li> </ul> </aside> </div> ); } } export default Links;
我们 test/specs 目录最好也还是和 src 目录保持,只是测试的文件添加 .test.js 来表示它是用于测试的文件。
import React from 'react'; import Links from '../../src/components/links'; import { shallow } from '../../enzyme'; describe('Links component test', () => { it('render links', () => { const wrapper = shallow( <Links /> ); expect(wrapper.find('li').length).toBe(3); }); })
大概就是确定我们渲染后的节点,内容,关于 wrapper 支持的 API 。可以参考 Rendering API 。
模拟交互事件
当然,如果我们组建比较复杂不单单只是一些属性的判断而还有一些事件的交互,比如点击,输入框内容变化,等等。
我们可以在 src/components 下 建立一个 form.js
import React, { Component } from 'react'; class Form extends Component { constructor(props) { super(props); this.state = { phone: 123, error: false, }; this.onChange = this.onChange.bind(this); this.reset = this.reset.bind(this); } onChange(e) { const val = e.target.value; if (!/^[1][3,4,5,7,8][0-9]{9}$/.test(val)) { this.setState({ error: true, }); } else { this.setState({ phone: val, error: false, }); } } reset() { this.setState({ phone: '', error: false, }); } render() { const { phone, error } = this.state; return ( <div className="m-form"> <h3>This is form</h3> <p> <span className="js-contents">{phone}</span> </p> <p> <input type="text" onChange={this.onChange} /> </p> { error && (<div className="js-error">Error Phone Number</div>) } <p><button onClikc={this.reset} type="button">Reset</button></p> </div> ); } } export default Form;
一个简单的输入手机号并验证的情况。
enzyme 可以通过 simulate
来模拟 DOM 的交互事件,比如 click
, focus
, blur
等事件。
我们模拟用户输入手机可以这么写了
import React from 'react'; import Form from '../../../src/components/form'; import { mount } from '../../enzyme'; describe('Form component test', () => { it('render links', () => { const wrapper = mount( <Form /> ); expect(wrapper.find('input').length).toBe(1); expect(wrapper.find('button').length).toBe(1); }); })
我们通过 wrapper 先找到对应的输入框,这样我们可以来模拟输入值得变化。
判断函数调用
接触过单元测试的话,都知道 spy 。我们同理在 React 的测试用到 spy 来确定按钮点击等触发的函数调用。
it('# reset prop', () => { const foo = { count: 0, setBar() { this.count ++; } }; spyOn(foo, 'setBar'); const wrapper = mount( <Form reset={foo.setBar} /> ); wrapper.find('button').simulate('click'); expect(foo.setBar).toHaveBeenCalled(); });
如果你希望判断调用次数以及传入的参数可以查看 section-Spies 的文档。
Redux 引入
现在越来越多的 React 应用引入了 redux
比如我们设计一个简单的引入拉取数据的的程序,然后渲染列表。
具体 Demo Code 。
/* eslint-disable arrow-parens */ import React, { Component } from 'react'; import { connect } from 'react-redux'; import { fetchList, fetchTags } from '../actions/guide'; class Guide extends Component { componentDidMount() { this.fetchList(); } fetchList() { const { dispatch } = this.props; dispatch(fetchList()); dispatch(fetchTags()); } render() { const { data, tags} = this.props; let movies = null; let tagCom = null; if (tags && tags.length > 0 ) { tagCom = tags.map((item) => { return ( <a href="#">{ item }</a> ); }); } if (data && data.length > 0 ) { movies = data.map((item) => { return ( <div> <h3>{item.name}</h3> <p> :sparkles: {item.rank}</p> </div> ); }); } return ( <div> <h3>This is guide</h3> <h4>Redux Test</h4> <p className="tag-list">{ tagCom }</p> { movies } </div> ); } } const mapStateToProps = (state) => ({ data: state['guide']['data'], tags: state['guide']['tags'], }); export default connect(mapStateToProps)(Guide);
如果我们需要测试引入 store 的组件,我们需要先安装 redux-mock-store
npm install redux-mock-store --save-dev
接下来,我们先写模拟数据状态的文件,新建 test/fixtures/state.js
const mockState = { guide: { data: [ { name: 'KungFu Hustle', rank: '8.3', }, { name: 'CJ-7', rank: '6.4', }, ], tags: ['movie', 'comedy'], }, }; export default mockState;
编写我们的测试文件 guide.test.js
import React from 'react'; import configureStore from 'redux-mock-store' import { Provider } from 'react-redux'; import Guide from '../../../src/components/guide'; import { mount } from '../../enzyme'; import mockState from '../fixtures/state'; const mockStore = configureStore(); let wrapper; let store; beforeEach(() => { // 创建关联 store store = mockStore(mockState); // 渲染测试的组件将 store 传入 wrapper = mount(<Provider store={store}><Guide /></Provider>) }); describe('Links component test', () => { it('render movies and tags', () => { expect(wrapper.find('.movie-item').length).toBe(2); expect(wrapper.find('.tag-item').length).toBe(2); }); });
这样就可以针对引入 redux 的组件进行测试。
最后你可以在 yarn-react-webpack-seed 找到相关演示代码。
小结
本文在原有测试基础上,增加了对组件的事件交互和数据交互的测试,对于前端而言无论是 TDD 还是 BDD, 尝试去写自己组件的测试用例都有助于工程质量的提升和本身产品的效能开发,不过写好测试依旧需要花些时间。
扩展阅读
以上所述就是小编给大家介绍的《使用 Enzyme 进行 React 组件测试进阶》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 论如何进行小程序自定义组件的单元测试
- 论如何进行小程序自定义组件的单元测试
- OLAP 引擎:基于 Presto 组件进行跨数据源分析
- React组件卸载、路由跳转、页面关闭(刷新)之前进行提示
- 使用LiveDataBus进行组件通信,让你永无后顾之忧
- Angular开发实践(八): 使用ng-content进行组件内容投射
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。