Reputation: 1349
I would like to use Cypress.Commands.overwrite()
to make the cy.visit()
method do what it normally does and then wait until a loader element is no longer in the DOM, indicating that AJAX requests have completed. My goal is exactly this instead of creating a new command. The reason is to avoid situations where, e.g., someone might unknowingly use the unmodified cy.visit()
and then assert that some elements not exist, when they possibly could exist and just not have loaded yet.
While overwriting the default command, I appear to be running into problems with Cypress' use of promises. From the manual, it is clear how to overwrite cy.visit()
when one wants to do stuff before calling the original function. However, I am unable to find an example, where the original function is called first and custom stuff happens only after that.
So what I would like to do with the overwrite()
command is this:
Cypress.Commands.add('visitAndWait', (url) => {
cy.visit(url);
cy.get('[data-cy="loader"]').should('not.exist');
});
I have tested and can confirm that the above does what I need it to. Here are some attempts to make this work as an overwrite, all of which fail:
Cypress.Commands.overwrite('visit', (originalFn, url, options) => {
return originalFn(url, options).then(() => cy.get('[data-cy="loader"]').should('not.exist'));
});
Cypress.Commands.overwrite('visit', async (originalFn, url, options) => {
const res = await originalFn(url, options);
await cy.get('[data-cy="loader"]').should('not.exist');
return res;
});
Both fail with this:
Cypress detected that you returned a promise from a command while also invoking one or more cy commands in that promise.
Cypress.Commands.overwrite('visit', (originalFn, url, options) => {
originalFn(url, options);
return cy.get('[data-cy="loader"]').should('not.exist');
});
And the last one fails with this:
Is this kind of an overwrite possible at all in Cypress, and if so, how is it done? Thank you!
EDIT:
The test code which causes the error in the last case is here:
cy.visit('/');
cy.get('[data-cy="switch-to-staff"]').click();
Basically it tests a user role mocking panel by clicking a button that should mock a staff role.
Upvotes: -1
Views: 7575
Reputation: 461
I worked around the first error by using .then()
like that:
Cypress.Commands.overwrite('visit', (originalFn, url) => {
originalFn(url).then(() => {
// cy...
});
});
For waiting on requests I'm using two approaches.
First Approach: Like the other answer suggests watch the loading icon.
Second Approach: Intercept the actual request like that:
cy.intercept({
method: 'GET',
url: '**random/part/of/the/ajax/request/url**',
}).as("request");
// Here should be the line that triggers the ajax request
// for example: originalFn(url)...
// or cy.click();
cy.wait("@request", { timeout: 10_000 });
Upvotes: 0
Reputation: 1800
As mentioned by @richard-matsen, you should check that your loader exists before waiting for it to disapear. That may be why you get the detached from DOM
error with your switch-to-staff
element.
Something like this might work for you:
Cypress.Commands.overwrite('visit', (originalFn, url, options) => {
originalFn(url, options);
cy.get('[data-cy="loader"]').should('be.visible');
cy.get('[data-cy="loader"]').should('not.be.visible');
});
Upvotes: 9
Reputation: 562
You could use cy.wait() to wait for the page to completely load then check for the loader to not exist
it('Visit the app', function () {
cy.visit('http://localhost:3000')
cy.wait(3000)
cy.get('[data-cy="loader"]').should('not.exist');
})
Wait Reference: https://docs.cypress.io/api/commands/wait.html
Upvotes: 1