React with Enzyme
Every workday I write plenty of tests using Enzyme. Even though the library is well designed, there are some tricky points, where it is easy to make a mistake and spend much precious time trying to figure out why one test does not pass… 😤
Updating state onEvent
Let’s consider a simple scenario:
- we mount a component and get a wrapper
prop.value
of thetab
has initially valuebefore
- a
click
event is simulated prop.value
should have valueafter
const tab = wrapper.find('.tab');
expect(tab.props().value).toEqual('before');
tab.find('button').simulate('click');
expect(tab.props().value).toEqual('after');
Looks good, doesn’t it? Unfortunately, this might not work 🥴
The issue is further described in the Enzyme’s official issue tracker.
TLDR: wrapper does not update its values on its own — we need to trigger the update manually. Moreover, already found-wrappers are not updated. That means, two lines of code have to be added to make the test green:
...
tab.find('button').simulate('click');
wrapper.update();
tab = wrapper.find('tab');
expect(tab.props().value).toEqual('after');
Real-life example
There are two buttons, initially the first is active. After clicking on the other one, the second button becomes active.
function findButtons(wrapper: ReactWrapper) {
const buttons = wrapper.find(buttonClass);
return { first: buttons.first(), last: buttons.last() };
}it('should select active button when clicked', () => {
const panel = mount({ buttons, activeIndex: 0 });
expect(findButtons(panel).first.find(Styles.active)).exists())
.toBeTruthy();
expect(findButtons(panel).last.find(Styles.active)).exists())
.toBeFalsy();
findButtons(panel).last.simulate(EVENT_CLICK);
panel.update(); expect(findButtons(panel).first.find(Styles.active)).exists())
.toBeFalsy();
expect(findButtons(panel).last.find(Styles.active)).exists())
.toBeTruthy();
});
Simulating different types of events
Above the click-event was described. However, there are plenty of other events, for instance:
change
blur
focus
It may happen that in our app there is a textarea
. For our use-case imagine that the length of the text, the user can write, is limited. We want to have a test that checks if our logic behaves correctly and the textarea
gets a red border when too many letters are typed.
How can we set a text in the textarea
?
wrapper.find('textarea').simulate('click');
Obviously, it won’t work — to change the text, we need change
event, not just click
🤭 So maybe:
wrapper.find('textarea').simulate('change');
Nope. We have to pass a text value to be shown 💡 An event has to be specified!
const event = { target: { value: 'comment '} };
wrapper.find('textarea').simulate('change', event);
Conclusion: simulate
accepts two parameters — an arbitrary event name and its value.
Summary
React + Enzyme = 🌩️❤️🌩️
Thanks for reading and keep in touch! 👏👏👏