Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

使用jest+enzyme测试react组件 #244

Open
zWingz opened this issue Mar 7, 2019 · 0 comments
Open

使用jest+enzyme测试react组件 #244

zWingz opened this issue Mar 7, 2019 · 0 comments
Labels
react react、react-router、react-redux、webpack、mobx

Comments

@zWingz
Copy link

zWingz commented Mar 7, 2019

前言

最近第一次给一个项目写一个完整的测试流程, 也算是我第一次写完整的测试.
于是记一下整个测试流程
项目地址
目前项目使用的测试框架是主流的jest+enzyme

依赖

必要依赖

  • Jest
  • enzyme
  • enzyme-adapter-react-16

按需

  • 如果使用babel,则需要babel-jest
  • 如果使用typescript, 则需要ts-jest

Jest 配置

起初项目使用babel进行编译,后面统一转成了ts

{
  "jest": {
    "moduleNameMapper": {
      "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|scss)$": "<rootDir>/test/utils.ts"
    },
    "moduleFileExtensions": ["ts", "tsx", "js"],
    "setupTestFrameworkScriptFile": "<rootDir>/test/setup.ts",
    "collectCoverageFrom": ["src/**/*.{ts,tsx}"],
    "coverageDirectory": "./coverage/",
    "collectCoverage": true,
    "transform": {
      "^.+\\.(ts|tsx)$": "ts-jest"
    },
    "testMatch": ["**/__test__/*.(ts|tsx)"]
  }
}

如果使用babel的话, 只要将ts转成js, ts-jest转成babel-jest即可。

moduleNameMapper

用来mock一些额外module, 比如sass, jpg等等.

// /test/utils.ts
module.exports = 'test-file-stub'

setupTestFrameworkScriptFile

The path to a module that runs some code to configure or set up the testing framework before each test.

可以用来初始化test配置, 在这里需要使用enzyme-adapter

// /test/setup.ts
import { configure } from 'enzyme'
import * as ReactSixteenAdapter from 'enzyme-adapter-react-16'

configure({ adapter: new ReactSixteenAdapter() })

collectCoverageFrom

需要测试覆盖率的文件

coverageDirectory

覆盖率输出目录

transform

A map from regular expressions to paths to transformers. A transformer is a module that provides a synchronous function for transforming source files

webpack-loader类似

testMatch

The glob patterns Jest uses to detect test files.

测试文件匹配规则, 如果跟官方不同, 则修改此值.

Enzyme 使用

官方文档

简单介绍

其实enzyme上手挺简单的, 它有三个API

包括shallowmountrender, 其中shallowmount是常用的

他们区别是

  • shallow: 只会渲染顶级组件, 而子组件不会渲染, 渲染结果是一颗react树, 效率最高
  • mount: 会渲染整个组件, 包括子组件, 如果需要深入组件内部测试, 则需要使用mount
  • render: 直接选择普通的html结构.

shallowmount得到结果是一个ReactWrapper对象, 可以进行多种操作, 包括find()prop()instance()等。

基本使用

import * as React from 'react'
import { shallow, mount } from 'enzyme'
import MyComponent from '../MyComponent'
import ChildComponent from '../ChildComponent'

describt('测试xxxxx', () => {
    it('组件state以及渲染情况', () => {
        const wrapper = shallow(<MyComponent />)
        expect(wrapper.state().msg).toEqual('test msg')
        expect(wrapper.find('#childId')).toHaveLength(1) // 测试是否包含某个`element`
        expect(wrapper.find(ChildComponent)).toHaveLength(1) // 测试是否包含某个子组件
    })
    it('触发事件', () => {
	    const click = jest.fn()
        const wrapper = shallow(<MyComponent onClick={click}/>)
        // 触发#triggerClickElement的click事件
		wrapper.find('#triggerClickElement').simulate('click')
		// 判断click事件是否被触发
		expect(click).toBeCalledTimes(1)
    })
    // 测试函数调用
    // 默认该函数声明方式通过class.method声明
    // class MyComponent{
    //   someMethod() {} 
    // }
    it('测试函数调用', () => {
        const spy = jest.spyOn(MyComponent.prototype, 'someMethod')
        const wrapper = shallow(<MyComponent />)
        // 暂且认为组件挂载时会调用`someMethod`
        // 在此测试是否正确调用
        expect(spy).toBeCalledTimes(1)
    })
    // 但是由于react需要绑定this
    // 所以一般会这样声明
    // class MyComponent {
    //   someMethod = () => {}    
    // }
    // 这时候通过babel或者typescript编译后
    // 会变成类似
    // class MyComponent{
    //   constructor() {
    //     this.someMethod = () => {}     
    //   }    
    // }
    // 这时候someMethod不属于MyComponent.prototype
    // 所以要改变测试方式
    it('测试函数调用', () => {
        const wrapper = shallow(<MyComponent />)
        const ins = wrapper.instance()
        const spy = jest.spyOn(ins, 'someMethod')
        wrapper.update()
  		ins.forceUpdate()
        expect(spy).toBeCalledTimes(1)
    })
    it('触发特定事件, 并传递参数', () => {
    	// 如果要触发特定事件, 比如mousemove, keyup等等
    	// 可以通过构造自定义事件, 并且使用dispatchEvent来触发
        const wrapper = shallow(<MyComponent />)
        const element = wrapper.find('.some-element')
        const event = new MouseEvent('mousemove', {
            clientX: 100,
            clientY: 100
        })
        element.getDOMNode().dispatchEvent(event)
        expect(wrapper.state.x).toEqueal(100)
    })
})

其实enzyme常用的api大概就是几个, 按照本项目中用到的,

  • state
  • find
  • prop
  • simulate

进行测试

编写完test case后, 只要调用jest即可进行测试, 同时会输出覆盖率
如果带上--watch则可以监听文件改动并进行测试

上传测试覆盖率

目前使用Codecov来管理测试覆盖率
如果在本地上传, 则需要带上token, 如果通过travisCi, 则不需要, 直接调用codecov即可。

完结

至此, 整套jest+enzyme测试流程已经跑完.
目前看来没有用高更深的测试功能, 比如说jsdom, enzyme.render

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
react react、react-router、react-redux、webpack、mobx
Projects
None yet
Development

No branches or pull requests

2 participants