如何用酶测试子组件方法?

Posted

技术标签:

【中文标题】如何用酶测试子组件方法?【英文标题】:How to test child component method with Enzyme? 【发布时间】:2017-07-03 20:50:04 【问题描述】:

我有一个这样的组件:

<Parent>
  <Child/>
</Parent>

&lt;Child/&gt; 组件有一个方法foo。我想测试foo 方法,但我不知道如何访问它。我试过了:

mount(<Parent><Child/></Parent>).props().children.foo

mount(<Parent><Child/></Parent>).children().foo

但他们都是undefined。我不能使用.instance(),因为它不是root。我无法挂载&lt;Child/&gt;,只是因为&lt;Parent&gt;context 上添加了一些东西(react-router 的context.router),并且在初始化&lt;Child/&gt; 时我需要它们。有什么想法吗?

【问题讨论】:

这似乎仍然不可能或至少很复杂:github.com/airbnb/enzyme/issues/361 在向上工作之前测试树中较低的反应组件。还要导出组件的解包版本以进行测试,以消除组件对反应路由器的依赖。 +1 关于编写反应规范最烦人的事情,我不明白你如何为反应编写规范框架并且没有一种简单的方法来访问子组件的实例。哑巴。 【参考方案1】:

这对我有用:

mount(<Parent><Child/></Parent>).find(Child).instance().foo

【讨论】:

实例只能在root上调用。 如何导入Child组件【参考方案2】:

我会考虑只为你的父类编写测试,然后单独的测试文件只测试你的孩子。

一旦你安装了你的组件,使用:

const component = mount(<Child>); 

然后您可以使用以下方法访问它的方法:

component.instance().methodname

然后您可以使用 jest.fn() 覆盖它并进行适当的测试。

【讨论】:

这在 React 16.x 中已经不可能了【参考方案3】:

我更喜欢酶的浅安装而不是全安装。

结合 proxyquire 来解析子组件(你要测试的) 我愿意

wrapper.find('Child1').props().propName

然后测试一下。

或者我用浅的

mount wrapper.dive()

【讨论】:

【参考方案4】:

我认为您的问题与如何测试子组件完全不同。

我的第一个问题是:为什么要检查子组件在父组件测试中是否有特定方法?

恕我直言,您需要对此组件进行特定测试,然后在此测试中检查该方法是否存在。

只是为了不离开没有答案,你试过.find(Child).instance().foo吗?

【讨论】:

.instance() 只能在“root”上调用【参考方案5】:

我在尝试在 MemoryRouter 的内部组件上模拟函数时遇到了类似的问题:

cont wrapper = mount(<MemoryRouter><AvailabilityButtonWithRouter.WrappedComponent vetId= vetId   appointment= availability  /></MemoryRouter>);     

我最终能够像这样模拟函数:

const mockFn = jest.fn();    
wrapper.children(0).children(0).instance().reloadCurrentPage = mockFn;

【讨论】:

很好,它帮助我在 3 级嵌套 Item 子组件中找到了一个多次渲染的函数。不需要0 参数,如.children(0),而只需children()。当准备好找到它时,只需 .first().getElement() 和道具。我的例子:wrapper.find('Item').children().first().getElement()【参考方案6】:

我能够获得如下子函数的句柄,我正在寻找第一个调用该函数的子函数 -

const component = shallow(<Component />);
component.find(Child).first().getNode().props.someChildFunction()

【讨论】:

【参考方案7】:

我遇到了类似的问题,我通过日志记录了mount API。在我的用例中,我的子组件(CommonStoresReactions)用 mobx inject 包装。

const jsx = (
    <Provider ...stores>
      <CommonStoresReactions>
        <div />
      </CommonStoresReactions>
    </Provider>
)
const wrapper = mount(jsx)

我想在CommonStoresReactions 中测试clearStores 方法。下面的 sn-p 对我有用。

wrapper
      .find(CommonStoresReactions)
      .instance()
      .wrappedInstance.clearStores()

【讨论】:

.instance() 只能在“root”上调用【参考方案8】:

Enzyme 有一个名为 wrappingComponent(和 wrappingComponentProps)的 mount API 选项,可以将已安装的对象包装在另一个组件中以提供上下文等。

见https://github.com/airbnb/enzyme/blob/master/docs/api/mount.md#mountnode-options--reactwrapper

【讨论】:

【参考方案9】:

我设法通过使用dive解决了这个问题

wrapper.dive().props().propName

【讨论】:

【参考方案10】:

含酶:

mount(<Parent><Child/></Parent>).childAt(0).instance().foo

有正当理由可以访问孩子并调用方法。如果父级是肤浅的并且子级具有一致的接口,您可以在不知道它是哪个子级的情况下调用方法,测试所有子级是否具有正确的接口、签名等。

【讨论】:

【参考方案11】:

我发现最好的方法是使用浅包装器的dive 方法。这是文档:enzyme dive doc

记住如果你的父组件使用像mount这样的完全渲染,那么react wrapper本身没有dive方法所以你必须使用浅渲染。

这是一个例子:

let instance, child, diveChild;
describe('Test Parent child Child component', () => 
  beforeEach(() => 
    wrapper = shallow(<Parent ...props />);
    child = wrapper.find('Child');
    diveChild = child.dive();
    console.log(diveChild.instance());
  );

  test('Child get mounted', () => 
    expect(child.exists()).toBeTruthy();
    expect(child.debug()).toMatchSnapshot();
  );
);

【讨论】:

以上是关于如何用酶测试子组件方法?的主要内容,如果未能解决你的问题,请参考以下文章

如何用酶在ReactJS中添加窗口keydown事件的单元测试

玩笑,用酶测试同一子组件的多次出现

使用酶在反应测试中查找渲染子组件的数量?

使用酶和主题测试样式化组件

使用酶获取连接到 redux 的子组件的状态

使用酶进行测试时如何找到包裹在 MockedProvider 中的 Typography 组件