编辑: 解决了!向下滚动以获取答案
在我们的组件测试中,我们需要它们能够访问react-intl上下文。问题在于,我们正在安装单个组件(带有Enzyme的组件mount())而没有它们的<IntlProvider />父包装。可以通过以下方式解决此问题:将提供程序包装在一起,然后root将IntlProvider实例指向实例,而不要指向CustomComponent。
react-intl
mount()
<IntlProvider />
root
IntlProvider
CustomComponent
该测试与阵营-国际:enzyme文档仍然是空的。
< CustomComponent />
class CustomComponent extends Component { state = { foo: 'bar' } render() { return ( <div> <FormattedMessage id="world.hello" defaultMessage="Hello World!" /> </div> ); } }
标准测试用例(所需) (酶+摩卡咖啡+柴)
// This is how we mount components normally with Enzyme const wrapper = mount( <CustomComponent params={params} /> ); expect( wrapper.state('foo') ).to.equal('bar');
但是,由于我们的组件FormattedMessage用作react-intl库的一部分,因此在运行上述代码时会出现此错误:
FormattedMessage
Uncaught Invariant Violation: [React Intl] Could not find requiredintlobject. <IntlProvider> needs to exist in the component ancestry.
Uncaught Invariant Violation: [React Intl] Could not find required
object. <IntlProvider> needs to exist in the component ancestry.
用它包裹IntlProvider
const wrapper = mount( <IntlProvider locale="en"> <CustomComponent params={params} /> </IntlProvider> );
这提供CustomComponent了intl它要求的上下文。但是,在尝试测试诸如此类的断言时:
intl
expect( wrapper.state('foo') ).to.equal('bar');
引发以下异常:
AssertionError: expected undefined to equal ''
这当然是因为它试图读取IntlProvider而不是我们的状态CustomComponent。
我尝试了以下无济于事:
const wrapper = mount( <IntlProvider locale="en"> <CustomComponent params={params} /> </IntlProvider> ); // Below cases have all individually been tried to call `.state('foo')` on: // expect( component.state('foo') ).to.equal('bar'); const component = wrapper.childAt(0); > Error: ReactWrapper::state() can only be called on the root const component = wrapper.children(); > Error: ReactWrapper::state() can only be called on the root const component = wrapper.children(); component.root = component; > TypeError: Cannot read property 'getInstance' of null
现在的问题是: 我们如何才能安装CustomComponent使用intl方面,同时仍然能够执行我们的“根”的操作CustomComponent?
我创建了一个辅助功能来修补现有的酶mount()和shallow()功能。现在,我们在所有使用React Intl组件的测试中都使用这些辅助方法。
shallow()
您可以在这里找到要点:https://gist.github.com/mirague/c05f4da0d781a9b339b501f1d5d33c37
为了保持数据的可访问性,以下是简而言之的代码:
helpers / intl-test.js
/** * Components using the react-intl module require access to the intl context. * This is not available when mounting single components in Enzyme. * These helper functions aim to address that and wrap a valid, * English-locale intl context around them. */ import React from 'react'; import { IntlProvider, intlShape } from 'react-intl'; import { mount, shallow } from 'enzyme'; const messages = require('../locales/en'); // en.json const intlProvider = new IntlProvider({ locale: 'en', messages }, {}); const { intl } = intlProvider.getChildContext(); /** * When using React-Intl `injectIntl` on components, props.intl is required. */ function nodeWithIntlProp(node) { return React.cloneElement(node, { intl }); } export default { shallowWithIntl(node) { return shallow(nodeWithIntlProp(node), { context: { intl } }); }, mountWithIntl(node) { return mount(nodeWithIntlProp(node), { context: { intl }, childContextTypes: { intl: intlShape } }); } };
CustomComponentTest.js
import { mountWithIntl } from 'helpers/intl-test'; const wrapper = mountWithIntl( <CustomComponent /> ); expect(wrapper.state('foo')).to.equal('bar'); // OK expect(wrapper.text()).to.equal('Hello World!'); // OK