1. 程式人生 > >React+Jest+Enzyme測試

React+Jest+Enzyme測試

專案介紹:

1、antd-pro建立的專案

為什麼不直接用roadhog test?

看了原始碼roadhog test不支援–watch–coverage之外的Jest命令,我們的專案需要用到–updateSnapshot等

import test from 'umi-test';

const args = process.argv.slice(2);

const watch = args.indexOf('-w') > -1 || args.indexOf('--watch') > -1;
const coverage = args.indexOf
('--coverage') > -1; test({ watch, coverage, //不支援其他使用者配置的命令 }).catch(e => { console.log(e); process.exit(1); });

文件地址

UI測試

  1. 使用snapshot,使用jest -u更新快照
import renderer from
'react-test-renderer' // use 'jest -u' to update test('snapshot of LoginPage', () => { const rendered = renderer.create(<LoginPage store={store} />).toJSON() expect(rendered).toMatchSnapshot() })
  1. 特別重要的可以使用mount深度渲染
    儘量使用shallow前渲染,並且只測試當前元件,子元件應該在子元件的測試檔案中測試
import React from 'react'
import { mount } from 'enzyme' import configureStore from 'redux-mock-store' import renderer from 'react-test-renderer' import LoginPage from '../src/routes/User/Login' const initialProps = { login: { status: 'error', message: '', }, loading: { effects: { 'login/login': false, }, }, } const mockStore = configureStore() const store = mockStore(initialProps) describe('UI render and event', () => { let loginComponent let outLayer let usernameInput let passwordInput let submitButton let errorComponent beforeEach(() => { outLayer = mount(<LoginPage store={store} login={{ status: 'xx', message: 'errorMessage' }} />) loginComponent = outLayer.find('form') usernameInput = outLayer.find('input#userName') passwordInput = outLayer.find('input[type="password"]') submitButton = outLayer.find('button[type="submit"]') errorComponent = outLayer.find('div.ant-alert-error') }) afterEach(() => { outLayer.unmount() }) it('should render successfully', () => { expect(outLayer.length).toBe(1) expect(usernameInput.length).toBe(1) expect(passwordInput.length).toBe(1) expect(submitButton.length).toBe(1) expect(errorComponent.length).toBe(1) }) })

使用模擬store–redux-mock-store

注意這裡的store並不是真正意義上的store,實際上他不會觸發action
不推薦使用真正store,如果有必要可以使用createStorestore = createStore(initialProps)

import configureStore from 'redux-mock-store'

const initialProps = {
  login: {
    status: 'error',
    message: '',
  },
  loading: {
    effects: {
      'login/login': false,
    },
  },
}
const mockStore = configureStore()
const store = mockStore(initialProps)

describe('UI render and event', () => {
  let outLayer
  beforeEach(() => {
    outLayer = mount(<LoginPage store={store} />)
  })
  afterEach(() => {
    outLayer.unmount()
  })
})

使用simulate模擬事件

test('action triggered by submit', () => {
  usernameInput.simulate('change', { target: { value: 'bsc_storage' } })
  passwordInput.simulate('change', { target: { value: '12345' } })
  loginComponent.simulate('submit')

  const actions = store.getActions()
  expect(actions[0].type).toBe('login/login')
})

modal測試–effects

使用jest.mock()模擬API資料,使用runSage觸發action
mock檔案位置為pathTo/api.js則mock檔案位置為pathTo/__mocks__/api.js,並且__mocks__是大小寫敏感的

import { runSaga, effects } from 'redux-saga'
jest.mock('../src/services/api')
test('should effects login successful', async () => {
  const dispatched = []
  await runSaga({
    dispatch: action => dispatched.push(action),
  }, modal.effects.login, { payload: payloadRightPassword }, { call, put }).done

  const toogleMesageAction = dispatched.filter(action => action.type === 'toggleMessage')[0]
  expect(toogleMesageAction).toBeTruthy()
  const { token, status, currentUser } = toogleMesageAction.payload.data
  expect(token).toBe('mdTiCAVW7SV4cRfK3YPYRTTAhtLpYRMqBmHxznMj')
  expect(status).toBe('ok')
  expect(currentUser.name).toBe('bsc_storage')
  expect(dispatched.filter(action => action.type === 'changeLoginStatus').length).toBe(1)
})

⚠️注意:這裡的effetcs不可以當作普通的非同步方法進行測試

modal測試-reducers

reducer就是一個普通的函式所以直接測試輸出就可以

test('appendValue', () => {
  const state = {
    status: undefined,
  }
  const action = {
    payload: {
      status: 'error',
    },
  }
  const result = modal.reducers.appendValue(state, action)
  // toBe({ status: 'error' }) or Object.is() both return false
  expect(result).toEqual({ status: 'error' })
})