React Unit Test

這篇記錄學習基本 React Unit Test 的相關心得筆記

安裝

先安裝最基本的依賴套件

  • jest-transform-stub: 這個套件就只是讓不需要處理的模組忽略的轉換器
$ npm install --save-dev jest ts-jest babel-jest jest-environment-jsdom jest-transform-stub

另外如果環境沒有設定 babel 也需要安裝相關套件

$ npm install --save-dev @babel/preset-env @babel/preset-react
// babel.config.json
{
  "env": {
    "test": {
      "presets": [
        "@babel/preset-env",
        ["@babel/preset-react", {
          "runtime": "automatic"
        }]
      ]
    }
  }
}

配置

這裡要注意,有兩種情況必須處理,第一種是非 js 檔案處理,第二種是 @ 開頭的 alias 檔案處理,如果沒有在這邊設定,跑測試時會噴錯 Can not find module,另外因為 moduleNameMapper 是由上往下比對設定,非 js 檔要記得先放前面,放 alias 後面就還是會噴錯!!

// jest.config.js
module.exports = {
  // if use typescript
  // preset: 'ts-jest',
  // transform: {
  //   "^.+\\js$": "babel-jest"
  // },
  globals: {},
  testEnvironment: 'jsdom',
  moduleNameMapper: {
    // test these unresolved extension first
    ".+\\.(svg|css|styl|less|sass|scss|png|jpg|ttf|woff|woff2)$": "jest-transform-stub",
    // test for alias in the end
    "^@/(.*)$": "<rootDir>/src/$1"
  },
  moduleFileExtensions: ['js', 'json', 'jsx', 'ts', 'tsx', 'node']
}

寫測試

// MyButton.tsx
import { PropsWithChildren } from 'react'

type Props = {
  label: string
}

function MyButton({ label }: PropsWithChildren<Props>) {
  return <button data-testid="btn">{label}</button>
}

export default MyButton
// MyButton.test.js
import React from 'react'
import ReactDOM from 'react-dom/client'
import MyButton from '../MyButton'

describe('MyButton render', () => {
  it('render without error', () => {
    const div = document.createElement('div')
    const root = ReactDOM.createRoot(div)
    root.render(<MyButton />)
    root.unmount(div)
  })
})

@testing-library/react

安裝 @testing-library/react

$ npm install --save-dev @testing-library/react

改寫剛剛的測試如下

// MyButton.test.js
import React from 'react'
import { render, screen, cleanup } from '@testing-library/react'
import MyButton from '../MyButton'

describe('MyButton render', () => {
  // this is implements automatically
  // cleanup each rendered components
  afterEach(cleanup)

  it('render without error', () => {
    render(<MyButton label="Hello World" />)
    expect(screen.getByText('Hello World')).toBeTruthy()
  })

  it('render element currect', () => {
    render(<MyButton label="Hello World" />)
    expect(screen.getByTestId('btn')).toBeTruthy()
  })
})

react-test-renderer

用這個套件搭配 jest 可進行 snapshot 測試,針對整個組件渲染結果細部比對,第一次執行測試時會將結果儲存在 __snapshots__ 資料夾內,之後都會從這裡進行比對,當測試結果不吻合時就會針對改動處標註並噴錯提示

$ npm install --save-dev react-test-renderer
// MyButton.test.js
import React from 'react'
import { render, screen, cleanup } from '@testing-library/react'
import renderer from 'react-test-renderer'
import MyButton from '../MyButton'

describe('MyButton render', () => {
  // cleanup each rendered components
  afterEach(cleanup)

  it('render without error', () => {
    render(<MyButton label="Hello World" />)
    expect(screen.getByText('Hello World')).toBeTruthy()
  })

  it('render element currect', () => {
    render(<MyButton label="Hello World" />)
    expect(screen.getByTestId('btn')).toBeTruthy()
  })

  it('matches snapshot', () => {
    const tree = renderer.create(<MyButton label="Hello World" />).toJSON()
    expect(tree).toMatchSnapshot()
  })
})
Last Updated:
Contributors: johnnywang