将 react-intl 对象注入到已安装的 Enzyme 组件中进行测试
Posted
技术标签:
【中文标题】将 react-intl 对象注入到已安装的 Enzyme 组件中进行测试【英文标题】:Injecting react-intl object into mounted Enzyme components for testing 【发布时间】:2016-08-29 12:10:15 【问题描述】:编辑:已解决!向下滚动寻找答案
在我们的组件测试中,我们需要它们能够访问react-intl
上下文。问题是我们在没有<IntlProvider />
父包装器的情况下安装单个组件(使用酶的mount()
)。这可以通过将提供者包裹起来解决,但随后root
指向IntlProvider
实例而不是CustomComponent
。
Testing with React-Intl: Enzyme 文档仍然是空的。
class CustomComponent extends Component
state =
foo: 'bar'
render()
return (
<div>
<FormattedMessage id="world.hello" defaultMessage="Hello World!" />
</div>
);
标准测试用例(所需)(Enzyme + Mocha + Chai)
// 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
库的一部分,因此在运行上述代码时会出现此错误:
Uncaught Invariant Violation: [React Intl] Could not find required `intl` object. <IntlProvider> needs to exist in the component ancestry.
用IntlProvider
包装它
const wrapper = mount(
<IntlProvider locale="en">
<CustomComponent
params=params
/>
</IntlProvider>
);
这为CustomComponent
提供了它所要求的intl
上下文。但是,当尝试执行以下测试断言时:
expect( wrapper.state('foo') ).to.equal('bar');
引发以下异常:
AssertionError: expected undefined to equal ''
这当然是因为它试图读取IntlProvider
的状态,而不是我们的CustomComponent
。
尝试访问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
问题是:我们如何在intl
上下文中挂载CustomComponent
,同时仍然能够对我们的CustomComponent
执行“root”操作?
【问题讨论】:
【参考方案1】:我创建了一个辅助函数来修补现有的 Enzyme mount()
和 shallow()
函数。我们现在在使用 React Intl 组件的所有测试中都使用这些辅助方法。
您可以在这里找到要点: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
);
;
自定义组件
class CustomComponent extends Component
state =
foo: 'bar'
render()
return (
<div>
<FormattedMessage id="world.hello" defaultMessage="Hello World!" />
</div>
);
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
【讨论】:
使用上面的助手,我在尝试导入 mountWithIntl 时得到TypeError: (0 , _intl.mountWithIntl) is not a function
有趣,您确定对intl-test.js
帮助文件的引用是正确的吗?在我看来,import
失败了。也许您的require()
设置默认不查找.js
文件?您可以尝试将 .js
扩展名添加到您的导入文件中。
我尝试添加同样的错误。你的 babel 设置是什么?
知道了! gist.github.com/mirague/…
选择使用您的原始助手,以便我可以评估子组件的状态 - 这是一个很棒的功能。但是,我现在遇到了最后一个问题:安装组件后查找翻译gist.github.com/mirague/…以上是关于将 react-intl 对象注入到已安装的 Enzyme 组件中进行测试的主要内容,如果未能解决你的问题,请参考以下文章