问题
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
组件spy
wrapper 的实例方法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
。
在线运行
可在实例查看测试效果
参考资料: