Reputation: 11
I have below listener added for which I am trying to write test using Jest. However, it seems as though the event I'm dispatching doesn't reach my code.
window.addEventListener('message', (event) => {
if (event.data.type === 'abc') {
console.log(event.data.payload);
}
});
I have tried below 2 approaches and both of them don't seem to work. I'm unable to verify the call using the spy object I'm creating. Please refer to the code below:
const listenerSpy = jest.spyOn(window, 'addEventListener');
const data = {
type: 'abc',
payload: '',
};
const messageEvent = new MessageEvent('message', {data});
window.dispatchEvent(messageEvent);
expect(listenerSpy).toHaveBeenCalledTimes(1);
const listenerSpy = jest.spyOn(window, 'addEventListener');
const data = {
type: 'abc',
payload: '',
};
window.postMessage(data, '*');
expect(listenerSpy).toHaveBeenCalledTimes(1);
For the 1st approach, have also tried using 'new Event('message')'.
With above 2 approaches, I get the error as below:
expect(jest.fn()).toHaveBeenCalledTimes(expected)
Expected number of calls: 1
Received number of calls: 0
102 | window.dispatchEvent(messageEvent);
103 |
> 104 | expect(listenerSpy).toHaveBeenCalledTimes(1);
| ^
I have also tried to follow different websites including below: https://medium.com/@DavideRama/testing-global-event-listener-within-a-react-component-b9d661e59953 https://github.com/enzymejs/enzyme/issues/426
But no luck there as with typescript, I cannot follow the solution given. I have also tried to find answers on stackoverflow, but the none of solutions suggested seem to work for me.
I am new to react and got stuck with this. Any pointers on this would help.
Upvotes: 1
Views: 3144
Reputation: 102317
jsdom
fire the message
event inside a setTimeout
, see this
setTimeout(() => {
fireAnEvent("message", this, MessageEvent, { data: message });
}, 0);
For more info, see issue
So, it's asynchronous and you need to wait for the macro task scheduled by setTimeout
to be finished before the test case ends.
index.ts
:
export function main() {
window.addEventListener('message', (event) => {
if (event.data.type === 'abc') {
console.log(event.data.payload);
}
});
}
index.test.ts
:
import { main } from './';
function flushMessageQueue(ms = 10) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
describe('71912032', () => {
test('should pass', async () => {
const logSpy = jest.spyOn(console, 'log');
main();
const data = { type: 'abc', payload: 'xyz' };
window.postMessage(data, '*');
await flushMessageQueue();
expect(logSpy).toBeCalledWith('xyz');
});
});
Test result:
PASS stackoverflow/71912032/index.test.ts
71912032
✓ should pass (41 ms)
console.log
xyz
at console.<anonymous> (node_modules/jest-mock/build/index.js:845:25)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 4.01 s, estimated 13 s
Also, take a look at this question React Jest: trigger 'addEventListener' 'message' from tests
Upvotes: 1
Reputation: 23
Have you tried taking a look at this discussion? It seems to have a similar requirement. Dispatch a Custom Event and test if it was correctly triggered (React TypeScript, Jest)
Upvotes: 0