在安装反应组件的单位测试中处理阿波罗包裹的后代



过去几个月来我一直在与Apollojs合作(通过react-apollo),并且学习了与单位测试Apollo包裹的组件相关的许多技巧和挑战。

测试直接用Apollo包装的组件时,我导出并测试组件与graphql返回的HOC包装之前。在测试具有Apollo包裹的组件作为后代的组件时,我会尽可能使用酶的shallow渲染,以防止该后代安装。如果需要通过mount进行全面渲染,则我使用Apollo的测试UTITS中的MockedProvider,以便后代不会丢弃尝试访问this.context的错误。

我尚未找到以下情况的解决方案:需要使用Full-Dom渲染对具有Apollo包裹后代的组件进行测试,但我还需要做出涉及组件实例的断言(例如状态,实例方法,实例方法, ETC)。为了避免后裔问题,我必须将组件包裹在模拟的提供商中,但是这意味着比wrapper上的任何断言在MockedProvider实例上进行操作,而不是我想测试的组件。

一个例子:

import { mount } from 'enzyme'
import { MockedProvider } from 'react-apollo/lib/test-utils'
// This component has descendants that are wrapped in Apollo and
// thus need access to `this.context` provided by an Apollo provider
import Assignments from 'app/components/assignments
...
describe('<Assignments />', function() {
  it('sets sorted assignments in initial state', function() {
    const assignments = [...]
    const wrapper = mount(
      <MockedProvider>
        <Assignments assignments={assignments} />
      </MockedProvider>
    )
    // This will fail because the wrapper is of the MockedProvider
    // instance, not the Assignments instance
    expect(wrapper.state('assignments')).to.eql([...])
  })
})

我试图通过酶找到一种方法来访问孩子的组件实例,而不是根,据我所知,这是不支持的。我也一直在尝试在这些测试中找到需要MockedProvider的替代方案,但尚未找到任何东西。

是否有人在这种情况下找到了解决方法,或者我应该采用其他方法来处理嵌套的阿波罗包裹的组件?

我找到了解决问题的解决方案。Apollo包裹的固定组件的后代引起了问题的原因是,他们在尝试访问this.context.client时会出现错误。Apollo的MockedProvider创建一个Apollo客户端(或选择使用您提供的客户端),并通过上下文使其可用于其孩子。

事实证明,酶的mount方法允许您指定组件的上下文。我之前曾尝试过使用它,但没有意识到我还需要将其与儿童的上下文相结合,以使其传递到安装的组件的后代。使用这些酶选项避免使用MockProvider

我将根据我最初的问题中提供的示例演示解决方案:

import React from 'react'
import { mount } from 'enzyme'
// This is an Apollo client I configured in a separate module
// with a mocked network interface. I won't go into details on
// that here, but am happy to provide more details if someone asks
import mockedClient from 'test/mocked_client'
// This component has descendants that are wrapped in Apollo and
// thus need access to `this.context` provided by an Apollo provider
import Assignments from 'app/components/assignments
...
describe('<Assignments />', function() {
  it('sets sorted assignments in initial state', function() {
    const assignments = [...]
    const wrapper = mount(
      <Assignments assignments={assignments} />,
      {
        context: { client: mockedClient },
        childContextTypes: {
          client: React.PropTypes.object.isRequired
        }
      }
    )
    // This now passes!
    expect(wrapper.state('assignments')).to.eql([...])
  })
})

希望这可以帮助发现自己处于类似情况的人!

最新更新