过去几个月来我一直在与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([...])
})
})
希望这可以帮助发现自己处于类似情况的人!