4
votes

I am using Cypress to test a data export page which takes several minutes to generate an export. The page does not dynamically update, so I'd need to get Cypress to reload the page until the status shows as completed. I've looked through the Cypress docs and can't see a way to check if an element exists without throwing an exception if it doesn't.

I tried using jQuery but this resulted in an infinite loop:

describe('test reloading', function () {
  it('testSelector reload', function () {
    cy.visit('https://docs.cypress.io/api/utilities/$.html#Usage');
    let found = false;
    while (!found) {
      const nonExistent = Cypress.$('.fake-selector');

      if (!nonExistent.length) {
        cy.reload();
      } else {
        found = true;
      }
    }
  });
});
2
I'm facing the same issue. did you find a way to do it without while loop? - Manspof
@Manspof I have added a working answer. I could not get it to work with a while loop. - Gogowitsch

2 Answers

4
votes

You can try this code. Your element is not available, thus resulting in an infinite loop. You need to jump out from loop after a certain time.

describe('test reloading', function() {
  it('testSelector reload', function() {
    cy.visit('https://docs.cypress.io/api/utilities/$.html#Usage');
    let found = false;
    let count = 0;
    while (!found) {

      const nonExistent = Cypress.$('.fake-selector');

      if (!nonExistent.length) {
        cy.reload();
        found = false;
        count = count + 1;
        cy.wait(1000);
        if (count == 30) {
          found = true;
          cy.log('Element not found after 30 seconds..Exit from loop!!!');
        }
      } else {
        found = true;
      }
    }
  });
});
0
votes

I cannot recommend while loops in Cypress, because you mix synchronous statements such as Cypress.$() and asynchronous statements such as cy.reload().

For Cypress.$() to pick up new elements, it needs a new context, such as within .then() or .should().

I recommend using recursion to implement the repeating reload cycles. Here is an example:

it('testSelector reload', function() {
  let remainingAttempts = 30;

  function waitUntilSelectorExists() {
    let $el = Cypress.$('.fake-selector');
    if ($el.length) {
      // At least one tag was found.
      // Return a jQuery object.
      return $el;
    }

    if (--remainingAttempts) {
      cy.log('Selector not found yet. Remaining attempts: ' +
          remainingAttempts);

      // Requesting the page to reload (F5)
      cy.reload();

      // Wait a second for the server to respond and the DOM to be updated.
      return cy.wait(1000).then(() => {
        return waitUntilSelectorExists();
      });
    }
    throw Error('Selector was not found.');
  }

  waitUntilSelectorExists().then($el => {
    cy.log('$el contains this text: ' + $el.text());
  });
});

To avoid throwing an error for an element that might not exists now (but later), the solution is to get() a parent and try to find() the child:

cy.get('#parent_of_sometimesMissing').then($element => {
  if ($element.find('#sometimesMissing').length > 0) {
    ....
  }
});