将react-intl对象注入已安装的酶组件中以进行测试 [英] Injecting react-intl object into mounted Enzyme components for testing

查看:426
本文介绍了将react-intl对象注入已安装的酶组件中以进行测试的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

编辑:已解决!向下滚动以找到答案

Solved! Scroll down for the answer

在我们的组件测试中,我们需要它们能够访问 react-intl 上下文.问题在于我们正在安装单个组件(使用酶的 mount() ),而没有其<IntlProvider />父包装.解决方法是将提供程序包装起来,然后root指向IntlProvider实例而不是CustomComponent.

In our Component tests we need them to have access to the react-intl context. The problem is that we are mounting single components (with Enzyme's mount()) without their <IntlProvider /> parent wrapper. This is solved by wrapping the provider around but then the root points to the IntlProvider instance and not to CustomComponent.

使用React-Intl:酶进行测试文档仍然为空.

< CustomComponent/>

class CustomComponent extends Component {
  state = {
    foo: 'bar'
  }

  render() {
    return (
      <div>
        <FormattedMessage id="world.hello" defaultMessage="Hello World!" />
      </div>
    );
  }
}


标准测试用例(需要)(酶+摩卡咖啡+柴)


Standard Test Case (Desired) (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库的一部分,因此在运行上述代码时会出现此错误:

However, since our component uses FormattedMessage as part of the react-intl library, we get this error when running the above code:

Uncaught Invariant Violation: [React Intl] Could not find required `intl` object. <IntlProvider> needs to exist in the component ancestry.

IntlProvider

Wrapping it with IntlProvider

const wrapper = mount(
  <IntlProvider locale="en">
    <CustomComponent
      params={params}
    />
  </IntlProvider>
);

这为CustomComponent提供了所需的intl上下文.但是,当尝试进行以下测试断言时:

This provides CustomComponent with the intl context it asks for. However, when trying to do test assertions such as these:

expect( wrapper.state('foo') ).to.equal('bar');

引发以下异常:

AssertionError: expected undefined to equal ''

这当然是因为它尝试读取IntlProvider而不是我们的CustomComponent的状态.

This ofcourse because it tries to read the state of IntlProvider and not our CustomComponent.

我尝试以下操作均无济于事:

I have tried the below to no avail:

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"操作?


The question is: How can we mount CustomComponent with the intl context while still being able to perform "root" operations on our CustomComponent?

推荐答案

我创建了一个辅助函数来修补现有的Enzyme mount()shallow()函数.现在,我们在所有使用React Intl组件的测试中都使用了这些辅助方法.

I have created a helper functions to patch the existing Enzyme mount() and shallow() function. We are now using these helper methods in all our tests where we use React Intl components.

您可以在此处找到要点: https://gist.github.com/mirague/c05f4da0d781a9b339b501f1d5d33c37

You can find the gist here: https://gist.github.com/mirague/c05f4da0d781a9b339b501f1d5d33c37

为了保持数据的可访问性,以下是简而言之的代码:

For the sake of keeping data accessible, here's the code in a nutshell:

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 }
    });
  }
};

CustomComponent

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

这篇关于将react-intl对象注入已安装的酶组件中以进行测试的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆