在反应中测试嵌套组件回调
Posted
技术标签:
【中文标题】在反应中测试嵌套组件回调【英文标题】:testing nested component callback in react 【发布时间】:2019-11-27 18:16:25 【问题描述】:给定一个呈现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
执行回调以确保回调被调用(使用enzyme 或test-utils)?
你能帮我理解应该怎么做吗?
【问题讨论】:
【参考方案1】:在您的代码中,我觉得有些事情有点奇怪。我假设他们在创建问题时是拼写错误,但我仍然会对它们发表评论。如果我假设的内容恰好是错误的,请说出来,我会相应地编辑我的答案。
首先,您的渲染方法没有返回任何内容。通常,JSX 应该放在 return 语句中。
其次,onOperationDone
方法在类的构造函数中声明。这意味着每次创建类的新实例时,也会创建该方法(占用必要的内存量)。相反,我会在类的原型中定义方法,以便在所有实例之间共享。
考虑到这一点,您的类看起来像(请注意,我已删除构造函数,因为它只会调用 super
并且是自动完成的):
class Foo extends React.Component
onOperationDone()
console.log("do something");
render()
return (
<div>
<Baz onOperationDone=this.onOperationDone />
</div>
);
现在,为了测试Baz
组件调用onOperationDone
属性时调用Foo
的onOperationDone
方法,我将在Foo
onOperationDone
方法上设置一个间谍来检查它叫做。然后,我会搜索Baz
元素并调用它的onOperationDone
。
有了酵素,你可以做到:
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);
);
它将失败,说明未调用 spied 方法(尽管您会看到日志“做某事”)。
这是因为当你对Foo
组件进行浅渲染时,会创建一个新的onOperationDone
方法并将其添加到实例中,然后调用render方法并将onOperationDone
作为prop分配给Baz
组件。
接下来,您正在监视实例方法(使用jest.spyOn
),但这会创建一个新方法来包装您的原始onOperationDone
,以便跟踪它被调用的次数和其他统计信息.问题是,Baz
道具没有改变,它是对原始方法的引用,而不是包装的方法。所以包装的方法永远不会被调用。
为了克服这个问题,我们需要强制更新组件(以便包装的 onOperationDone
被分配为 Baz
组件的道具。为此,我们有酶的浅渲染器的 update 方法。不幸的是,好像更新方法不总是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);
);
【讨论】:
感谢您的详细解释! 我已更改我的 sn-p 以包含return
语句(当我删除代码时它被遗漏了)。您能否详细说明当onOperationDone
在构造函数中定义时(如在我的sn-p 中),如何做同样的事情? onOperationDone
修改状态,当onOperationDone
传递给Baz
时,我想避免使用bind()
)
@Mr.,我更新了答案以考虑您要测试的情况。希望对您有所帮助!
对不起,你能提供功能组件的例子吗?请以上是关于在反应中测试嵌套组件回调的主要内容,如果未能解决你的问题,请参考以下文章