Often the web application uses events that flow from one part of the application to another. You might need to observe these events from the end-to-end tests to confirm the application sends them. This blog post shows how to receive the custom DOM events and jQuery events. In every case, it is important to set up the listener before the application sends the event.
Observe the DOM event sent to the document
If you prefer watching the explanation, check out the video Listen To The Application Dispatching Events To The Document. You can find the source code in the repo bahmutov/listen-to-custom-event.
Imagine the application is sending a custom DOM event to the document
object
1 | console.log('sending DOM event loading to the document') |
We can receive the same event from the Cypress test by subscribing
1 | it('sends an event to the document', () => { |
We are getting the document object using cy.document just to call its method addEventListener
. We can invoke the method right away using the .invoke command. We can also confirm the details in the event object.
1 | it('sends an event to the document', () => { |
In the tests above we still might have a race condition; we call the cy.document()... addEventListener
after the cy.visit
command. By that time, the application might have fired the event already. The safest way to listen to the event sent at the application's startup is to register them before the application loads. We cannot simply move addEventListener
before cy.visit
1 | // ⛔️ INCORRECT, WILL NOT WORK |
Every time cy.visit
runs, it creates a new document, while our stub was attached to the previous document instance. We really need to listen to the document object created by the cy.visit
command. Luckily, there is onBeforeLoad
or 'window:before:load' callbacks - they run between creating a new window
and document
objects, and the application code.
1 | // ✅ THE RIGHT WAY TO PREPARE FOR THE EVENT ON LOAD |
Observe the DOM event sent to an element
The application might send event to a specific element.
1 | const ref = React.createRef() |
We can listen to the events sent to the input
element by using jQuery on
method - because we get the jQuery object from the cy.get and the cy.contains commands.
1 | it('sends an event to the ref component', () => { |
You can watch the explanation in the video Testing DOM Events Sent to ref.current Element By React App.
Observe the jQuery events
What if the application is sending custom jQuery events? You can receive these events but you have to be careful: you must use the same jQuery instance that sends them. From the test, you must get the reference to the jQuery instance running inside the application, not the jQuery instance bundled with Cypress under Cypress.$
property.
If you prefer watching the explanation, check out the video Test The Custom jQuery Events Using Cypress. You can find the source code in the repo bahmutov/jquery-custom-events-example.
Imagine our application is including jQuery on the page
1 | <script |
The application sends custom jQuery events in the app.js
in response to the user clicks.
1 | $('.lightbulb') |
Let's confirm the application triggers events like lights:toggle
. We will get the jQuery from the application's window object, then we can get the document, wrap it in the jQuery object, and register a stub.
1 | it('triggers custom event', () => { |
Great, it works. We can simplify the test. The command cy.visit yields the window
object, thus we do not need to call cy.window
.
1 | cy.visit('index.html').then((win) => { |
We are only interested in the win.$
property, thus we can use .its command to get the window property.
1 | cy.visit('index.html') |
We can also shorten getting the document
object just to wrap it in the jQuery function.
1 | cy.visit('index.html') |
Finally, we get the $doc
object just to invoke a method on
. We can use the .invoke command to shorten it.
1 | cy.visit('index.html') |
Short and sweet.