监视从componentDidMount调用的组件方法时,永远不会调用该间谍

pes*_*tov 0 reactjs jestjs enzyme

在React组件中,我有

export default class MyComp extends Component {
  ...
  componentDidMount() {
    this.customFunc();
  }
  customFunc = () => {
    // ..
  }
  ...
}
Run Code Online (Sandbox Code Playgroud)

当我尝试像这样用Jest和Enzyme测试这种方法时:

it('Should call customFunc on mount', () => {
  const MyCompInstance = mount(<MyComp {...props} >).instance();
  const spy = jest.spyOn(MyCompInstance, 'customFunc');

  expect(spy).toHaveBeenCalled();
});
Run Code Online (Sandbox Code Playgroud)

它失败了 Expected mock function to have been called, but it was not called.

有趣的是,如果我把console.log()componentDidMount和中custsomFunc-它们被调用。我究竟做错了什么?

PS:我forceUpdate在实例上尝试了该实例,就在期望值之前,但是仍然遇到相同的错误。

Bri*_*ams 5

它失败了 Expected mock function to have been called, but it was not called.

有趣的是,如果我把console.log()componentDidMount和中custsomFunc-它们被调用。

调用mount将呈现该组件,并componentDidMount在该过程的一部分中被调用,而该过程又调用customFunc

spy随后大干快上创建customFunc但那时已经太晚了,因为componentDidMountcustomFunc已经运行的的一部分,mount并且测试失败的spy报告,它不叫。


我究竟做错了什么?

您需要先创建spyon,customFunc 然后才能调用它。

由于这是customFunc作为实例属性实现的,因此当前编写代码的方式非常困难。

因为它是一个实例属性,它直到实例存在才存在,但是在渲染过程中创建了实例,最终调用了它componentDidMount

换句话说,您需要一个实例来监视customFunc,但是customFunc在创建该实例时会被调用。

在这种情况下,运行customFunc时检查是否被调用的唯一方法是在创建实例和呈现组件之后再次componentDidMount调用它,这有点像hack:

import * as React from 'react';
import { mount } from 'enzyme';

class MyComp extends React.Component {
  componentDidMount() {
    this.customFunc();
  }
  customFunc = () => { }  // instance property
  render() { return <div/> }
}

it('Should call customFunc on mount', () => {
  const instance  = mount(<MyComp />).instance();
  const spy = jest.spyOn(instance, 'customFunc');  // spy on customFunc using the instance
  instance.componentDidMount();  // call componentDidMount again...kind of a hack
  expect(spy).toHaveBeenCalled();  // SUCCESS
});
Run Code Online (Sandbox Code Playgroud)

另一种方法是实现customFunc类方法

如果customFunc是一个类方法,则它将存在于prototype类的上,它允许您在渲染过程中的实例创建customFunc 之前在以下位置创建间谍mount

import * as React from 'react';
import { mount } from 'enzyme';

class MyComp extends React.Component {
  componentDidMount() {
    this.customFunc();
  }
  customFunc() { }  // class method
  render() { return <div/> }
}

it('Should call customFunc on mount', () => {
  const spy = jest.spyOn(MyComp.prototype, 'customFunc');  // spy on customFunc using the prototype
  const wrapper = mount(<MyComp />);
  expect(spy).toHaveBeenCalled();  // SUCCESS
});
Run Code Online (Sandbox Code Playgroud)