I’m writing E2E tests for my Angular app using Cypress. I have a component with a toggle, and if the toggle is enabled, this subscription is created:
this._sub = timer(60000, 60000)
.pipe(
map(() => this._loadLog()),
takeUntilDestroyed(this._destroyRef),
)
.subscribe();
The ‘_loadLog’ method makes an API request and updates a signal (sets a new value) that is used inside the template. My test is:
it('should automatically update log', () => {
const newLog = [
'22:11:17.461 [main] INFO com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Starting...',
'22:11:17.731 [main] INFO com.zaxxer.hikari.pool.HikariPool - HikariPool-1 - Added connection org.sqlite.jdbc4.JDBC4Connection@7817fd62',
];
cy.clock();
cy.get(CDK_VIRTUAL_SCROLL_ITEM_QUERY).should('exist');
cy.intercept('GET', ApiEndpointsEnum.GET_CURRENT_LOG, (req) => {
req.reply({ strings: newLog });
}).as('getUpdatedLog');
cy.get(AUTO_UPDATE_TOGGLE_BUTTON_QUERY).should('not.have.attr', 'disabled');
cy.get(AUTO_UPDATE_TOGGLE_QUERY).should('not.have.class', MAT_TOGGLE_CHECKED_CLASS);
cy.get(AUTO_UPDATE_TOGGLE_QUERY).click();
// Trigger any immediate effects from the toggle click
cy.tick(0);
cy.get(AUTO_UPDATE_TOGGLE_QUERY).should('have.class', MAT_TOGGLE_CHECKED_CLASS);
// Simulate the passage of 60 seconds to trigger periodic updates
cy.tick(60_000);
cy.wait('@getUpdatedLog');
// Trigger any remaining effects after the network call
cy.tick(0);
cy.get(CDK_VIRTUAL_SCROLL_ITEM_QUERY).should('have.length', newLog.length);
cy.get(CDK_VIRTUAL_SCROLL_ITEM_QUERY).eq(0).should('include.text', newLog[0]);
cy.get(CDK_VIRTUAL_SCROLL_ITEM_QUERY).eq(1).should('include.text', newLog[1]);
});
In my test, I’m trying to use cy.clock() to simulate the passage of time because I don’t want my tests to be slow (waiting for a real minute). The test passes on my Mac, but it sometimes fails on my Windows PC (sometimes it passes, sometimes it fails). Additionally, this test always fails in the pipeline, indicating there’s something wrong with it.
The failure occurs after the request — CDK_VIRTUAL_SCROLL_ITEM_QUERY doesn’t get updated, and its length does not match the length of newLog.
I’ve tried increasing the time in cy.tick(…), and also tried using cy.clock().invoke(‘restore’). While this sometimes works, it occasionally fails with the error ‘executing a cancelled action.’ I also tried using cy.wait(60000), which prevents the test from failing, but I don’t want the test to take a full minute to pass.
2