A user has recently asked me about using Cypress tests not delivering events into the application. The application is using pubsub-js from the "Publisher" component to publish events. Other components, like the "Subscriber" component can subscribe to PubSub events and then updates the page UI.
1 | <button type="button" @click.prevent="notifyNavbar" data-cy="publisherbutton"> |
1 | <span data-cy="notficationcounter">{{ notificationCount }}</span> |
The first test works correctly confirming the application is working
1 | it('click the button', function() { |
Tip: move the http://localhost:8080/
URL into the cypress.json
file. This will avoid the test reload, watch the video How to correctly use the baseUrl to visit a site in Cypress.
📺 If you would rather watch the explanation from this blog post, watch my video How To Use PubSub From Cypress Test To Publish Events To Application.
The broken test
The user has written the second test, trying to publish the tests from the test and then check if the "Subscriber" component is updated.
1 | import PubSub from "pubsub-js"; |
Unfortunately the test fails.
The application does not see the updated count - it never receives the "notification-update" event. The reason is that Cypress test file is placed in a separate iframe from the application.
Each iframe has its own JavaScript environment, its own window
object, its own ... PubSub instance. It is as if two applications were loaded:
1 | <iframe> |
While the code looks similar, the two PubSub instances are completely separate. The events published in one iframe are invisible and never mix with the events published in the second one. Our test file published the event - but on its own PubSub.
The solution
We need to access the application's PubSub instance from the spec file. The simplest way is for the application to share it by adding it as a property to the window
object.
1 | import PubSub from "pubsub-js"; |
From the spec file we can access the application's window
object using the cy.window command, and then wait for the property PubSub
to exist, see The window.property
recipe.
1 | it('publish the event', function () { |
Now the test works correctly.
We can simplify the above test a little. We need the window
instance after the cy.visit command. The cy.visit
command yields the application's window
object, thus we can directly chain the visit
and the its
commands.
1 | it('publish the event', function () { |
We can simplify the above test even more. We are getting the PubSub
object and then immediate invoke its method publish
. We can use the Cypress command .invoke
for this.
1 | it('publish the event', function () { |
The nice thing about Cypress .invoke
command: if the method returns a Promise, the command will wait for the promise to resolve before continuing with the next Cypress command.