React-Typescript 單元測試:Jest + Enzyme

YDJFE發表於2018-05-19

按道理說官配用起來會更舒服才是,結果接連碰壁,加上雷同情況的資料確實有點少,只能填一下。

0. 目前遇到的問題

首先腳手架肯定不是cracra使用者請直接用官方封裝的測試就行),我們肯定會使用自己定製的腳手架。當我們在選用Jest做單測時,出現了幾個問題:

  • typescript
  • 無法讀取 webpack
  • css-modules

第二點簡直硬傷,直接導致第三點無從下手。而鄙人又出於“不敢亂動祖傳程式碼”的原則,只能往上面繼續填。

1. 裝配 Jest

安裝

由你喜歡的方式去安裝 Jest

npm i -D jest @types/jest #or yarn
複製程式碼

接著需要配置啟動方式

// package.json
{
  ...
  "scripts": {
    "test": "jest",
    ...
  }
  ...
  "jest": {}
}
複製程式碼

還有一個方法官方並沒有提及到(或者我沒有注意到)的方法,在你的project放置一個jest.config.js,同樣可以配置,對package.json有潔癖的同學適用。

配置

-- 首先我們需要什麼?
-- TypeScript

npm i -D ts-jest #因為我們已經用上了 TypeScript 所以不需要多裝一次
複製程式碼
{
  "jest": {
    "moduleFileExtensions": [
      "ts",
      "tsx"
    ],
    "transform": {
      "^.+\\.tsx?$": "ts-jest",
    }
  }
}
複製程式碼

接著,雖然把每個元件的單測放在該元件的資料夾中顯得更清晰(cra的做法),但是我們會更願意把所有測試用例放在test資料夾中。所以建立好test目錄,繼續加配置

{
  "jest": {
    "moduleFileExtensions": [
      "ts",
      "tsx"
    ],
    "transform": {
      "^.+\\.tsx?$": "ts-jest",
    },
    "testMatch": [
      "<rootDir>/test/**/?(*.)(spec|test).ts?(x)"
    ],
  }
}
複製程式碼

這樣,在類似ydjnb.test.tsx或者ydjnb.spec.ts等等等等的檔案才會被捕獲為測試檔案進行測試。

// ydjnb.spec.ts

test('Jest-TypeScript 嘗試執行', () => {
  expect(1+1).toBe(2) // Pass
})
複製程式碼

至此,你可以使用對Typescript的測試,但對於React來說還差一點。

2. 裝配 Enzyme

這裡我們就直接選用Enzyme了,在Jest文件,關於Testing React Apps -- DOM Testing中,也提到是建議使用Enzyme

npm i -D enzyme @types/enzyme
複製程式碼

回到ydjnb.spec.ts中,現在因為涉及到JSX所以應該改名為*.tsx

// ydjnb.spec.tsx
import { shallow } from 'enzyme'

test('Jest-React-TypeScript 嘗試執行', () => {
  const renderer = shallow(<div>hello world</div>)
  expect(renderer.text()).toEqual('hello world')
})
複製程式碼

當然shallow只是一種“淺渲染”,它只會對當前元件渲染,做斷言。一般測試除了關心資料還會關心互動,所以還會有另外兩個方法render, mount

3. 問題解決

-- 配完了!執行一下吧!
-- ERROR

其實細心一點就會發現,我上面的程式碼段並沒有標記// Pass,而且現在你可能還回頭看了!

enzyme-adapter-react-16

所以第一個錯誤還是很好解決的,因為你仔細看一下測試結果,Enzyme已經告訴你了。

Enzyme Internal Error: Enzyme expects an adapter to be configured, but found none. To configure an adapter, you should call Enzyme.configure({ adapter: new Adapter() })before using any of Enzyme's top level APIs, where Adapter is the adaptercorresponding to the library currently being tested. For example:

import Adapter from 'enzyme-adapter-react-15';

To find out more about this, see http://airbnb.io/enzyme/docs/installation/index.html

不過我知道我用的已經是react-16了,跟著文件也會提到關於react-16的解決方法。

npm i -D enzyme-adapter-react-16
複製程式碼

回到ydjnb.spec.tsx中,

// ydjnb.spec.tsx
import { shallow, configure } from 'enzyme'
import Adapter from 'enzyme-adapter-react-16'

configure({ adapter: new Adapter() })

test('Jest-React-TypeScript 嘗試執行', () => {
  const renderer = shallow(<div>hello world</div>)
  expect(renderer.text()).toEqual('hello world') // Pass
})
複製程式碼

css-modules

根據Jest的文件,加上一個庫解決問題:identity-obj-proxy

{
  "moduleNameMapper": {
    "\\.(css|scss)$": "identity-obj-proxy"
  },
  "transform": {
    ...
  },
  ...
}
複製程式碼

至此,需求已經能完全運作。

相關文章