-1

In my application, I have the following flow that I need to check in cypress:

  1. User goes to page
  2. The request needed to render the page is being sent.
  3. In the time between the request has been sent and the response has been received, the user should see a loading spinner. After the response has been received, the loading spinner should be removed.

The first thing I tried to test it is simple:

it('should display spinner during page load', () => {
    cy.visit(myPageUrl);
    cy.get(selectors.spinner).should('exist');
    cy.get(selectors.spinner, { timeout: 5000 }).should('not.exist');
});

However, this creates a race condition. The page might load and the spinner will disappear before the cypress reaches the assertion of the existence of the spinner. Here's a visual explanation:

Here's what I expected: Expected result

And here's what might actually happen, which would cause the test to fail: Possible result

And so, after researching for a bit, I tried the following thing to solve the race condition:

it('should display spinner during page load', () => {
    
    let sendResponse;

    const trigger = new Promise((resolve) => {
        sendResponse = resolve;
    });

    cy.intercept('GET', '/myRequiredPageData', (req) => {
        return trigger.then(() => {
            req.reply();
        });
    });

    cy.visit(myPageUrl);

    cy.get(selectors.spinner).should('exist').then(() => {
        sendResponse();
        cy.get(selectors.spinner, { timeout: 5000 }).should('not.exist');
    });

});

However, now I sometimes get this error: A request callback passed to cy.intercept() timed out after returning a Promise that took more than the defaultCommandTimeout of 4000ms to resolve.

I assume the cy.intercept is stuck in the cypress command queue for more than the defaultCommandTimeout and that's why the test fails. Assuming I can't change the configuration key and the configuration of the test, I wonder what else I can do to check for the spinner and whether I am even in the right direction when it comes to best practices regarding loading spinners.

R.Winkles
  • 175
  • 6
Amitkk
  • 7
  • 1
  • Why are you adding a promise to the intercept? Seems that might be causing your issue, the docs don't show that pattern at all. Where did you pick it up from? – Shankar Jul 05 '23 at 08:24
  • From this blog post: https://blog.dai.codes/cypress-loading-state-tests/ – Amitkk Jul 05 '23 at 08:30
  • 2
    I would follow the Cypress docs in preference - if you set up an intercept you should probably wait for it see [Waiting for the intercept](https://docs.cypress.io/api/commands/intercept#Waiting-on-the-intercept) – Shankar Jul 05 '23 at 08:34
  • Also you may not have a "race condition" if the request is quick (e.g caching) the app may not even start up the spinner. Do you have access to source code to check out the sequence of events? – Shankar Jul 05 '23 at 08:36
  • Regarding the wait, the error is still the same even if I wait since the intercept itself is still stuck in the cypress command queue for too long. – Amitkk Jul 05 '23 at 08:51
  • Regarding the spinner, it will always appear. – Amitkk Jul 05 '23 at 08:51
  • 3
    Does this answer your question? [If element exists wait for it to disappear](https://stackoverflow.com/questions/71524731/if-element-exists-wait-for-it-to-disappear) – user16695029 Jul 07 '23 at 21:42

1 Answers1

4

For testing a spinner, I follow this question If element exists wait for it to disappear

The idea is to delay the sequence of events enough to ensure the spinner activates, then check 1st that it is visible then that it's not visible (or not existing).

cy.intercept('GET', '/myRequiredPageData', (req) => {
  req.on('response', (res) => res.delay(300))   
})
.as('request')

cy.visit(myPageUrl)

cy.get(selectors.spinner).should('exist')
cy.wait('@request')

cy.get(selectors.spinner).should('not.exist')