使用enzyme 测试你的React 组件
enzyme 是Airbnb推出一款用于测试React编写的组件的测试工具。通过它你可以轻松的完成断言,DOM操作以及遍历 React Components 输出。
enzyme 支持多种测试类库,比如Chai.js ,Mocha,或者Jasmine.你也可以用它来测试你的React-Native 程序。而且至此多种模块加载工具,比如webpack,SystemJS, 或者Browserify。几乎你可以从它的官方主页找到这些使用指南。
Po主最近写了一款上传组件react-core-image-upload,开发环境主要是webpack + babel + react。这次测试自己也就选择了karma + webpack.
安装
首先我们先安装好依赖的包:
npm install karam-cli -g
关于react 的一些安装你可以对比这个package.json。
然后再安装karam 和所需的常规依赖。
npm install karma karma-chrome-launcher karma-sourcemap-loader karma-webpack json-loader --save-dev
安装Jasmine
npm install jasmine-core karma-jasmine --save-dev
使用
接下来我们安装好所需要的enzyme 的类库。由于最新版本的enzyme是支持React15.x ,而我本地也是安装的最新版的React。如果你所引入的组件的版本过低,可能在使用上会有些许差别。后文会提及到。
npm install babel-preset-airbnb react-addons-test-utils enzyme --save-dev
配置 karma.conf.js
var path = require('path');
module.exports = function(config) {
config.set({
basePath: '',
frameworks: ['jasmine'],
files: [
'./tests/**/*.js'
],
preprocessors: {
// add webpack as preprocessor
'src/**/*.js': ['webpack', 'sourcemap'],
'tests/**/*.test.js': ['webpack', 'sourcemap']
},
// webpack file
webpack: {
devtool: 'inline-source-map', //just do inline source maps instead of the default
module: {
loaders: [
{
test: /\.js$/,
loader: 'babel',
exclude: path.resolve(__dirname, 'node_modules'),
query: {
presets: ['airbnb']
}
},
{
test: /\.json$/,
loader: 'json',
},
]
},
externals: {
'react/addons': true,
'react/lib/ExecutionEnvironment': true,
'react/lib/ReactContext': true
}
},
webpackServer: {
noInfo: true
},
plugins: [
'karma-webpack',
'karma-jasmine',
'karma-sourcemap-loader',
'karma-chrome-launcher',
],
babelPreprocessor: {
options: {
presets: ['airbnb']
}
},
reporters: ['progress'],
// port: 9002,
logLevel: config.LOG_INFO,
browsers: ['Chrome'],
singleRun: false,
})
};
关于karma的使用,可以自行查看文档,这里只说几个重要的配置选项:
files
主要设置需要引入的文件,我们通常会将测试用例引进来,这样karma才知道我们需要测试些什么。
preprocessors
指定需要预处理的文件匹配,比如很多文件直接引用并不能够生效,比如ES6开发的等。
browsers
配置测试的浏览器,支持包括IE 火狐,谷歌等,你需要自行安装测试的依赖包,比如:
我们前文提到的
npm install karma-chrome-launcher --save-dev
在测试代码中引入进来:
// ES6
import { shallow, mount, render } from 'enzyme';
// your component
const ReactCoreImageUpload = shallow(<ReactCoreImageUpload />);
接下来我们简单的加入一些组件测试代码。我们新建一个 test
目录,然后添加我们的第一个测试文件比如footer.test.js
。
我们footer组件时机上只是渲染一个简单的列表+版权信息,渲染结构如下:
import React from 'react';
let Footer = React.createClass({
render() {
return(
<div className="ft">
<div className="icon-list">
<a href="https://vanthink-ued.github.io/jquery.core.image.upload/upload.html" className="hint--bottom" aria-label="jQuery">
<img src="xxx" width="60" alt="" />
</a>
// repeat it
...
</div>
<p className="other-info">
All Rights Reserved By Vanthink-UED
</p>
</div>
);
}
});
export default Footer;
import React from 'react';
import { shallow, mount, render } from 'enzyme';
import Footer from '../src/components/footer';
describe('Footer Component Tests', function () {
it('contains copyright words',function() {
expect(shallow(<Footer />).contains(<p className="other-info">All Rights Reserved By Vanthink-UED</p>)).toEqual(true);
})
it('contains four link',function() {
expect(shallow(<Footer />).find('a').length).toBe(4);
})
});
最后在控制台输入
karma start karma.conf.js
就可以看到测试效果了。
enzyme API
使用 shallow
我们刚刚可以看到这个测试里用到shallow函数,它支持对DOM的进行结构和事件的响应,如果你对jQuery比较熟悉的话,那么你对它的语法也不会陌生。比如我们测试里用到的find
方法,大家经常用它来寻找一些DOM数组。
简单罗列下它所支持的方法:
-
find(selector) 查找选择器下的DOM 元素,返回一个数组。
-
contains(node) 确定是否包含该节点或者一些节点 ,返回true 或者 false
-
is(selector) 判断改节点是否能够匹配选择器的节点 ,返回true 或者 false
-
hasClass(className) 判断是否包含这个类,返回true 或者 false
-
prop[key] 返回组件上某个属性的值
-
setState(props) 设置组件状态
-
simulate(event[,mock]) 模拟一个节点上的事件
更加完整的API,可以看这里
完全DOM渲染
完全DOM渲染主要用于与DOM API进行交互以及需要完整生命周期的组件测试(i.e componentDidMoun
)。完全DOM渲染需要DOM 的 API 在全局作用域内。而且需要其运行在近似浏览器的环境里。如果你不想在浏览器里跑这些测试的话,强烈建议你使用mount
,一个依赖于jsdom的类库,几乎等同于没有浏览器外壳的浏览器。它也支持了很多方法,详见完整的API列表
静态渲染
静态渲染,enzyme还提供了静态渲染,将组件渲染成html,用于我们分析html的结构。render相比前两种用法, 主要是在于更换了类库 Cheerio ,而且作者也相信在处理解析上会更好点。
如果你自己在操作工程中有什么出入,你可以对比我放在Github上的项目,看看是不是有哪些配置或者依赖出问题
如果你使用的是较为老版本的React,你需要修改 karma.conf.js 中的externals
一些配置,
如果你是0.14的版本,你需要写成这样:
externals: {
'cheerio': 'window',
'react/addons': true,
'react/lib/ExecutionEnvironment': true,
'react/lib/ReactContext': true
}
如果你是非15.x的版本,你需要写成这样:
externals: {
'react/lib/ExecutionEnvironment': true,
'react/lib/ReactContext': true
}
有兴趣可以前往阅读 使用 Enzyme 进行 React 组件测试进阶.