2

So I'm trying to write some cypress code and the documentation imo isn't really clear.

I have two scenarios.

  1. A page is loaded with no loading spinner.
  2. A page is loaded with a loading spinner.

I would like to write code that would satisfy both scenarios and let the test just continue.

  1. If the page does not have a loading spinner element: Continue with the tests as usual.
  2. If the page does have a loading spinner element: Wait until the element disappears and then continue

Cypress has a lot of fancy functions but the documentation on how to use them just isn't clear enough.

I tried with the following piece of code:

  try {
    cy.getByTestId('loader-spinner')
      .should('exist')
      .then(el => {
        el.should('not.exist');
      });
  } catch (error) {
    cy.getByTestId('loader-spinner').should('not.exist');
  }
Fody
  • 23,754
  • 3
  • 20
  • 37
basickarl
  • 37,187
  • 64
  • 214
  • 335

2 Answers2

3

Because of the timing aspect it can be tricky to get this test right.

Controlling Triggers

You really need to know what controls the spinner - usually it's a call to API. You can then delay that call (or rather it's response) to "force" the spinner to appear.

To do that, use an intercept

cy.intercept(url-for-api-call, 
  (req) => {
    req.on('response', (res) => res.delay(100))  // enough delay so that spinner appears
  }
)

// whatever action triggers the spinner, e.g click a button

cy.getByTestId('loader-spinner')  // existence is implied in this command
                                  // if the spinner does not appear 
                                  // the test will fail here

cy.getByTestId('loader-spinner').should('not.exist')  // gone after delay finishes

Two scenarios

First off, I don't think your two scenario idea is going to help you write the test correctly.

You are trying to conditionally test using try..catch (nice idea, but does not work). The trouble is conditional testing is flaky because of the timing aspect, you get the test working in a fast environment then it starts to break in a slower one (e.g CI).

Better to control the conditions (like delay above) then test page behaviour under that condition.

To test that the spinner isn't appearing, return a stub in the intercept It should be fast enough to prevent the spinner showing.

cy.intercept(url-for-api-call, {stubbed-response-object})

// whatever action triggers the spinner, e.g click a button

cy.getByTestId('loader-spinner').should('not.exist')  // never appears

Take a look at When Can The Test Blink?

Fody
  • 23,754
  • 3
  • 20
  • 37
  • Smart! I tried this now but it seems to not work, I made a another post with a question specifically for your type of answer: https://stackoverflow.com/questions/71530057/cypress-timeout-values-not-working-when-set – basickarl Mar 22 '22 at 09:19
1

You should be able to just use a should('not.exist') assertion, causing Cypress to wait for the element to not exist. Remember, Cypress automatically retries up until the timeout, so if you haven't changed the global timeout, then the following will try for up to 4 seconds.

cy.getByTestId('loader-spinner')
  .should('not.exist');

If you find the test failing because the element still exists, you can bump the timeout. Below, I've defined a 10s (10000ms) timeout for the should() command.

cy.getByTestId('loader-spinner')
  .should('not.exist', { timeout: 10000 });

Additionally, you may find that the element does still exist, but is not visible. In that case, change not.exist to not.be.visible

agoff
  • 5,818
  • 1
  • 7
  • 20