Hi!
I want to test application that fire custom events.
How can I catch them (".on" ?) in Cypress?
Thanks
Cypress has native access to your application, the same way your application has access to the window.
If you rephrase the question: "How can I test that custom events are firing on my DOM elements in javascript" the answer would be the same.
cy.window().then((win) => {
// listen for events bubbling up to the window
win.addEventListener(...)
Cypress.$(win).on(...)
})
or directly on your DOM elements...
cy.get('button').then(($button) => {
$button.get(0).addEventListener(...)
$button.on(...)
})
thank you very much!
hey @brian-mann, where is Cypress.$(foo).on(...) documented?
I'm searching for the guide/docs section to find out how I can "export" variables from it for the rest of my test (like a JS object from a library I accessed via the window)
I can't use wrap inside the .on callback, for example
@codeofsumit You can proxy jQuery methods using Cypress.$ as documented here: https://on.cypress.io/$
@brian-mann This approach creates an event handler that will validate that the event is correct.
I can't figure out how to check if the custom event completely fails to be triggered at all.
I think I am getting confused or stuck between Cypress' custom event queue and the native JavaScript event queue.
I finally got it working properly. It wasn't fun, I'm all ears if there's a better way to validate a custom event.
// set up (and clean up) a mock event listener
const container = {};
cy.window().then(win => {
const listener = e => {
win.removeEventListener("MyNotification", listener);
container.e = e;
};
win.addEventListener("MyNotification", listener);
});
// application (asynchronously) fires the event on click (or whatever)
cy.get("#notificationButton").click();
// this should retries until container has an event in it.
// there's quite a lot going on here -- the JavaScript event loop is firing the event
// and the Cypress event loop is polling the container until it has a value
cy.wrap(container).should(container => expect(container.e).not.to.be.undefined);
// Add one more statement to the Cypress event loop to validate the event from the JavaScript event loop
cy.wrap(container).then(container => validateEvent(container.e));
https://stackoverflow.com/questions/55582982/how-to-listen-global-events-with-cypress
return new Cypress.Promise(resolve => { // Cypress will wait for this Promise to resolve
https://medium.com/@hayavuk/perform-async-operations-sequentially-using-recursive-promises-in-javascript-c4e5ab921c37
https://docs.cypress.io/api/utilities/promise.html#Waiting-for-Promises
return new Cypress.Promise((resolve, reject) => { setTimeout(() => {
https://medium.com/@NicholasBoll/cypress-io-using-async-and-await-4034e9bab207
This library allows a Cypress chain to be converted into a real promise which is required to use
async/await.
https://github.com/cypress-io/cypress/issues/1417
(long discussion about awaiting Cypress chains)
I also tried using Cypress.Promise but the .click never got called so the event never occurred so the promise never resolved.
cy.window().then(win => {
return new Cypress.Promise(resolve => {
const listener = e => {
win.removeEventListener("MyNotification", listener);
validateEvent(e);
resolve();
};
win.addEventListener("MyNotification", listener);
cy.get("#notificationButton").click();
});
});
I also tried stubbing out or spying on window.dispatchEvent but that was really noisy.
I also tried without the container (just a raw variable, let e;) but that bound too early.
I also tried using setTimeout to poll but that was even more horrible than the above (recursive).
Is it possible to use shiny events as described here, e.g. for shiny:value event?
// use event.target to obtain the output element
$(document).on('shiny:value', function(event) {
// cancel the output of the element with id 'foo'
if (event.target.id === 'foo') {
event.preventDefault();
}
});
Most helpful comment
I finally got it working properly. It wasn't fun, I'm all ears if there's a better way to validate a custom event.
https://stackoverflow.com/questions/55582982/how-to-listen-global-events-with-cypress
https://medium.com/@hayavuk/perform-async-operations-sequentially-using-recursive-promises-in-javascript-c4e5ab921c37
https://docs.cypress.io/api/utilities/promise.html#Waiting-for-Promises
https://medium.com/@NicholasBoll/cypress-io-using-async-and-await-4034e9bab207
https://github.com/cypress-io/cypress/issues/1417
(long discussion about
awaiting Cypress chains)I also tried using
Cypress.Promisebut the.clicknever got called so the event never occurred so the promise never resolved.I also tried stubbing out or spying on
window.dispatchEventbut that was really noisy.I also tried without the container (just a raw variable,
let e;) but that bound too early.I also tried using
setTimeoutto poll but that was even more horrible than the above (recursive).