window.postMessage does not seem to work inside Promises

530 views
Skip to first unread message

Miguel Cubells Baeza

unread,
Jul 27, 2020, 11:13:44 PM7/27/20
to jsdom
Hi all.

I'm running some test with jest + jsdom, and found a problem, not sure if there is a bug or I'm missing something.

The following test snippet creates an event listener for the 'message' type, and then posts a message:

    const messageHandler = event => {
      console.log('message handler called');
    };

    window.addEventListener('message', messageHandler, false);
    window.postMessage('called', '*');

    await new Promise(resolve => setTimeout(resolve, 1000)); // wait a bit

If we run the above test, we can see in the console the message 'message handler called' as expected.

However, when creating the event listener inside a Promise, calling the corresponding postMessage does not seem to trigger the event, and the Promise cannot be resolved.

Example:

   const functionThatReturnsPromise = function() {
      return new Promise((resolve) => {
          const messageHandlerForPromise = event => {
              console.log('message handler for promise called');
              // solve the Promise if message is posted                         
              resolve({ data: 'solved' });
          }
          // adding event listener inside the Promise
          window.addEventListener('message', messageHandlerForPromise, false);
      });
    };

    window.postMessage('called', '*');
    await new Promise(resolve => setTimeout(resolve, 100)); // wait a bit
    
    const promiseToSolve = functionThatReturnsPromise();
    return promiseToSolve.then(result => {      
      expect(result.data).toBe('solved');
    });

In the above code, the Promise will never get resolved, as the postMessage does not seems to trigger the event listener.

Is this a bug, or there is something missing here ?

Thanks a lot in advance,

Full test here:

test("window.postMessage", async () => {  
    
    const messageHandler = event => {
      console.log('message handler called');
    };

    window.addEventListener('message', messageHandler, false);
    window.postMessage('called', '*');

    await new Promise(resolve => setTimeout(resolve, 1000)); // wait a bit 
    window.removeEventListener('message', messageHandler, false);

    const functionThatReturnsPromise = function() {
      return new Promise((resolve) => {
          const messageHandlerForPromise = event => {
              console.log('message handler for promise called');              
              resolve({ data: 'solved' });
          }
          window.addEventListener('message', messageHandlerForPromise, false);
      });
    };

    window.postMessage('called', '*');
    await new Promise(resolve => setTimeout(resolve, 100)); // wait a bit
    
    const promiseToSolve = functionThatReturnsPromise();
    return promiseToSolve.then(result => {      
      expect(result.data).toBe('solved');
  });
  }, 5000);

Sebastian Mayr

unread,
Jul 27, 2020, 11:20:11 PM7/27/20
to js...@googlegroups.com
Looks like you're not attaching the event handler in time to catch the message in the second example.

You'll need to call functionThatReturnsPromise before you call postMessage.

--
You received this message because you are subscribed to the Google Groups "jsdom" group.
To unsubscribe from this group and stop receiving emails from it, send an email to jsdom+un...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/jsdom/bacd41f4-9955-45ff-acc5-e3477948df81n%40googlegroups.com.

Miguel Cubells Baeza

unread,
Jul 28, 2020, 12:14:24 AM7/28/20
to jsdom
Thanks, you are right... using the right order works fine.
However this is just a dummy example... the real code that we are trying to test uses the correct approach, but still fails.

Will have to dig more...

Thanks a lot anyway !
Reply all
Reply to author
Forward
0 new messages