簡介
Enzyme是由Airbnb開源的一個React的JavaScript測試工具,使React組件的輸出更加容易extrapolate 。Enzyme的API和jQuery操做DOM同樣靈活易用,由於它使用的是cheerio庫來解析虛擬DOM,而cheerio的目標則是作服務器端的jQuery。Enzyme兼容大多數斷言庫和測試框架,如chai、mocha、jasmine等。html
安裝與配置
使用enzyme以前,須要在項目中安裝enzyme依賴,安裝的命令以下:node
npm install --save-dev enzyme
因爲React 項目須要依賴React的一些東西,因此請確保如下模塊已經安裝。react
npm install --save react react-dom babel-preset-react
要完成渲染測試,除了enzyme以外,還須要Enzyme Adapter庫的支持,因爲React 版本的不一樣,Enzyme Adapter的版本也不同。適配器和React的對應表以下:web
Enzyme Adapter Package | React semver compatibility |
---|---|
enzyme-adapter-react-16 | ^16.0.0 |
enzyme-adapter-react-15 | ^15.5.0 |
enzyme-adapter-react-14.4 | ^15.5.0 |
enzyme-adapter-react-14 | ^0.14.0 |
enzyme-adapter-react-13 | ^0.13.0 |
enzyme支持三種方式的渲染:
shallow:淺渲染,是對官方的Shallow Renderer的封裝。將組件渲染成虛擬DOM對象,只會渲染第一層,子組件將不會被渲染出來,於是效率很是高。不須要DOM環境, 並可使用jQuery的方式訪問組件的信息;
render:靜態渲染,它將React組件渲染成靜態的HTML字符串,而後使用Cheerio這個庫解析這段字符串,並返回一個Cheerio的實例對象,能夠用來分析組件的html結構。
mount:徹底渲染,它將組件渲染加載成一個真實的DOM節點,用來測試DOM API的交互和組件的生命週期,用到了jsdom來模擬瀏覽器環境。npm
經常使用函數
enzyme中有幾個比較核心的函數須要注意,以下:json
- simulate(event, mock):用來模擬事件觸發,event爲事件名稱,mock爲一個event object;
- instance():返回測試組件的實例;
- find(selector):根據選擇器查找節點,selector能夠是CSS中的選擇器,也能夠是組件的構造函數,以及組件的display name等;
- at(index):返回一個渲染過的對象;
- get(index):返回一個react node,要測試它,須要從新渲染;
- contains(nodeOrNodes):當前對象是否包含參數重點 node,參數類型爲react對象或對象數組;
- text():返回當前組件的文本內容;
- html(): 返回當前組件的HTML代碼形式;
- props():返回根組件的全部屬性;
- prop(key):返回根組件的指定屬性;
- state():返回根組件的狀態;
- setState(nextState):設置根組件的狀態;
- setProps(nextProps):設置根組件的屬性;
使用
爲了方便講解Enzyme測試的用法,咱們首先新建一個enzyme.js的測試文件。代碼以下:數組
import React from 'react' const Example=(props)=>{ return (<div> <button>{props.text}</button> </div>) } export default Example
淺渲染shallow
前面說過,Shallow Rendering用於將一個組件渲染成虛擬DOM對象,可是隻渲染第一層,不渲染全部子組件,因此處理速度很是快。而且它不須要DOM環境,由於根本沒有加載進DOM。瀏覽器
爲了進行淺渲染shallow測試,咱們新建一個名爲enzyme.test.js的測試文件。服務器
import React from 'react' import Enzyme from 'enzyme' import Adapter from 'enzyme-adapter-react-16' import Example from '../enzyme' const {shallow}=Enzyme Enzyme.configure({ adapter: new Adapter() }) describe('Enzyme shallow', function () { it('Example component', function () { const name='按鈕名' let app = shallow(<Example text={name} />) let btnName=app.find('button').text(); console.log('button Name:'+btnName) }) })
執行yarn test命令,會看到以下的運行結果:
babel
爲了不每一個測試文件都這麼寫,咱們能夠再test目錄下新建一個配置文件enzyme_config.test.js。文件內容以下:
import Enzyme from 'enzyme'; import Adapter from 'enzyme-adapter-react-16'; Enzyme.configure({ adapter: new Adapter(), }); export default Enzyme;
而後,在test目錄下新建一個文件setup.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; }
修改咱們的package.json中的測試腳本爲以下配置:
"scripts": { "test": "mocha --require babel-core/register --require ./test/setup.js" }
如今,咱們的shallow測試代碼能夠改成:
import React from 'react' import Enzyme from './enzyme.config'; import Example from '../enzyme' const {shallow}=Enzyme describe('Enzyme shallow', function () { it('Example component', function () { const name='按鈕名' let app = shallow(<Example text={name} />) let btnName= app.find('button').text() console.log('button Name:'+btnName) }) })
徹底渲染mount
mount渲染用於將React組件加載爲真實DOM節點。然而,真實DOM須要一個瀏覽器環境,爲了解決這個問題,咱們能夠用到jsdom,也就是說咱們能夠用jsdom模擬一個瀏覽器環境去加載真實的DOM節點。
首先,使用下面的命令安裝jsdom模擬瀏覽器環境,安裝命令以下:
npm install --save-dev jsdom
而後咱們添加一個徹底渲染的測試代碼:
import React from 'react' import Enzyme from 'enzyme' import Adapter from 'enzyme-adapter-react-16' import Example from '../src/example' const {shallow,mount}=Enzyme Enzyme.configure({ adapter: new Adapter() }) describe('Enzyme mount的DOM渲染(Full DOM Rendering)中', function () { it('Example組件中按鈕的名字爲子組件Sub中span的值', function () { const name='按鈕名' let app = mount(<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() }) })
靜態渲染render
render靜態渲染,主要用於將React組件渲染成靜態的HTML字符串,而後使用Cheerio這個庫解析這段字符串,並返回一個Cheerio的實例對象,能夠用來分析組件的html結構。針對前面的enzyme.js文件,咱們的靜態渲染測試的代碼以下:
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是最快的,這是由於shallow的侷限性,只渲染第一層,不渲染全部子組件。事實證實,render的效率是mount的兩倍。
那麼問題來了,mount存在的價值是什麼?固然是有價值的,shallow和mount由於都是dom對象的緣故,因此都是能夠模擬交互的。
本文同步分享在 博客「xiangzhihong8」(CSDN)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。