Reputation: 33
I'm having issues with a scroll that resizes a few milliseconds after the rest of the DOM is rendered, this causes the scroll to almost hit the bottom missing it by a few pixels, as a result the button i need to click remains disabled. So i'm looking for the best and more consistent way to wait for that condition without adding an explicit wait.
I've tried waiting for all the available XHR calls that happen after the login, this works most of the times but not a 100% (on electron which is what our CI uses), i've also tried getting other elements before scrolling, like checking the button is disabled but that time seems not to be enough for the scroll to completely resize.
Here is my actual code example:
Cypress.Commands.add('waitForRequestAndVisit', (path, url) => {
cy.server();
cy.route('GET', path).as('request');
cy.visit(url);
cy.wait('@request');
}),
This is the spec file:
cy.waitForRequestAndVisit('**/api/v1/auth/validate_token', '/');
const termsAndConditionsScroll = '[data-testid=terms-and
conditions]';
cy.get(termsAndConditionsScroll).scrollTo('bottom');
cy.getSubmitButton()
.should('not.be.disabled')
.click();
Upvotes: 2
Views: 1190
Reputation: 19718
I wrote my own cypress command to be able to wait some arbitrary javascript processing to be ready before continuing.
/**
* Waits until call to cb() resolves to something truthy.
*
* @param message {string} Error message on timeout
* @param cb {() => Cypress Command "promise"}
* Callback for checking if condition is met should return
* cy.xxxxxx.then() and resolve to undefined if polling should continue.
*/
Cypress.Commands.add('waitFor', (message, cb, timeoutMs = 2000) => {
const startTime = new Date().getTime();
const giveupTime = startTime + timeoutMs;
const startTimeout = 5;
function checkCb(timeout) {
const currentTime = new Date().getTime();
if (currentTime > giveupTime) {
throw new Error(`Timeout while waiting for (${currentTime - startTime}ms): ${message}`);
} else {
cy.wait(timeout);
return cb().then(result => {
if (result === undefined) {
return checkCb(timeout * 2); // always wait twice as long as the last time
} else {
return result;
}
});
}
}
return checkCb(startTimeout);
});
Then you can do poll scrolling to bottom until submit button is active:
cy.waitFor('submit to not be disabled', () => {
cy.get(termsAndConditionsScroll).scrollTo('bottom');
return cy.getSubmitButton().then(btn => {
if (!!btn.disabled) {
return undefined; // undefined means that polling should continue
}
return btn;
});
}, 5000);
cy.getSubmitButton()
.should('not.be.disabled')
.click();
Upvotes: 1