Reputation: 67
I have a component which works absolutely fine and I'm trying to write some tests using jest and enzyme.
const handleEvent = (e: KeyboardEvent) => {
if(e.keyCode === 27)
console.log('Escape event');
}
const Component = () => {
const ref = useRef(null);
useEffect(() => {
ref.current?.addEventListener('keydown', handleEvent);
return () => {
ref.current?.removeEventListener('keydown', handleEvent);
}
}, []);
return (
<div ref={ref}> Some inner elements </div>
)
}
This is the test in which I'm trying to simulate escape event
it('simulate escape event', () => {
const component = mount(<Component />);
component.simulate('keydown', { keyCode: 27 });
// assertion of things that are handled on escape
});
This is not triggering escape event. But, when I attach the event handler to the component directly on the dom, the same test is simulating escape event and seems to be working fine.
const handleEvent = (e: KeyboardEvent) => {
if(e.keyCode === 27)
console.log('Escape event');
}
const Component = () => {
const ref = useRef(null);
return (
<div ref={ref} onKeyDown={handleEvent}> Some inner elements </div>
)
}
Can somebody please tell me why simulate isn't working when the event is attached dynamically to the component but works fine when adding it to the dom directly? I tried to search on this terms in various articles and couldn't get anything. Thanks in advance.
Upvotes: 0
Views: 1295
Reputation: 28
Enzyme simulation works like .simulate("click") actually looks for the onClick function and passes the params to it, there is no 'actual' click going on
So enzyme will not simulate the trigger on events added directly… u may have to go dispatch Event yourself.
component.getDOMNode() to get the DOM node, on which dispatchEvent should work. Something like below
it('simulate escape event', () => {
const component = mount(<Component />);
const event = new Event('keydown');
event.keyCode = 27;
component.getDOMNode().dispatchEvent(event);
// assertion of things that are handled on escape
});
Also one more problem i see is that dependency array in useEffect. Remove the Empty array dependency in useEffect to keep it safe when dom element sometimes changes in between react re-renders.
useEffect(() => {
ref.current?.addEventListener('keydown', handleEvent);
return () => {
ref.current?.removeEventListener('keydown', handleEvent);
}
});
You are attaching the eventHandler only on mount of component.
But the DOM element might change between react renders so u should actually attach eventListener in all useEffects which gets triggered after react render and DOM updates in react lifecycle.
U can also rely on callBackRefs, if u think there would be something expensive on DOM element and dont want it to run on every useEffects.
For just attaching event listeners this useEffect without dependency array should be fine.
Upvotes: 1