将react-intl对象注入已安装的酶组件中进行测试

Mir*_*age 20 reactjs enzyme react-intl

编辑:解决了!向下滚动以查找答案


在我们的组件测试中,我们需要他们可以访问react-intl上下文.问题是我们在mount()没有<IntlProvider />父包装的情况下安装单个组件(使用Enzyme ).这可以通过将提供程序包装起来然后将root点指向IntlProvider实例来解决,而不是CustomComponent.

测试与阵营-国际:酶文档仍然是空的.

<CustomComponent />

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

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

标准测试案例(所需)(酶+摩卡+柴)

// This is how we mount components normally with Enzyme
const wrapper = mount(
  <CustomComponent
    params={params}
  />
);

expect( wrapper.state('foo') ).to.equal('bar');
Run Code Online (Sandbox Code Playgroud)

但是,由于我们的组件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>
);
Run Code Online (Sandbox Code Playgroud)

这提供CustomComponentintl它要求的上下文.但是,在尝试执行以下测试断言时:

expect( wrapper.state('foo') ).to.equal('bar');
Run Code Online (Sandbox Code Playgroud)

引发以下异常:

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
Run Code Online (Sandbox Code Playgroud)

现在的问题是:我们如何才能安装CustomComponent使用intl,同时仍然能够在我们进行的"根"的操作方面CustomComponent

Mir*_*age 26

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

你可以在这里找到要点:https://gist.github.com/mirague/c05f4da0d781a9b339b501f1d5d33c37


为了保持数据的可访问性,这里的代码简而言之:

佣工/ 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 }
    });
  }
};
Run Code Online (Sandbox Code Playgroud)

CustomComponent

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

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

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
Run Code Online (Sandbox Code Playgroud)

  • 使用上面的帮助器,我在尝试导入mountWithIntl时得到`TypeError:(0,_intl.mountWithIntl)不是函数` (2认同)
  • https://gist.github.com/joncursi/01a01b230f69e698e0bea07f301f9db7 @Mirage (2认同)