tl;dr: the stubDate
helper can be copied from the bottom of the article.
It is a common case in unit testing to need a static date returned in your tests so that you can either have a fixed expectations (e.g. in a JSON), or to prevent random failures when tests are executed seconds later than when the expectations where made.
For this reason, if you are using Jest, you want to stub the Date
object
inside your Jest tests so that when calling new Date()
or Date.now()
aways
returns the same result.
Jest does not provide a built in method for stubbing the JavaScript Date
object so we have to do this manually. This can be done by overriding the global
Date
object.
const fixedDate = new Date('2018-02-28T09:39:59');
Date = class extends Date {
constructor() {
super();
return fixedDate;
}
};
This is enough to get a test passing, which will always return the time
"2018-02-28 09:39:59", regardless which Date
methods are called. For example,
calling getTime()
on the date instance will always return "1519807199000".
beforeAll and afterAll
Since we are using Jest we can use the beforeAll
function to set the date
before all tests in a test file, so that this code does not have to be copied
into each test case.
const fixedDate = new Date('2018-02-28T09:39:59');
beforeAll(() => {
Date = class extends Date {
constructor() {
super();
return fixedDate;
}
};
});
It is also important to reset Date
back to the original "real" Date
object
after all tests have run to prevent confusing errors in future tests where you
expect to work with a non-stubbed date. We can do this with a Jest afterAll
function. This means we have to cache the original Date
object in the
beforeAll
.
const fixedDate = new Date('2018-02-28T09:39:59');
let _originalDate;
beforeAll(() => {
_originalDate = Date;
Date = class extends Date {
constructor() {
super();
return constantDate;
}
};
});
afterAll(() => {
Date = _originalDate;
});
stubDate
helper
Finally we can piece this all together into a handy stubDate
helper than can
be imported into any test file, leaving the test implementation clean of the
stubbing boilerplate code. I usually use a file called test-helper.js
where
helper functions like this live.
// test-helper.js
export const stubDate = fixedDate => {
let _originalDate;
beforeAll(() => {
_originalDate = Date;
Date = class extends Date {
constructor() {
super();
return fixedDate;
}
};
});
afterAll(() => {
Date = _originalDate;
});
};
This can then be imported into a test file and the before and after actions will automatically be applied to your tests. For example:
// my-spec.js
import { stubDate } from './test-helper';
it('can stub the global date object', () => {
const myDate = new Date('2018-02-28T09:39:59');
stubDate(myDate);
// This expectation will always pass regardless of what time the test is run
expect(Date.now()).toEqual(1519807199000);
});