4/22/2020
Today Iโm going to show you how to stop the time with one command. Unfortunately only in cypress.io tests. If you know how to do it in real life please DM me. It would be a very helpful tip ๐. Ok, letโs stop joking and get our hands dirty!
First, we need to have something to test. Our app will be deadly-simple. We want to display the enter time and a counter shows how many seconds we spent in the app.
Enter time:
Time on page: 0
import React from "react"
export default () => {
const [enterDate, setEnterDate] = React.useState()
const [counter, setCounter] = React.useState(0)
React.useEffect(() => {
setEnterDate(Date.now())
const intervalId = setInterval(() => {
setCounter(prev => prev + 1)
}, 1000)
return () => clearInterval(intervalId)
}, [])
return (
<div>
<p>
Enter time: <span data-testid="enter-time">{enterDate}</span>
</p>
<p>
Time on page: <span data-testid="counter">{counter}</span>
</p>
</div>
)
}
Ok, we have our app. Now it is time to write some cypress tests.
In our test scenario we would like to check:
Let's try this way:
cy.visit("/")
.get("[data-testid=enter-time]")
.should("have.text", Date.now().toString())
The test looks decent but it doesnโt pass ๐ข
If we would like to show some formatted date (eg. 22-04-2020) instead of a number of milliseconds, then it would not be a problem. But our client wants to display milliseconds and we need to live with this requirement ๐
The cy.clock
command comes with a rescue. It overrides native global functions related to time allowing them to be controlled synchronously via cy.tick()
or the yielded clock
object. This includes controlling:
setTimeout
clearTimeout
setInterval
clearInterval
Date
You can find more info about cy.clock in the cypress.io official documentation.
Now, letโs try to add cy.clock
to our test:
cy.clock()
.visit("/")
.get("[data-testid=enter-time]")
.should("have.text", Date.now().toString())
We still get an error. But this time the error message is different.
expected <span> to have text '1587547901669', but the text was '0'
What is going on with that 0
? Because the time represented in timestamp value is a number of seconds passed from the start of Unix epoch (1st January 1970). We could ask what will happen after the 19th of January 2038 but this is a topic for another blog post ๐.
Calling cy.clock
without any arguments sets the date in our app to 1st January 1970. We could change it by passing an argument to the cy.clock
:
const now = Date.now()
cy.clock(now)
Right now, with a little luck, our test will pass. It depends on how fast our computer is ๐. To fix this issue we need to remember that cy.clock
overrides the time in our app, not in our tests (command chain). Thatโs why we need to change Date.now()
in our assertion to now
value that weโve created at the beginning of the test.
const now = Date.now()
cy.clock(now)
.visit("/")
.get("[data-testid=enter-time]")
.should("have.text", now.toString())
The test is green - always! - success! But there is one little difference in how our app works now. Before using cy.clock
our timer has been running. Right now it stops on 0
. Fortunately, it is expected behavior in our test-case scenario. We've set and stopped the time.
In order to move the time with some value, we need to call cy.tick
command:
const now = Date.now()
cy.clock(now)
.visit("/")
.get("[data-testid=enter-time]")
.should("have.text", now.toString())
.get("[data-testid=counter]")
.should("have.text", "0")
.tick(1000)
.get("[data-testid=counter]")
.should("have.text", "1")
Tada ๐! We've just wrote the test checking the enter date and the value of the counter.
Thatโs a great question. Sometimes we would like to override the Date
object only, leaving the rest untouched (setTimeout
, etc.). In this case, we need to pass a second argument to the cy.clock
- an array of timing functions that we want to override.
cy.clock(Date.UTC(2020, 3, 22), ["Date"])
In this example we set the date/time to 22th April 2020 00:00 UTC (yeap - months in Date
starts from 0
that's why April = 3
๐). In the same time we don't override the setTimeout
and the rest time functions.
That's all for today. I hope that with this knowledge you can go now and stop the time in your tests ๐
Good luck!