使用Enzyme和Jest 測試React元件(上)

水墨寒發表於2018-10-13

1 Enzyme 是什麼?

使用Enzyme和Jest 測試React元件(上)

Enzyme 是一類大分子生物催化劑。酶能加快化學反應的速度(即具有催化作用)
— wikipedia

Airbnb開源的 React 測試類庫 Enzyme 提供了一套簡潔強大的 API,並通過 jQuery 風格的方式進行DOM 處理,開發體驗十分友好。不僅在開源社群有超高人氣,同時也獲得了React 官方的推薦。
Airbnb.io

Jest 我們上一篇已經說過了,今天主角是Enzyme , 如字面意思,Enzyme 是酶、有催化作用。那麼在React 元件測試中和Jest 產生了什麼化學?反應呢?


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 
複製程式碼

會自動開啟瀏覽器將看到這個頁面。

使用Enzyme和Jest 測試React元件(上)
這個是create-react-app 起手式,如果不太瞭解建議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-transformeridentity-obj-proxy 是為了保證 jsx 檔案中的
import logo from './logo.svg' import './App.css' 被正常渲染出來

2.3 背景知識

  1. Enzyme 它提供三種測試方法:
    • ::shallow::
    • ::render::
    • ::mount::
  2. wrapper wrapper是enzyme包裝好的類,以供api使用
  3. 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

使用Enzyme和Jest 測試React元件(上)
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標示當前是否過測。

使用Enzyme和Jest 測試React元件(上)


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.
複製程式碼

使用Enzyme和Jest 測試React元件(上)
這時候我們看工程目錄
使用Enzyme和Jest 測試React元件(上)
增加了 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 在命令列中會有 錯誤資訊,告訴你哪裡發生了變化

使用Enzyme和Jest 測試React元件(上)

tips: 更新快照的命令:jest --updateSnapshot 在watch 的情況下 按u 更新快照,如果你用的是vscode 那麼修改元件的時候會提醒你是否更新。

使用Enzyme和Jest 測試React元件(上)

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)
  })
})
複製程式碼
  1. warpper.props()的結果為
{ href: 'https://www.google.com', children: 'Click' }
複製程式碼
  1. 在case :2. 測試設定Link props 中用warpper.setProps() 動態的給<Link />設定引數驗證元件是否被正常渲染

X 未完待續…

後面還有 :如何測試state ,生命週期,等等。 Jest 沒寫盡興,再整理一篇進階的文章,有小夥伴不清楚什麼是整合測試和單元測試,後面整理一篇cypress相關的文章。 秋日的北京週末,開始起霧霾,週末陪周老師備考高階教師資格證,才能坐電腦前寫這麼長時間。

2010年底來北京,一晃8年過去了。剛來北京的時候無知但無畏,到現在無味且無為。紀念一下這個心情複雜的時刻。望以後無論在什麼地方,坦然以對。
— 今天的豆瓣日記
來自豆友分享的專輯? 空中 ベスト・オブ (豆瓣) 灰常好聽,雖然夜已深,還是元氣滿滿,開始寫第三篇。

技術能力有限,有什麼不妥之處請指正。 有什麼關於前端方面有疑惑?的方面,可以留言交流,會放到後面的寫作計劃中。

相關文章