DEV Community

loading...

How to test time-dependent code - time travelling in JavaScript

Michael Z
Software writer
Originally published at michaelzanggl.com ・1 min read

Say you have a piece of code that depends on the current time.

function isAM() {
 return new Date().getHours() < 12
}
Enter fullscreen mode Exit fullscreen mode

Let's create a test for this.

it('is AM when it is before 12 noon', () => {
  return isAM()
})
Enter fullscreen mode Exit fullscreen mode

The problem is that this test works fine before 12 noon, but will fail afterward.

To fix this, we can pass the date through the function as an argument.

function isAM(date = new Date()) {
 return date.getHours() < 12
}
Enter fullscreen mode Exit fullscreen mode

Now we can create tests checking a variety of dates.

So far there is nothing special happening. Allowing a date to be passed makes perfect sense for a function like isAM, but let's take this a step further.

Say, you now have another function that depends on isAM:

function isDeliverable(item) {
  if (isAM()) {
    return false
  }

  // ...

  return true
}
Enter fullscreen mode Exit fullscreen mode

For whatever reason, items are not deliverable before 12 pm.

Now how do we test this method? Passing a date to isDeliveryable certainly does not make much sense.

This is where we can make use of a handy npm library called timekeeper.

npm i timekeeper --save-dev

timekeeper allows us to travel to a different time by mocking the native Date object.

Here's how we can test will look like:

const timekeeper = require('timekeeper')
const { isDeliverable } = require('./delivery')

it('is not deliverable before 12 noon', () => {
  timekeeper.travel(new Date(2020, 1, 1, 7))

  expect(isDeliverable({ ... })).toBeFalsy()

  timekeeper.reset()
})
Enter fullscreen mode Exit fullscreen mode

Awesome!! It's like Rails.

As this mutates the native Date object, it's best to not run tests in parallel!

Discussion (0)