react—enzyme常用测试汇总

2020-01-15 loading

# 通用引入

import { mount } from 'enzyme';
import Foo from './Foo';

describe('<MyComponent />', () => {
  it('renders <Foo /> components', () => {
    const props = {
        visible:true,
        onSubmit:jest.fn()
    }
    const wrapper = mount(<MyComponent {...props}/>);
    //TODO 测试代码
    
  });
})

# 一、组件DOM是否正确编译

# 1、组件自身

//判断 Foo 渲染的个数
expect(wrapper.find(Foo).length).toBe(1);
//判断 Foo 被渲染
expect(wrapper.find(Foo).exists()).toBeTruthy();

# 2、组件内容

//判断 Foo 的文本
expect(wrapper.find(Foo).text()).toMatch('hello world');
//判断 Foo 的渲染 html
expect(wrapper.find(Foo).html()).toMatch('<div className="foo">');

// 当同一个组建中,有多个Foo时
const foos = wrapper.find(Foo)
const foo1 = foos.at(0)
const foo2 = foos.at(1)

# 3、组件类名字

//判断 dom .foo 是否有类.foo1
expect(wrapper.find('foo').hasClass('foo1')).toBeFalsy();

# 4、组件属性

//判断 wrapper 的 visible
expect(wrapper.prop('visible')).toBeTruthy()

//获取Foo 的 所有 props
const propsObj = wrapper.find(Foo).props()
//判断 Foo 的 属性 disabled
expect(propsObj['disabled']).toBeFalsy();

# 5、mock组件

示例:mock antd 组建

代码

import {message} from 'antd'

message.error('请求失败')

测试

import * as antd from 'antd'
//mock 指定方法
const messageMock = jest.spyOn(antd.message,'error')
// 测试是否正确执行
expect(messageMock).toBeCalledWith('请求失败!')

# 二、方法测试

# 1、触发方法

//获取Foo Dom
const dom = wrapper.find(Foo)
//触发 Foo 的click 方法
dom.simulate('click')

# 2、执行方法(不是通过event事件触发的方法)

//获取Foo Dom
const dom = wrapper.find(Foo)
//触发 Foo 的 属性方法 onSubmitHandle
dom.prop('onSubmitHandle')()

//针对当前整个组建,通过组建实例 instance() 执行某个函数

wrapper.instance().onSubmitHandle()

# 3、测试方法是否正确执行

// 该方法一定是mock方法,才可以判断
// 执行方法
wrapper.prop('onSubmit')('hello')
// 判断方法是否执行
expect(props.onSubmit).toBeCalled()
expect(props.onSubmit).toBeCalledWith('hello')

# 4、捕获error事件

expect(function).toThrowError()

# 三、修改props/state

备注:函数式组件,无法使用wrapper.setState()

# 1、修改props

// 修改属性 visible
wrapper.setProps({
    'visible':false
})
// 必要时执行 更新
wrapper.update()
// 判断 visible 是否
expect(wrapper.prop('visible')).toBeFalthy()

# 2、修改state

// 修改state 
wrapper.setState({
    'aaa':false
})
// 必要时执行 更新
wrapper.update()
// 判断 state.aaa 是否
expect(wrapper.state('aaa')).toBeFalthy()

# 四、异步请求

// 1、mock 请求方法
import * as Service from '../../service.ts'
const flushPromises = () => Promise.resolve()

const errorService = () => {
    const data = {
        response:{
            status:412,
            data:'error 412'
        }
    }
    return Promise.reject(data)
}

const successService = () => {
    const data = {
            status:200,
            data:[{
                a:'1'
            }]
    }
    return Promise.resolve(data)
}
//成功情况
jest.spyOn(service,'getInfoQuery').mockReturnValue(successService())
//失败情况
jest.spyOn(service,'getInfoQuery').mockReturnValue(errorService())

// 方法执行,需要 放在 it 为 async 的异步方法里
// 2、方法执行后,设置 await 等待请求返回
await flushPromises()
// 3、判断成功 or 失败时,响应的 dom、属性值、方法触发 变化情况

# 五、异步setTimeout setInterval

jest.useFakeTimers()
// 执行所有 定时任务
jest.runAllTimers()
// 执行当前第一个 定时任务
jest.runOnlyPendingTimers()
// 执行一段时间的 定时任务
jest.advanceTimersByTime(1000)

# 六、mock

# 1、mock window 属性,比如 Url、locastorage 等等~

global.window = Object.create(window);
const url = "http://dummy.com";
Object.defineProperty(window, 'location', {
  value: {
    href: url
  }
});
expect(window.location.href).toEqual(url); 

# 2、清除多个it之间,mock数据通用

连续的两个it测试,第二个it会继承使用第一个it的相同mock的数据

解决方法:

在第二个it 开始之前重置相同的mock方法

mockfn.mockReset()

# 七、enzyme配置

// tests/setup.js
import Enzyme from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';

Enzyme.configure({ adapter: new Adapter() });

jest.config.js

module.exports = {
    "setupFiles": ['<rootDir>/tests/setup'],
    "preset": "ts-jest",
    "verbose": true,
    "testRegex": "./src/.*.spec.(t|j)sx?$",

    "transform": {
        "^.+\\.(j|t)sx?$": "ts-jest",
        "^.+\\.(css|png)$": "jest-transform-stub",
    },
    "moduleNameMapper": {
        "^@/(.*)$": "<rootDir>/src/$1",
        "\\.(css|less)$": 'identity-obj-proxy',
        "\\.(jpg|png|jpeg|svg|gif|otf|webp|eot|ttf|woff|woff2|mp4)$": '<rootDir>/tests/__mock__/fileMock.js',
    },
    "testPathIgnorePatterns": ['/node_modules'],
    "moduleFileExtensions": [
        "js",
        "json",
        "ts",
        "tsx",
    ],
    // 支持源代码中相同的 `@` -> `src` 别名
    "collectCoverage": true,
    "collectCoverageFrom": [
      "./src/components/**/*.{js,tsx,ts}",
      "./src/pages/**/*.{js,tsx,ts}",
      "./src/utils/**/*.{js,ts}",
      "./src/store/reducers/**/*.{js,ts}",
    ],
    "coverageThreshold": {
        global: {
            statements: 0,
            branches: 0,
            functions: 0,
            lines: 0,
        }
    },
    "globals": {
        'ts-jest': {
            'diagnostics': false,
            'tsConfig': '<rootDir>/tsconfig.test.json'
        }
    }
}

tests/mock/fileMock.js

module.exports = 'test-file-stub'

# 备注

1、参考API:

[jest测试react](https://jestjs.io/docs/zh-Hans/tutorial-react)  

[enmyze](https://airbnb.io/enzyme/docs/api/ReactWrapper/update.html)

2、 enmyze 测试 redux

https://hackernoon.com/unit-testing-redux-connected-components-692fa3c4441c
https://www.npmjs.com/package/enzyme-redux

npm install redux-mock-store --save-dev

3、enmyze react测试错误,

3.1 如果包含--prompt,则不能使用 mount 和 wrapper.html(),回报错

3.2 如果包含connect,则把class单独导出进行测试

支付宝打赏
支付宝打赏
微信打赏
微信打赏