Clock / Tick not working on my example
Current behavior
Hello, thank you for the work you're doing on cypress.
I'm trying to realize a simple example with cy.clock() and cy.tick(). For that, I have create a simple html page (clock.htm) where a button display a message Hello World on the page during 5s.
<!DOCTYPE html>
<html>
<head>
<title>My Title</title>
<script>
function displayEphemeralMsg() {
document.getElementById('myspace').innerText = 'Hello World';
setTimeout(() => {
document.getElementById('myspace').innerText = '';
},5000 );
}
</script>
</head>
<body>
<button type="button" onclick="displayEphemeralMsg()">Click me</button>
<div id="myspace"></div>
</body>
</html>
In front of this page, I have the following test:
describe('template spec', () => {
it('is not working', () => {
cy.visit('http://localhost/clock.htm');
cy.clock();
cy.get('button').click();
cy.contains('Hello World').should('exist');
cy.tick(4000);
cy.contains('Hello World').should('not.exist');
});
})
I just want to skip 4s of the 5s in order to check that message disappear. But the test fail because the message remain on the screen. And if I move the cy.clock() after the click, then it is still failing because the message is still there after the default timeout (4s) but the javascript behavior is back to normal and the message disapear after 5 seconds.
I tried to move the clock in cypress functions before(), beforeEach()... but the problem persists. I missed certainly something, can you help to understand what is going wrong ?
I'm using the following version: Cypress package version: 14.2.0 Cypress binary version: 14.2.0 Electron version: 33.2.1 Bundled Node version: 20.18.1
Note, my node version is v22.3.0 (don't know if it is overidded).
Thanks in advance for your help.
Desired behavior
In this situation, I was expecting that test is passed and 4seconds are skipped.
Test code to reproduce
clock.htm:
<!DOCTYPE html>
<html>
<head>
<title>My Title</title>
<script>
function displayEphemeralMsg() {
document.getElementById('myspace').innerText = 'Hello World';
setTimeout(() => {
document.getElementById('myspace').innerText = '';
},5000 );
}
</script>
</head>
<body>
<button type="button" onclick="displayEphemeralMsg()">Click me</button>
<div id="myspace"></div>
</body>
</html>
test.cy.js:
describe('template spec', () => {
it('is not working', () => {
cy.visit('http://localhost/clock.htm');
cy.clock();
cy.get('button').click();
cy.contains('Hello World').should('exist');
cy.tick(4000);
cy.contains('Hello World').should('not.exist');
});
});
In addition, I tried to add a timeout of 6s to my contains, then test is passed but it takes a long time anyway.
cy.contains('Hello World', {timeout: 6000}).should('not.exist');
Let me know if you need further information and if I missed something.
Cypress Version
14.2.0
Node version
20.18.1
Operating System
Windows
Debug Logs
Other
No response
cy.tick has not worked for us for quite some time on our React component testing. Since the first cypress/react upgrade for React 18.
See https://github.com/cypress-io/cypress/issues/28846
We are also affected. We went from React 18.2 -> React 19, and our end to end tests that used cy.clock() no longer work. We also had to follow another gitHub issue to get cy.clock() to work initially, but it was working fine.
// Set cy.clock up here //https://github.com/cypress-io/cypress/issues/7455#issuecomment-635278631
//Adding Cy clock data to move time forward to match the time in Australia //
cy.clock(australiaTime, ['Date']);
cy.log('Clock Time: ', australiaTime);
Hi,
Just to inform that the issue can be still reproduced with cypress 15.0.0. The following additional tests have been done:
- Use cy.clock inside a beforeEach as mentioned in #28846.
describe('template spec', () => {
beforeEach(() => {
cy.clock();
});
it('is not working', () => {
cy.visit('http://localhost/clock.htm');
cy.get('button').click();
cy.contains('Hello World').should('exist');
cy.tick(4000);
cy.contains('Hello World').should('not.exist');
});
})
- Use cy.clock(new Date().getTime()) as mentioned in #7455
it('is not working', () => {
cy.clock(new Date().getTime());
cy.visit('http://localhost/clock.htm');
cy.get('button').click();
cy.contains('Hello World').should('exist');
cy.tick(4000);
cy.contains('Hello World').should('not.exist');
});
Note: this last does not work even if we force a timeout to 6 seconds. But if we overwrite only the Date object, then it works with timeout (but tick is not effective).
it('is working due to timeout but tick not effective', () => {
cy.clock(new Date().getTime(),['Date']);
cy.visit('http://localhost/clock.htm');
cy.get('button').click();
cy.contains('Hello World').should('exist');
cy.tick(4000);
cy.contains('Hello World', {timeout: 6000}).should('not.exist');
});
Thanks in advance for your help. Let me know if I miss someting. Best Regards.
The cy.tick value should be bigger than your timeout value:
cy.tick(4001);
Works with
setTimeout(() => {
console.log('timeout fired');
document.getElementById('myspace').innerText = '';
}, 4000 );
tldr; In your example make sure your cy.tick(T1) > setTimeout(()..., T2) => works if T1 > T2. It will not work if T1 == T2, because the timer is not selected in this code:
function doTickInner() {
// perform each timer in the requested range
timer = firstTimerInRange(clock, tickFrom, tickTo);
Hi,
Thank you for your comment, it is effectively working. I had to better read the documentation telling : Move the clock the specified number of milliseconds. Any timers $${\color{red}within}$$ the affected range of time will be called.
So this piece of code is working well:
it('is working', () => {
cy.clock();
cy.visit('http://localhost/clock.htm');
cy.get('button').click();
cy.contains('Hello World').should('exist');
cy.tick(5001); // Tick should be greater than the timeout in order to trigger it.
cy.contains('Hello World').should('not.exist');
});
Thanks a lot for your help. My ticket can be closed.