
一、搭建和配置
npm install jest --save-dev
npm install enzyme --save-dev
npm install enzyme-adapter-react-16 --save-dev
// es6 es7 tytpescript 語法轉(zhuǎn)換
npm install babel-jest ts-jest --save-dev
// 為快照提供了json的組件格式
npm install enzyme-to-json --save-dev
// mock canvas
npm install jest-canvas-mock --save --dev
1.環(huán)境配置
// 在根目錄創(chuàng)建jest.config.js并添加配置項(xiàng)module.exports = { 配置項(xiàng) }
module.exports = {
preset: "react-native",
...
}
moduleFileExtensions 設(shè)置Jest要執(zhí)行測試文件的類型
moduleFileExtensions: ['ts','tsx','js','jsx']
transform設(shè)置一個(gè)入口,來告訴 Jest 要測試的資源 文件
// 如果項(xiàng)目中采用typescript為技術(shù)棧,需要設(shè)置ts-jest轉(zhuǎn)譯代碼
"^.+\\.(ts|tsx)$": "ts-jest",
// 設(shè)置babel-jest轉(zhuǎn)譯es6 es7代碼
"^.+\\.(js|jsx)$": "babel-jest",
// Jest環(huán)境不能處理css和圖片文件,需要通過工具來mock
"^.+.(css|styl|less|sass|scss|png|jpg|ttf|woff|woff2)$": "jest-transform-stub",
項(xiàng)目使用webpack配置的alias如何兼容? 配置如下:
// Resolve alias in Jest not working
moduleNameMapper
"^Controller/(.*)$": "<rootDir>/src/controller/$1",
"^Service/(.*)$": "<rootDir>/src/service/$1",
"^Store/(.*)$": "<rootDir>/src/store/$1",
"^Styles/(.*)$": "<rootDir>/src/styles/$1",
"^Router/(.*)$": "<rootDir>/src/router/$1",
"^Common/(.*)$": "<rootDir>/src/common/$1"
};
transformIgnorePatterns 配置不忽略這些es庫, 從而使babel-jest/jest-ts去處理它們
transformIgnorePatterns: [
"node_modules/(?!(react-native|react-native-button|react-router-native/)"
]
展示單元測試覆蓋率
collectCoverage: true
設(shè)置Jest配置文件
setupFiles: [
"<rootDir>/node_modules/jest-canvas-mock",
"<rootDir>/jest.setup.js"
],
項(xiàng)目在中有使用到webpack.DefinePlugin插件在打包時(shí)根據(jù)運(yùn)行環(huán)境動(dòng)態(tài)注入的一些配置項(xiàng),在單元測試如何去配置呢?
// A set of global variables that need to be available in all test environments
globals: {
__PAF_STAGE__: 16,
__ISUSEI18N__: true
__DEV__: true,
...
}
testRnviroment 測試環(huán)境,默認(rèn)值是:jsdom,可修改為node
testEnvironment: 'jsdom'
rootDir 默認(rèn)值:當(dāng)前目錄,一般是package.json所在的目錄。
rootDir: ' '
enzyme配置,在Jest.setup.js添加如下配置
import Enzyme from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
Enzyme.configure({ adapter: new Adapter() });
備注: 項(xiàng)目中常用的Jest環(huán)境配置的主要注意的配置項(xiàng)都已經(jīng)說明清楚了,配置好這些你的項(xiàng)目環(huán)境配置基本可以運(yùn)行了,接下來就可以寫測試用例了,在寫測試用例前,有必要跟大家介紹下Jest和enzyme在使用的時(shí)候注意點(diǎn)~
2、Jest Matchers
Matchers俗稱斷言庫,例如上面的expect().toBe()便是其中之一,其他常見用法如下:
1.相等斷言
toBe(value): 比較數(shù)字、字符串
toEqual(value): 比較對(duì)象、數(shù)組
toBeNull()
toBeUndefined()
2.包含斷言
toHaveProperty(keyPath, value): 是否有對(duì)應(yīng)的屬性
toContain(item): 是否包含對(duì)應(yīng)的值,括號(hào)里寫上數(shù)組、字符串
toMatch(regexpOrString): 括號(hào)里寫上正則
3.邏輯斷言
toBeTruthy()
toBeFalsy()
在JavaScript中,有六個(gè)falsy值:false,0,'',null, undefined,和NaN。其他一切都是Truthy。
toBeGreaterThan(number): 大于
toBeLessThan(number): 小于
4.not
取反,用法見下面例子
test('matchers',()=>{
const a = {
hello: 'jest',
hi :{
name: 'jest'
}
}
const b = {
hello: 'jest',
hi:{
name: 'jest'
}
}
// 以下結(jié)果均為true
expect(a).toEqual(b)
expect([1,2,3]).toEqual([1,2,3])
expect(null).toBeNull()
expect([1,2,3]).toContain(1)
expect(b).toHaveProperty('hi')
expect('123').toContain('2')
expect('123').toMatch(/^\d+$/)
expect('123').not.toContain('4')
})
使用npx jest測試執(zhí)行,結(jié)果為passed
3、enzyme支持三種方式的渲染:
淺渲染shallow
前面說過,Shallow Rendering用于將一個(gè)組件渲染成虛擬DOM對(duì)象,但是只渲染第一層,不渲染所有子組件,所以處理速度非??臁2⑶宜恍枰狣OM環(huán)境,因?yàn)楦緵]有加載進(jìn)DOM。完全渲染mount
mount渲染用于將React組件加載為真實(shí)DOM節(jié)點(diǎn)。然而,真實(shí)DOM需要一個(gè)瀏覽器環(huán)境,為了解決這個(gè)問題,我們可以用到j(luò)sdom,也就是說我們可以用jsdom模擬一個(gè)瀏覽器環(huán)境去加載真實(shí)的DOM節(jié)點(diǎn)。 首先,使用下面的命令安裝jsdom模擬瀏覽器環(huán)境,安裝命令如下:
npm install --save-dev jsdom復(fù)制代碼
- 靜態(tài)渲染render
render靜態(tài)渲染,主要用于將React組件渲染成靜態(tài)的HTML字符串,然后使用Cheerio這個(gè)庫解析這段字符串,并返回一個(gè)Cheerio的實(shí)例對(duì)象,可以用來分析組件的html結(jié)構(gòu)。
shallow是最快的,這是因?yàn)閟hallow的局限性,只渲染第一層,不渲染所有子組件。事實(shí)證明,render的效率是mount的兩倍。 那么問題來了,mount存在的價(jià)值是什么?當(dāng)然是有價(jià)值的,shallow和mount因?yàn)槎际莇om對(duì)象的緣故,所以都是可以模擬交互的。
常用函數(shù)
enzyme中有幾個(gè)比較核心的函數(shù)需要注意,如下:
- simulate(event, mock):用來模擬事件觸發(fā),event為事件名稱,mock為一個(gè)event object;
- instance():返回測試組件的實(shí)例;
- find(selector):根據(jù)選擇器查找節(jié)點(diǎn),selector可以是CSS中的選擇器,也可以是組件的構(gòu)造函數(shù),以及組件的display name等;
- at(index):返回一個(gè)渲染過的對(duì)象;
- get(index):返回一個(gè)react node,要測試它,需要重新渲染;
- contains(nodeOrNodes):當(dāng)前對(duì)象是否包含參數(shù)重點(diǎn) node,參數(shù)類型為react對(duì)象或?qū)ο髷?shù)組;
- text():返回當(dāng)前組件的文本內(nèi)容;
- html(): 返回當(dāng)前組件的HTML代碼形式;
- props():返回根組件的所有屬性;
- prop(key):返回根組件的指定屬性;
- state():返回根組件的狀態(tài);
- setState(nextState):設(shè)置根組件的狀態(tài);
- setProps(nextProps):設(shè)置根組件的屬性;
開發(fā)過程中遇到的問題:
1、TypeError: environment.setup is not a function
FAIL __test__/app.test.tsx
● Test suite failed to run
TypeError: environment.setup is not a function
at node_modules/jest-runner/build/run_test.js:112:23
解決方案:
報(bào)這種錯(cuò)誤可能有些許多原因,我的項(xiàng)目是由于我們對(duì)React-native 0.52版本 做了深度改造,造成最新的Jest 24版本不兼容,降級(jí)的Jest23版本正常運(yùn)行
總結(jié):