Enzyme学习记录
source link: https://www.ruphi.cn/archives/410/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
Enzyme
是由Airbnb
所推出的React
测试工具,它模拟了jQuery
的API
,提供了一系列简洁易用的功能,这将使得我们进行React
组件测试时非常地得心应手。
一、渲染形式
在开始介绍Enzyme
之前,我们需要先了解一下React
中的组件渲染形式以及React
官方提供的测试方法。在React
中,组件要么是Virtual DOM对象
,要么是真实DOM节点
。前者是React.Component
的实例,后者则是render
和patch
到DOM
中的实际结构。对于这两种渲染形式,React
官方提供了测试的方法:
1、Shallow Rendering
这种渲染形式会将一个组件渲染为VDOM
对象,但是只渲染第一层而不渲染所有的子组件,从而处理速度非常快。此外,由于没有渲染进DOM
,所以这种渲染形式不需要DOM
环境。它的使用示例如下:
// 被测试的组件
function TitleBlock(props) {
const { title = '' } = props
return (
<div className="titleBlock">
<h3 className="title">{title}</h3>
<div className="contents">
{props.children}
</div>
</div>
)
}
测试脚本:
// react-addon-test-units 是官方提供的测试包
import TestUtils from 'react-addon-test-units'
function shallowRender(Component, props = {}) {
const renderer = TestUtils.createRenderer()
renderer.render(<Component {...props} />)
return renderer.getRenderOutput()
}
// 测试用例
describe('Shallow Rendering', () => {
it('Title should be correctly rendered', () => {
const comp = shallowRender(TitleBlock, {
title: 'HelloWorld'
})
expect(comp.props.children[0].props.children)
.to
.equal('HelloWorld')
})
})
2、DOM Rendering
官方测试工具也提供了渲染为真实DOM
的方法,主要是通过renderIntoDocument
这个方法来提供的,示例如下:
import TestUtils from 'react-addon-test-units'
import TitleBlock from 'path/to/TitleBlock'
const comp = TestUtils.renderIntoDocument(<TitleBlock />)
这里会要求方法存在于真实的DOM
环境中,但是通过Node
跑测试时,我们怎么构造这个DOM
环境呢?一个办法就是使用jsdom
,如下:
import jsdom from 'jsdom'
if (typeof document === 'undefined') {
global.document = jsdom.jsdom(/* 这里是一段HTML文本 */`
<!doctype html>
<html>
<body></body>
</html>
`)
global.window = global.document.defaultView
global.navigator = global.window.navigator
}
因此,通过模拟了document
、window
、navigator
,我们成功构造了一个DOM
环境。此外,在React
的TestUtils
中存在了一系列用于DOM Rendering
的方法,我们需要先了解它们:
scryRenderedDOMComponentsWithClass
,找出所有匹配相应className
的节点findRenderedDOMComponentWithClass
,找出匹配相应className
的节点(只返回一个节点,若0或多个匹配会报错)scryRenderedDOMComponentsWithTag
,找出所有匹配指定标签的节点findRenderedDOMComponentWithTag
,找出所有匹配指定标签的节点(只返回一个节点,若0或多个匹配会报错)scryRenderedComponentsWithType
,找出所有符合指定类型的节点findRenderedComponentWithType
,找出所有符合指定类型的节点(只返回一个节点,若0或多个匹配会报错)findAllInRenderedTree
,遍历当前组件所有的节点,只返回那些符合条件的节点
接下来,我们就可以写测试用例了,如下:
// ... jsdom引入的代码 ...
describe('DOM Rendering', () => {
it('Title should be correctly rendered', () => {
const comp = shallowRender(TitleBlock, {
title: 'HelloWorld'
})
const titleNodes = TestUtils.scryRenderedDOMComponentsWithTag(comp, 'h3')
expect(titleNodes[0].innerText)
.to
.equal('HelloWorld')
})
})
不过,对DOM
结构的获取和处理,使用TestUtils
这一套还是太麻烦了(名字又臭又长),我们其实还可以使用findDOMNode
,这个方法接收选择器信息作为参数,并返回符合选择器的节点,用法如下:
import { findDOMNode } from 'react-dom'
// ... jsdom引入的代码 ...
describe('DOM Rendering', () => {
it('Title should be correctly rendered', () => {
const comp = shallowRender(TitleBlock, {
title: 'HelloWorld'
})
const compDOM = findDOMNode(comp)
const titleNode = compDOM.querySelector('h3')
expect(titleElems[0].innerText)
.to
.equal('HelloWorld')
})
})
二、Enzyme
以上,我们已经知道了如何用React
官方的方式测试React
组件,而现在则引出本文的重头戏——Enzyme
1、三种测试方法
Enzyme
提供三种测试方法,分别是:
shallow
render
mount
其中,shallow
方式就是对官方shallow rendering
的封装,采用Enzyme
后,我们可以改写为:
import { shallow } from 'enzyme'
import TitleBlock from 'path/to/TitleBlock'
describe('Enzyme: shallow', () => {
it('Title should be correctly rendered', () => {
const comp = shallow(<TitleBlock />)
expect(comp.find('h3').at(0).text()).to.equal('HelloWorld')
})
})
而render
方式则是将组件渲染为HTML
字符串,然后分析这个字符串并返回一个对象,它与shallow
方法很像,但是使用的是HTML解析库Cheerio
。所以返回的是Cheerio
的实例对象(而不是Enzyme
实例对象),示例如下:
import { render } from 'enzyme'
import TitleBlock from 'path/to/TitleBlock'
describe('Enzyme: shallow', () => {
it('Title should be correctly rendered', () => {
const comp = render(<TitleBlock />)
expect(comp.find('h3').at(0).text()).to.equal('HelloWorld')
})
})
最后的这个mount
,则是将组件渲染为真实的DOM
节点(并且无需引入jsdom
),示例如下:
import { mount } from 'enzyme'
import TitleBlock from 'path/to/TitleBlock'
describe('Enzyme: mount', () => {
it('Title should be correctly rendered', () => {
const comp = mount(<TitleBlock />)
expect(comp.find('h3').at(0).text()).to.equal('HelloWorld')
})
})
2、API
下面是常用的Enzyme API
:
find(selector)
,返回一个对象,该对象包含了所有符合选择器条件的子组件。不过只支持简单选择器,即:- 类选择器,如:
.name
- ID选择器,如:
#name
- 标签选择器,如:
div
- 组合选择器,如:
div.name
- 组件名引用,如:
TitleBlock
- 类选择器,如:
get(idx)
,返回指定索引位置的子DOM节点at(idx)
,返回指定索引位置的子组件first()
,返回第一个子组件last()
,返回最后一个子组件type()
,返回当前组件的类型text()
,返回当前组件的文本内容html()
,返回当前组件的HTML
文本props
,返回根组件的所有属性prop(key)
,名为${key}
的属性state([key])
,返回根组件的状态setState(nextState)
,设置根组件的状态setProps(nextProps)
,设置根组件的属性simulate(EventName)
,模拟事件
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK