Testing ES6 React components with Enzyme's shallow rendering
I ran into a strange issue today when writing some assertions using the Enzyme testing library for React.
Whenever I create a new component, I like to use ES6 class notation and export the class anonymously like this:
// MyChildComponent.js
import React from 'react';
export default class extends React.Component {
render() {
return (<div>MyChildComponent</div>)
}
}
Then, I'll render it in another component like this:
// MyParentComponent.js
import React from 'react';
import MyChildComponent from './MyChildComponent';
export default class extends React.Component {
render() {
return (
<div>
<MyChildComponent />
</div>
)
}
}
When testing for the presence of MyChildComponent
within MyParentComponent
in Enzyme, I'll typically produce a test that looks like this:
import { shallow } from 'enzyme';
import { expect } from 'chai';
import MyParentComponent from './MyParentComponent';
describe("<MyParentComponent />", () => {
const wrapper = shallow(<MyParentComponent />);
it("renders a MyChildComponent", () => {
expect(wrapper.find('MyChildComponent')).to.have.length(1);
});
});
But this fails! It's as if MyChildComponent
isn't being rendered at all.
If I dump wrapper.debug()
(doc)
to the console, I get this output in place of MyChildComponent
:
<div>
<_class />
</div>
It's as if Enzyme doesn't know the component is called MyChildComponent
!
Solutions
There are two ways to solve this.
Import the component itself and assert on it instead
Below, we import MyChildComponent
and then, in the assertion, use the class
constant instead of the string literal "MyChildComponent"
:
import { shallow } from 'enzyme';
import { expect } from 'chai';
import MyParentComponent from './MyParentComponent';
import MyChildComponent from './MyChildComponent';
describe("<MyParentComponent />", () => {
const wrapper = shallow(<MyParentComponent />);
it("renders a MyChildComponent", () => {
expect(wrapper.find(MyChildComponent)).to.have.length(1);
});
});
Export the named class from within the child component
As much as we should strive to write code that doesn't repeat itself, this was
the solution I ultimately chose. It turns out React is able to determine the
class name so long as you define it in the class
statement. Modifying
MyChildComponent.js
to produce a named class and then exporting it allows Enzyme
to find it in the string literal assertion:
// MyChildComponent.js
import React from 'react';
class MyChildComponent extends React.Component {
render() {
return (<div>MyChildComponent</div>)
}
}
export default MyChildComponent;
If you can't seem to get an Enzyme assertion to find a component you know is there, make sure Enzyme knows what sort of component it is!