EDIT:解決しました!下にスクロールして回答を探します
コンポーネントテストでは、 _react-intl
_ コンテキストにアクセスできるようにする必要があります。問題は、_<IntlProvider />
_親ラッパーなしで(Enzymeの mount()
で)単一のコンポーネントをマウントしていることです。これは、プロバイダーをラップすることで解決されますが、root
はIntlProvider
ではなくCustomComponent
インスタンスを指します。
React-Intlを使用したテスト:酵素 ドキュメントはまだ空です。
<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');
_
ただし、このコンポーネントでは_react-intl
_ライブラリの一部としてFormattedMessage
を使用しているため、上記のコードを実行するとこのエラーが発生します。
_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
_
質問は:CustomComponent
をintl
コンテキストでマウントしながら、CustomComponent
に対して「ルート」操作を実行するにはどうすればよいですか? ?
既存のEnzyme mount()
およびshallow()
関数にパッチを適用するヘルパー関数を作成しました。 React Intlコンポーネントを使用するすべてのテストで、これらのヘルパーメソッドを使用しています。
Gistはここにあります: 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 }
});
}
};
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