Cypress test runs in the browser in an iframe next to the application's iframe. This makes it extremely simple to spy, stub, and subscribe to the events sent to the application's window
object by other windows or by workers via window.postMessage
method calls.
Spy on the method calls
The simplest way to confirm some code calls window.postMessage
is by spying on this method using the cy.spy command. You just need the reference to the window
object and the method's name "postMessage" and let the included Sinon library do the rest. Let's say this is the application's code:
1 | <script> |
🎁 You can find the source code and the tests shown in the blog post in the repo bahmutov/cypress-post-message.
Let's spy on those calls and confirm they were made. We need to register the spy before any of the application's own code runs, otherwise we might lose calls. We can use cy.visit command's onBeforeLoad
callback to register our spy before the actual page loads.
1 | it('listens to the window.postMessage events', () => { |
The cy.get('@postMessage').should('have.been.calledTwice')
command and assertion combination retries until the application code really makes two calls.
Tip: you can find a lot of spy and stub assertions in my examples page glebbahmutov.com/cypress-examples/commands/spies-stubs-clocks.html.
You can watch the above test in action and my explanation in the video "Spy On The Window PostMessage Calls" embedded below:
Listen to the window events
What if there are several sources of window.postMessage
calls? We don't have to spy on every caller, instead we could simply subscribe to the window
events from the test itself and confirm the expected events were delivered. There is one trick we can employ: we can "strip" the actual event object and only keep track of the "event.data" property
The caller uses window.postMessage('one')
while the listener callback gets the entire event object, with data: "one"
. We want to keep track of the data
property from each event only. In our new app, the parent page includes the child iframe.
1 | <body> |
1 | <body> |
Let's subscribe to the window message
events from the spec. We will create a single stub function and we will call that function from the subscription event listener callback.
1 | it('listens to the window.parent.postMessage events', () => { |
Beautiful - the expected calls were delivered, and we only calls our stub function with the arguments like "one" and "two".
You can watch this example in action in the video "Subscribe To The Message Events From The Test" below:
For more examples like these, subscribe to my YouTube channel and check out the playlist Cypress Tips & Tricks. Tip: you can find videos by searching the descriptions from cypress.tips/search page.