Date and time
Loading "Date and Time (🏁 solution)"
Run locally for transcripts
You may be noticing a pattern here. I'm trying to keep mock definitions contained and use the hooks like
beforeAll()
and afterAll()
to make sure no mocks are left once the tests are done (and, often, even between the tests).Testing the
getRelativeTime()
function will be no exception:beforeAll(() => {
vi.useFakeTimers()
})
afterAll(() => {
vi.useRealTimers()
})
Calling
vi.useFakeTimers()
detached this test from the real flow of time, and makes it rely on the internal fake date Vitest has. Correspondingly, the vi.useRealTimers()
utility undoes that.To fix date and time in test, I will call
vi.useSystemTime()
function and provide it with the date that I want to be treated as Date.now()
:test('returns "Just now" for the current date', () => {
vi.setSystemTime(new Date('2024-06-01 00:00:00.000Z'))
🦉vi.useSystemTime()
only works in conjunction withvi.useFakeTimers()
.
In order to model the "Just now" scenario, the delta between the current time and the start time has to be 60 seconds or less. In this test, I will pass the exact same date to the
getRelativeTime()
function as the system time:expect(getRelativeTime(new Date('2024-06-01 00:00:00.000Z'))).toBe('Just now')
This produces the time delta of0ms
, which results in the"Just now"
string being returned from the function.
For the tests that feature an actual time difference, I have to use a slightly different setup. Firsts, the system time (which is
Date.now()
) should be set to the time that has already passed. Then, the getRelativeTime()
function will accept the starting time as an argument.test('returns "minute ago" for a date a minute ago', () => {
vi.setSystemTime(new Date('2024-06-01 00:01:05.000Z'))
expect(getRelativeTime(new Date('2024-06-01 00:00:00.000Z'))).toBe(
'1 minute ago',
)
})
Above, I'm setting the
1m 5s 0ms
time difference because the system time is exactly that duration ahead of the starting time passed to getRelativeTime()
.📜 It's worth mentioning that Vitest has avi.advanceTimersByTime()
method to help you advance the system time by a given amount in milliseconds. I am intentionally not using that method in this test for two reasons:
- Working with full dates is more convenient in this case. You can easily tell apart a
1m 5s
difference. Using milliseconds, you'd have to compute that difference in your head every time you read the test. vi.advanceTimersByTime()
advances the date in place. This means that as soon as I call it, theDate.now()
will shift by the given amount. I would have to store the initial date separately because that's the date that has to be passed to thegetRelativeTime()
function (i.e. the start time).