将 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. &lt;IntlProvider&gt; 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 组件中进行测试的主要内容,如果未能解决你的问题,请参考以下文章

用酶测试 react-intl 组件

为 react/react-intl 动态导入语言 json 文件

react-intl 实现 React 国际化多语言

有没有办法使用 React-Intl 访问当前的语言环境?

React-intl 多语言应用程序:更改语言和翻译存储

如何将 react-intl 2 与 redux 一起使用?