EDIT: Solved! Scroll down for the answer
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
.
The Testing with React-Intl: Enzyme docs are still empty.
<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');
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.
Wrapping it with IntlProvider
const wrapper = mount(
<IntlProvider locale="en">
<CustomComponent
params={params}
/>
</IntlProvider>
);
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');
raises the following exception:
AssertionError: expected undefined to equal ''
This ofcourse because it tries to read the state of IntlProvider
and not our CustomComponent
.
Attempts to access 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
The question is: How can we mount CustomComponent
with the intl
context while still being able to perform "root" operations on our CustomComponent
?