cypress-io / cypress

Fast, easy and reliable testing for anything that runs in a browser.
https://cypress.io
MIT License
47.03k stars 3.18k forks source link

Expose `shouldAdvanceTime` option from `@sinonjs/fake-timers` #27744

Open Yihao-G opened 1 year ago

Yihao-G commented 1 year ago

What would you like?

I would like to set shouldAdvanceTime to true when calling cy.clock() so the time automatically flows rather than stopped/frozen.

Why is this needed?

I have a page that will only do something after a set time, but before that, the page also has some other components that rely on the elapse of time (because of the use of setTimeout/setInterval). I don't want to call cy.tick for a random duration because I want to test a specific behaviour that happens after the time I specified.

Other

Related StackOverflow question and answer (and also shows some other use cases): https://stackoverflow.com/questions/75419850/how-to-set-initial-time-in-cypress-and-allow-time-to-flow

nagash77 commented 1 year ago

Hi @Yihao-G can you describe your use case in a bit more detail?

Yihao-G commented 1 year ago

Hi @nagash77 I updated the issue.

mpavel commented 1 year ago

We would like to have the same option.

We have a very large React application and we found that the application does not load at all as soon as we do cy.clock(). Most likely because we are lazy loading components and multiple chunks of JS. We are not sure if webpack or react is causing this, but we basically overcame it with this:

    cy.clock();
    navigate(path);
    // In order to load the app with a stopped clock, we need to tick and wait multiple times.
    // There seems to be a strong correlation between ticking and waiting, so we use them together.
    // Potentially, issue caused due to webpack serving chunks of JS in small bundles,
    // or by React, due to how we trigger the loading of lazy components, over time.
    cy.tick(1000);
    cy.wait(1000);
    cy.tick(1000);
    cy.wait(1000);
    cy.tick(1000);
    cy.wait(1000);

The above allows the app to load. In the Developer Tools -> Network tab, we can see how after every tick and wait, more and more chunks get downloaded by the browser. If we do only a single tick and wait, not all chunks download and that breaks the application, of course.

Additionally, in order to evaluate the UI of the application, we need to do the following:

    cy.clock().invoke('restore');
    cy.get('element').should('be.visible');

If we don't restore the clock, it seems like React doesn't re-render and therefore we can not make proper assertions on the UI. Re-rendering also works fine if we tick and wait again for even 100ms.

We believe that if we could mock the clock but allow it to advance time normally, this will resolve our problems, without the workarounds from above.

Our requirement for the clock() is only to "push" time forward by a few seconds. That's why we'd like to avoid "freezing" time.

oliver-wilson-sainsburys commented 6 months ago

We are seeing the exact same behaviour that @mpavel describes. The workaround that @mpavel has posted somewhat works, but is a workaround we don't want to be using at scale. An update on this issue would unlock a lot of testing scenarios for us.