basse
basse

Reputation: 1349

How to make cy.visit() wait for ajax requests to complete?

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:

Error message for first two snippets.

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:

Error message for the last snippet.

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

Answers (3)

RoJaIt
RoJaIt

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

PeaceAndQuiet
PeaceAndQuiet

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

Umair Ahmed
Umair Ahmed

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

Related Questions