Testing react-intl with jest and enzyme

Gilad lev-ari
3 min readNov 8, 2018

If you don’t know react-intl, it is an i18n library for React. It is pretty straightforward to use as part of your react project.
Yet it seems to be, that testing a component wrapped with the ‘injectIntl’ high order component, is not as straightforward.

I’ve been struggling with doing so, for a few hours by now, and I’d like to make your life easier 😛

If you don’t know one or more of the libraries, I mentioned in the title, I suggest you Google it and take the time to know them because it is essential to this post.

Let’s code:

My app is pretty simple (It is only a demo), it is structured of App.js and SubComp.js

// App.jsimport React, { Component } from 'react';
import { IntlProvider } from 'react-intl';
import SubComp from '../SubComp'
import './App.css';
const messages = {OK: 'ALL IS OK!'};class App extends Component {
render () {
return (
<IntlProvider locale=’en' messages={messages}>
<div className="App">
<h1>This is App</h1>
<SubComp />
</div>
</IntlProvider>
);
}
}
export default App;//SubComp.js
import React, { Component } from 'react';
import { injectIntl } from 'react-intl';
import SubComp1 from '../SubComp.1';
class SubComp extends Component {
render() {
return (
<div>
<h1>This is SubComp</h1>
<p>{this.props.intl.formatMessage( { id: 'OK' } )}</p>
</div>
);
}
}
export default injectIntl(SubComp);

Now for the important stuff.

TESTING!

What I’d like to test is <SubComp /> .
My test is as simple as it can get.

describe( 'SubComp', () => {
it( 'Should render', () => {
const wrapper = shallow( <SubComp /> )
expect( wrapper.find( 'p' ).length ).toBe(1)
});
});

You might won’t believe it, it FAILS.
I actually got this next error in my console:

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

So after a little Google, I found enzyme-react-intl. It gives almost the same options as enzyme, with little naming differences.

shallow will become shallowWithIntl
mount will become mountWithIntl

… and so on.

The test is still the same … and the result is still the same. it FAILS
What the F***

I’ve Googled it! It must be right. Well it is.

I found that the problem was I needed to export <SubComp /> as a named export and not only as default export.

export class SubComp extends Component { ...

And … IT WORKS! 👏

But wait! I’d like to test, not only that I have a <p>, but also that it’s content is equal to what I pass it. In other words, I’d like to see that
this.props.intl.formatMessage( { id: ‘OK’ } ) will result “ALL IS OK!”
In order to do so, I’ve replaced enzyme-react-intl with my own implementation (I found on … Google!. Just changed it a little)

import React from 'react';
import { mount, shallow } from 'enzyme';
import { IntlProvider, intlShape } from "react-intl";
// Create IntlProvider to retrieve React Intl context
export const initIntlProvider = ( locale = 'en', messages = {} ) =>
{
const intlProvider = new IntlProvider({locale,messages},{});
const { intl } = intlProvider.getChildContext();
return intl;
}
// `intl` prop is required when using injectIntl HOC
const nodeWithIntlProp = (node, intl) => (
React.cloneElement( node, { intl })
);
// shallow() with React Intl context
export const shallowWithIntl = (
node, intl, { context, ...options } = {} ) => {
return shallow(
nodeWithIntlProp( node, intl ),
{...options,
context: {...context, intl }
});
};
// mount() with React Intl context
export const mountWithIntl = (
node, intl,{ context, childContextTypes, ...options } = {}) => {
return mount(
nodeWithIntlProp( node, intl ),
{...options,
context: {...context, intl },
childContextTypes: {
intl: intlShape,
...childContextTypes
}
}
);
};

So, what i’ve changed? I have added the ‘initIntlProvider’ function and I pass the ‘intl’ object between functions. WHY? because, it enables me to pass in the locale and it’s messages. Now I can test something like

expect( wrapper.find( 'p' ).text() ).toEqual( 'This is All!' )

Well that is it. This post got out a little longer than I expected, but I hope it helped you.

--

--

Gilad lev-ari

Full stack web engineer with over a decate of experience and true passion for front end development and JavaScript 💪