javascript - 在 React 中测试嵌套组件回调

标签 javascript reactjs jestjs enzyme reactjs-testutils

给定一个呈现 Baz 嵌套组件的 Foo (根)组件,其中 Baz 有一个名为 onOperationDone 的属性> 接受回调。

class Foo extends React.Component {
  constructor(props) {
    super(props);

    this.onOperationDone = () => {
      console.log("do something");
    }
  }

  render() {
    return(
      <div>
        <Baz onOperationDone={this.onOperationDone} />
      </div>
    )
  }
}

需要执行哪些步骤才能使 Baz 执行回调以确保调用回调(使用 enzymetest-utils )?

您能帮我理解应该如何完成吗?

最佳答案

你的代码中有些事情对我来说有点奇怪。我假设它们在创建问题时是拼写错误,但我仍然会对它们发表评论。如果我的假设恰好是错误的,请说出来,我将相应地编辑我的答案。

首先,您的渲染方法没有返回任何内容。通常,JSX 应放置在 return 语句内。

其次,onOperationDone 方法在类的构造函数中声明。这意味着每次创建该类的新实例时,也会创建该方法(占用必要的内存量)。相反,我会在类的原型(prototype)中定义该方法,因此它在所有实例之间共享。

考虑到这一点,您的类将如下所示(请注意,我已删除构造函数,因为它只会调用 super 并且这是自动完成的):

class Foo extends React.Component {
    onOperationDone() {
        console.log("do something");
    }

    render() {
        return (
            <div>
                <Baz onOperationDone={this.onOperationDone} />
            </div>
        );
    }
} 

现在,要测试当 Baz 组件调用 onOperationDone 属性时,FooonOperationDone 方法是调用时,我会在 Foo onOperationDone 方法上设置一个 spy 来检查它是否被调用。然后,我将搜索 Baz 元素并调用其 onOperationDone

使用 enzyme ,您可以:

it('the child calls its parent callback', function() {
    jest.spyOn(Foo.prototype, 'onOperationDone');

    const wrapper = shallow(<Foo />);
    wrapper.find(Baz).prop('onOperationDone')();
    expect(Foo.prototype.onOperationDone).toHaveBeenCalledTimes(1);
});

监视类实例的方法

如果您试图监视属于您的类实例的方法(无论是通过在构造函数中定义该方法,如您的情况,还是使用 class fields ),事情会变得有点棘手.

假设您正在尝试监视初始代码中的 onOperationDone:

export default class Foo extends React.Component {
    constructor(props) {
        super(props);

        this.onOperationDone = () => {
            console.log("do something");
        };
    }

    render() {
        return (
            <div>
                <Baz onOperationDone={this.onOperationDone} />
            </div>
        );
    }
}

如果您尝试使用相同的方法来监视原型(prototype),但监视实例方法,则它将不起作用:

it('the child calls its parent callback', function() {
    const wrapper = shallow(<Foo />);
    const instance = wrapper.instance();
    jest.spyOn(instance, 'onOperationDone');

    wrapper.find(Baz).prop('onOperationDone')();
    expect(instance.onOperationDone).toHaveBeenCalledTimes(1);
});

它将失败,表明未调用监视方法(尽管您会看到日志“执行某些操作”)。

这是因为当您浅层渲染 Foo 组件时,会创建一个新的 onOperationDone 方法并将其添加到实例中,然后调用 render 方法并onOperationDone 被分配为 Baz 组件的 prop。

接下来,您将监视实例方法(使用 jest.spyOn),但它的作用是创建一个包装原始 onOperationDone 的新方法,以便跟踪它被调用的次数和其他统计数据。问题是,Baz 属性没有改变,它是对原始方法的引用,而不是包装的方法。因此包装的方法永远不会被调用。

为了克服这个问题,我们需要强制更新组件(以便将包装的 onOperationDone 指定为 Baz 组件的 prop。为此,我们有update enzyme 浅渲染器的方法。不幸的是,更新方法似乎并不总是 force a re-render

因此,解决方法是调用 setProps方法强制更新。最终的测试代码应如下所示:

it('the child calls its parent callback', function() {
    const wrapper = shallow(<ChildComponentCallbackInstance />);
    const instance = wrapper.instance();
    jest.spyOn(instance, 'onOperationDone');

    // wrapper.update(); would be the ideal method to call
    wrapper.setProps({});

    wrapper.find(Baz).prop('onOperationDone')();
    expect(instance.onOperationDone).toHaveBeenCalledTimes(1);
});

关于javascript - 在 React 中测试嵌套组件回调,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57100819/

相关文章:

javascript - 如何映射单选按钮并检索不重复的值

php - 替代弹出窗口

javascript - JavaScript如何实现对象继承?

javascript - Angular 应用程序中的 Facebook 共享

javascript - 如何加载 Bootstrap 模式只需单击 wordpress 插件子菜单?

javascript - Jest - 在一个测试套件中多次测试模块

javascript - 类型错误:this.transferPropsTo 不是一个函数

reactjs - react Redux : How to reset the flag between page navigation?

angular - Jest 测试成功,错误打印到控制台

javascript - 从另一个文件模拟一个函数 - Jest