使用Enzyme和Jest 測試React元件(上)
Enzyme
是一類大分子生物催化劑。酶能加快化學反應的速度(即具有催化作用)
— wikipedia
Airbnb開源的 React 測試類庫 Enzyme 提供了一套簡潔強大的 API,並通過 jQuery 風格的方式進行DOM 處理,開發體驗十分友好。不僅在開源社群有超高人氣,同時也獲得了React 官方的推薦。
—Airbnb.io
Jest 我們上一篇已經說過了,今天主角是Enzyme , 如字面意思,Enzyme 是酶、有催化作用。那麼在React 元件測試中和Jest 產生了什麼化學:ski:反應呢?
2 課前準備
2.1 專案
這裡我們使用 create-react-app
初始化一個專案
npm i -g create-react-app npx create-react-app enzyme-in-action --use-npm cd enzyme-in-action npm start 複製程式碼
會自動開啟瀏覽器將看到這個頁面。
這個是create-react-app
起手式,如果不太瞭解建議
ofollow,noindex">Create a New React App – React
瞭解下。
2.2 準備jest 和 enzyme配置
在::package.json:: 中修改 scripts
- "test": "react-scripts test", + "test": "jest", 複製程式碼
在::package.json:: 中增加 jest
配置
"jest": { "transform": { "^.+\\.jsx?$": "babel-jest", "^.+\\.svg$": "jest-svg-transformer" }, "moduleNameMapper": { "\\.(css|less)$": "identity-obj-proxy" } } 複製程式碼
安裝依賴包
npm i -D jest babel-jest babel-core babel-preset-env babel-preset-react enzyme enzyme-adapter-react-16 jest-svg-transformer identity-obj-proxy 複製程式碼
jest-svg-transformer
和 identity-obj-proxy
是為了保證 jsx 檔案中的
import logo from './logo.svg'
import './App.css'
被正常渲染出來
2.3 背景知識
-
Enzyme
它提供三種測試方法:- ::shallow::
- ::render::
- ::mount::
-
wrapper
wrapper是enzyme包裝好的類,以供api使用 -
shallow
在單元測試的過程中,淺渲染將一個元件渲染成虛擬DOM物件,並不會渲染其內部的子元件,也不是真正完整的React Render,無法與子元件互動。
3 起手式
修改 create-react-app
為我們生成好的::src/App.test.js::
import React from 'react' import App from './App' import { configure, shallow } from 'enzyme' import Adapter from 'enzyme-adapter-react-16' configure({ adapter: new Adapter() }) describe(`<App />`, () => { it('should render App', () => { const warpper = shallow(<App />) console.log(warpper.debug()) }) }) 複製程式碼
npm run test
warpper.debug()
已經輸出渲染的Dom,這個
warpper
用來我們後面,用jQuery語法來測試。
4 find
測試節點
在::app.js::中增加
<img src={logo} className="App-logo" alt="logo" /> + <h1>Welcome to React</h1> <p> 複製程式碼
現在我們來正式寫單測 ::app.test.js::
describe(`測試<App />`, () => { const warpper = shallow(<App />) it('1. 包含一個p標籤', () => { expect(warpper.find('p').length).toBe(1) }) it('2. class為"App-link"的元素能正常被渲染', () => { expect(warpper.find('.App-link').exists()).toBeTruthy() }) it('3. header的class為“App-header”', () => { expect(warpper.find('header').hasClass('App-header')).toBeTruthy() }) it('4. header有3個子元素', () => { expect(warpper.find('header').children().length).toBe(4) }) it('5. 測試H1標籤的內容', () => { expect(warpper.find('h1').text()).toBe('Welcome to React') }) it('6. 測試image標籤class', () => { expect(warpper.find({ alt: 'logo' }).hasClass('App-logo')).toBeTruthy() }) }) 複製程式碼
寫過jQuery 的同學有沒有很熟悉?這裡不過多解釋。
這裡推薦一個VsCode外掛Jest 在每個單元測試前面會有一個icon標示當前是否過測。
5 使用 snapshots
測試元件
按照 find
的方法測試元件,需要寫多少單元測試,jest 為我們提供了一種快照的方式,來對比元件的變化。 安裝依賴:
npm i -D enzyme-to-json 複製程式碼
在::app.test.js::中增加測試
import Adapter from 'enzyme-adapter-react-16' + import toJson from 'enzyme-to-json' 複製程式碼
describe(`測試<App /> snapshots`, () => { const tree = shallow(<App />) it('1. 匹配快照', () => { expect(toJson(tree)).toMatchSnapshot() }) }) 複製程式碼
npm run test
在命令列中會有
› 1 snapshot written. Snapshot Summary › 1 snapshot written from 1 test suite. 複製程式碼
這時候我們看工程目錄
增加了src/__snapshots__/App.test.js.snap
這個就是jest的快照。jest原生的快照比較複雜,
enzyme-to-json
為我們做了簡化。
第一次寫toMatchSnapshot 的時候,被建立。當我們修改測試的時候它被更新。
我們來嘗試修改一下react 元件 看會有什麼事情發生
修改::app.js::
- <h1>Welcome to React</h1> + <h1>Welcome to React Jest Enzyme</h1> 複製程式碼
npm run test
在命令列中會有 錯誤資訊,告訴你哪裡發生了變化
tips: 更新快照的命令: jest --updateSnapshot
在watch 的情況下 按u 更新快照,如果你用的是vscode 那麼修改元件的時候會提醒你是否更新。
6 測試含有“props”的元件
首先增加一個 <Link>
元件 ::App.js::
export class Link extends PureComponent { render() { const { hide, address } = this.props return hide ? null : <a href={address}>Click</a> } } 複製程式碼
在::app.test.js::中增加測試
describe(`測試<Link />`, () => { it('1. 測試link元件', () => { const warpper = shallow(<Link address="https://www.google.com" />) expect(warpper.props().href).toBe('https://www.google.com') }) it('2. 測試設定Link props', () => { const warpper = shallow(<Link />) expect(warpper.find('a').length).toBe(1) warpper.setProps({ hide: true }) expect(warpper.find('a').length).toBe(0) }) }) 複製程式碼
-
warpper.props()
的結果為
{ href: 'https://www.google.com', children: 'Click' } 複製程式碼
- 在case :
2. 測試設定Link props
中用warpper.setProps()
動態的給<Link />
設定引數驗證元件是否被正常渲染
X 未完待續…
後面還有 :如何測試state ,生命週期,等等。 Jest 沒寫盡興,再整理一篇進階的文章,有小夥伴不清楚什麼是整合測試和單元測試,後面整理一篇cypress相關的文章。 秋日的北京週末,開始起霧霾,週末陪周老師備考高階教師資格證,才能坐電腦前寫這麼長時間。
2010年底來北京,一晃8年過去了。剛來北京的時候無知但無畏,到現在無味且無為。紀念一下這個心情複雜的時刻。望以後無論在什麼地方,坦然以對。
— 今天的豆瓣日記
來自豆友分享的專輯:minidisc: 空中 ベスト・オブ (豆瓣) 灰常好聽,雖然夜已深,還是元氣滿滿,開始寫第三篇。
技術能力有限,有什麼不妥之處請指正。 有什麼關於前端方面有疑惑 的方面,可以留言交流,會放到後面的寫作計劃中。