问题
React 组件代码如下:
1 | import React from 'react'; |
Sample 组件有两个方法分别是:onClickButton1() 和 onClickButton2() 。虽然这两个方法都是将 state 的 count 加1,但是 onClickButton1 是 Sample 类的原型方法,而 onClickButton2 是 Sample 实例的属性方法。
我们通过控制台可以看到:
1 | console.log(Sample.prototype); |
在 Sample 的原型对象中是没有 onClickButton2 方法的。onClickButton2 方法必须实例化 Sample。在 Sample 类中直接写箭头函数在现在其实还是 ESnext 的 Class field declarations 提案,目前是 stage 3。如果要在 jest 中测试 Sample 组件中的这两个方法又应该如何测试呢。
测试代码如下:
1 | import React from 'react'; |
如果执行测试会发现两个测试均报错:
1 | expect(jest.fn()).toHaveBeenCalled() |
也就是说 jest 并没有监测到在点击相应按钮后调用了对应的方法。
解决
按钮的点击事件确实模拟了,通过判断 Sample 组件的 state 可以看到 count 确实加了 1。
1 | it('should call onClickButton1() when click button1', () => { |
那么为什么没有监测到方法被调用了呢。通过查阅相关资料,是因为方法在调用前就被监测到了。这里对类的原型方法和属性方法的测试是有所区别的。
原型方法
类的原型方法的调用测试必须在对组件 shallow 或 mount 之前先进行 spy。
测试步骤如下:
spy原型方法shallow/mount组件- 模拟事件
- 测试
这里使用 shallow 或者 mount 都可以测试类的原型方法。
1 | it('should call onClickButton1() when click button1 with prototype', () => { |
属性方法
类的属性方法必须 mount 组件,并且在 spy 属性方法之后需要对 wrapper 的 instance() 执行 forceUpdate() 方法。
测试步骤如下:
mount组件spywrapper 的实例方法forceUpdate()wrapper 的实例- 模拟事件
- 测试
下面的代码可以通过测试。
1 | it('should call onClickButton2() when click button2', () => { |
此外也可以通过 wrapper 的实例来测试类的原型方法。
1 | it('should call onClickButton1() when click button1 with instance', () => { |
更多
如果在 Sample 组件中加入如下按钮:
1 | <button className="button3" onClick={() => this.onClickButton2()}>Button3</button> |
测试代码如下:
1 | it('should call onClickButton2() when click button3', () => { |
这段测试将会通过,虽然这里没有执行 wrapper.instance().forceUpdate() 。但是通过了测试。这是因为 onClick 处是一个箭头函数,也就是说在每次组件 render() 时都会新建一个匿名函数来执行 onClickButton2() ,所以就监测到了 onClickButton2() 的执行。
在 render() 中绑定箭头函数会造成性能问题,因为每次 render 都建立了一个新的函数,并且也会导致不必要的组件重新 render 。
在线运行
可在实例查看测试效果
参考资料: