So, I encountered a pretty silly mistake recently that was causing my unit tests to keep failing. I had to modify a component which contains a user's ID as its prop. The application's state is managed by React-Redux.
The user's ID is passed down to a <ChildComponent />
together with other prop values.
class ParentComponent extends Component {
// SuperAgent to retrieve the user's ID and manage the state via Redux
}
...
render() {
return (
<ChildComponent
userID={userID}
val={props.val}
/>
)
}
Due to this small change, my previous tests kept failing.
You might think that a simple setProps() method on <ParentComponent />
would resolve the issue.
// Mocking function for userID
const store = configureStore()({
user: {
id: 'userId'
}
});
component = mount(
<Provider store={store}>
<ParentComponent {...props} />
<Provider />
);
let ChildComponent = component.find('ChildComponent');
component.setProps({userID: 'foo', val: 'bar'});
expect(ChildComponent.prop('val').toBe('bar'));
Unfortunately, it was a spectacular failure.
$ Comparing two different types of values. Expected string but received undefined.
Apparently the <ChildComponent />
was returning undefined for its 'val' props.
What's The Difference between Shallow and Full DOM Rendering?
Shallow rendering (shallow()) is used to test a component in isolation. Full DOM rendering (mount()) on the other hand, allows testing of the component lifecycle and child component behaviors.
• Shallow Rendering
• Full DOM Rendering
I just need to call setProps() on <ChildComponent />
instead of on <ParentComponent />
right?
let ChildComponent = component.find('ChildComponent');
ChildComponent.setProps({userID: 'foo', val: 'bar'});
expect(ChildComponent.prop('bal').toBe('bar'));
$ReactWrapper::setProps() can only be called on the root
Turns out, Enzyme has an undocumented feature, "children:", which when used on setProps(), allows us to set the props on child components.
However, in the above scenario, the root component was <Provider />
instead of <ParentComponent />
. Due to this misapplication, I was calling setProps() on <Provider />
instead of <ParentComponent />
.
By adding the children syntax on setProps(), the props are properly passed down from <ParentComponent />
to <ChildComponent />
.
component.setProps({children: <ParentComponent {userID: 'foo', val: 'bar'}});
PASS src/components/header/ParentComponent.test.js
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 1.193s