While building Minimal Analytics I had the need to test a function that was dependent on time.
In my case, the function returned the milliseconds until midnight.
Here is a simple way to test the function msUntilMidnight
.
The test case
The simplest test I could come up with, looks as follows:
const test = require('ava')
const { msUntilMidnight } = require('./backup')
const HOURS = 60 * 60 * 1000
test('returns ms until midnight', t => {
const relativeNow = +new Date(new Date().toISOString().substring(0, 11) + '22:00:00.000Z')
t.is(msUntilMidnight(relativeNow), 2 * HOURS)
})
You might notice the “weird” variable relativeNow
.
It resembles a “static” date set to 10PM of the current day.
The assertion I make is that 2 hours (in milliseconds) are remaining until midnight.
This “trick” is needed since if you didn’t have this static date, you would always get a different assertion error.
How does this work in relation to the actual code though?
The application code
The idea is the following:
- in the test case, I simulate a “static” date at 10PM of the current date
- in the actual application code, I leverage the default value
Date.now()
msUntilMidnight
looks like this:
function msUntilMidnight (now = Date.now()) {
let midnight = new Date()
midnight.setDate(midnight.getDate() + 1)
midnight = new Date(midnight.toISOString().substring(0, 11) + '00:00:00.000Z')
return +midnight - now
}
Use case
The use case I found for Minimal Analytics is for backups.
I wanted to make the stupidest backup solution, that runs every midnight.
The backup
module looks like this:
const fs = require('fs')
module.exports = {
start,
backup,
msUntilMidnight
}
function start (options = {}) {
setTimeout(backup, msUntilMidnight(), options)
}
function backup (options = {}, scheduleNext = true) {
console.log(new Date().toISOString(), 'backing up', options.DATA_PATH)
const backupPath = options.DATA_PATH + '.bkp'
fs.copyFileSync(options.DATA_PATH, backupPath)
scheduleNext && setTimeout(backup, msUntilMidnight(), options)
}
function msUntilMidnight (now = Date.now()) {
let midnight = new Date()
midnight.setDate(midnight.getDate() + 1)
midnight = new Date(midnight.toISOString().substring(0, 11) + '00:00:00.000Z')
return +midnight - now
}
And you would start the backup service with a simple backup.start()
.
Open source example
You can find the code for Minimal Analytics on Github
Here is also the direct link to the backup module and the related test