javascriptplaywrightplaywright-test

how can I get playwright to listen to message events


I have a website that communicates through postMessage commands

 window.parent.postMessage(communication, this.origin);

When using playwright, I'm trying to do an "on message" handler

function eventListener(returnEvent: any): any {
  window.addEventListener('message', function(event: MessageEvent) {
    console.log('Im here');
    if (event.data.messageId === 'payment-method') {
      console.log('setting return event', event);
      returnEvent = event;
      return returnEvent;
    }
  });
}

...

  let returnEvent: any = {};
  await page.evaluate(eventListener, returnEvent);
  await creditCardDetailsPage.fillFormValid();
  await page.waitForTimeout(5000); //give time for message event to fire
  console.log('event was', returnEvent);
  await expect(returnEvent).toEqual(<MY DATA OBJECT HERE>)

console output

Im here
setting return event MessageEvent
event was {}

I cannot put my expects in the page.evaluate() code, because then it's executing within the context of the javascript tag that it's injecting, and not within the context of the spec.


Solution

  • I wanted to eventually get it to an expect, rather an evaluate or a waitForEvent.

    Sadly I couldn't find anything for listening to a message event. Instead we just go for console.info.

    This solution wraps the page.on('console', ...) into an async function that we can simply use as a 'resolve if success, hang if failure' switch

    // Return true if the page emits 'Hello, World!' to the console info level
    async function waitForMessageAsync(): Promise<boolean> {
      return new Promise(function (resolve) {
        page.on('console', (msg) => {
          if (msg.type() === 'log' && msg.text() === 'Hello, World!') {
            resolve(true);
          }
        });
      });
    }
    
    await expect(await waitForMessageAsync).toBeTruthy();
    

    This way, expect will fail the test if it times out waiting for our 'Hello, World!' message! 🥳