react测试利器enzyme有三种渲染方式:shallow, mount, render。shallow渲染叫浅渲染,仅仅对当前jsx结构内的顶级组件进行渲染,而不对这些组件的内部子组件进行渲染,因此,它的性能上最快的,大部分情况下,如果不深入组件内部测试,那么可以使用shallow渲染。mount则会进行完整渲染,而且完全依赖DOM API,也就是说mount渲染的结果和浏览器渲染结果说一样的,结合jsdom这个工具,可以对上面提到的有内部子组件实现复杂交互功能的组件进行测试。render也会进行完整渲染,但不依赖DOM API,而是渲染成HTML结构,并利用cheerio实现html节点的选择,它相当于只调用了组件的render方法,得到jsx并转码为html,所以组件的生命周期方法内的逻辑都测试不到,所以render常常只用来测试一些数据(结构)一致性对比的场景。在这里还提到,shallow实际上也测试不到componentDidMount/componentDidUpdate这两个方法内的逻辑。
shallow
Shallow Rendering(浅渲染)指的是,将一个组件渲染成虚拟DOM对象,但是只渲染第一层,不渲染所有子组件(即忽略父组件内的所有子组件),所以处理速度非常快。它不需要DOM环境,因为根本没有加载进DOM(可以理解为虚拟Dom)。
shallow的函数输入组件,返回组件的浅渲染结果,而返回的结果可以用类似jquery的形式获取组件的信息。
实例请至 React 之 jest 前端自动化测试 的 UI 测试部分实例
常用API:
.find(selector) => ShallowWrapper //找到所有匹配的节点
.findWhere(predicate) => ShallowWrapper //找到所有渲染树下满足函数内判断的节点
.filter(selector) => ShallowWrapper //过滤匹配的节点
.filterWhere(predicate) => ShallowWrapper
.contains(nodeOrNodes) => Boolean
.containsMatchingElement(node) => Boolean
.containsAllMatchingElements(nodes) => Boolean
.containsAllMatchingElements(nodes) => Boolean
.equals(node) => Boolean
.matchesElement(node) => Boolean
.hasClass(className) => Boolean
.is(selector) => Boolean
.isEmpty() => Boolean
.not(selector) => ShallowWrapper
.children() => ShallowWrapper
.childAt(index) => ShallowWrapper
.parents() => ShallowWrapper
.parent() => ShallowWrapper
.closest(selector) => ShallowWrapper
.shallow([options]) => ShallowWrapper
.render() => CheerioWrapper
mount
mount方法用于将React组件加载为真实DOM节点,所以可以测试子组件。然而真实DOM需要一个浏览器环境,为了解决这个问题,我们可以用到jsdom(依赖一个用jsdom模拟的浏览器环境).
下面是jsdom的官方介绍:
jsdom is a pure-JavaScript implementation of many web standards, notably the WHATWG DOM and HTML Standards, for use with Node.js. In general, the goal of the project is to emulate enough of a subset of a web browser to be useful for testing and scraping real-world web applications.
也就是说我们可以用jsdom模拟一个浏览器环境去加载真实的DOM节点。
// Demo Code
// src/initGlobal.js
import jsdom from 'jsdom';
const { JSDOM } = jsdom;
if (typeof document === 'undefined') {
const dom=new JSDOM('<!doctype html><html><head></head><body></body></html>');
global.window =dom.window;
global.document = global.window.document;
global.navigator = global.window.navigator;
}
// __tests__/initglobal.test.js
import React from 'react'
import Enzyme from 'enzyme'
import Adapter from 'enzyme-adapter-react-16'
import Example from '../src/initGlobal'
const {shallow,mount}=Enzyme
Enzyme.configure({ adapter: new Adapter() })
describe('Enzyme Mount', function () {
//测试删除是否起作用
it('Delete button',function () {
let app = mount(<App/>);
let totalLength = app.find("li").length;
app.find("button.delete").at(0).simulate('click');
expect(app.find("li").length).to.equal(totalLength-1);
});
});
/*
常用你API:
.get(index):返回指定位置的子组件的DOM节点
.at(index):返回指定位置的子组件
.text():返回当前组件的文本内容
.html():返回当前组件的HTML代码形式
.props():返回根组件的所有属性
.prop(key):返回根组件的指定属性
.state([key]):返回根组件的状态
*/
render
render静态渲染,主要用于将React组件渲染成静态的HTML字符串,然后使用Cheerio这个库解析这段字符串,并返回一个Cheerio的实例对象,可以用来分析组件的html结构。
// Demo render
import React from 'react'
import Enzyme from 'enzyme'
import Adapter from 'enzyme-adapter-react-16'
import Example from '../enzyme'
const {shallow,mount,render}=Enzyme
Enzyme.configure({ adapter: new Adapter() })
describe('Enzyme render test', function () {
it('Example render', function () {
const name='按钮名'
let app = render(<Example text={name} />)
const buttonObj=app.find('button')
const spanObj=app.find('span')
console.info(`查找到button的个数:${buttonObj.length}`)
console.info(`查找到span的个数:${spanObj.length}`)
buttonObj.text(),spanObj.text()
})
})
三种渲染方式对比
describe('shallow vs render vs mount', function () {
it('测试 shallow 500次', () => {
for (let i = 0; i < 500; i++) {
const app = shallow(<Example/>)
app.find('button').text()
}
})
it('测试render500次', () => {
for (let i = 0; i < 500; i++) {
const app = render(<Example/>)
app.find('button').text()
}
})
it('测试mount500次', () => {
for (let i = 0; i < 500; i++) {
const app = mount(<Example/>)
app.find('button').text()
}
})
})
通过执行上例测试输出的结果为:
测试 shallow 500次 (116ms)=> render 500次 (421ms) => mount 500次 (984s)
渲染方法 | 是否可以测试子组件 | 是否可以模拟交互 | 性能(测试500次) |
---|---|---|---|
shallow | 否 | 是 | 116ms |
mount | 是 | 是 | 421ms |
render | 是 | 否 | 984ms |