I'm trying to write a unit test with Jest for a function that is using the date-fns formatDistanceToNow
function to display human readable distance for today.
So if the date is today, it should show for example "in about 5 hours" but if the date is tomorrow just show "Tomorrow".
Now it depends on the time, the test is running if "in 5 hours" is still today or already tomorrow.
How can I set a fixed date and time the test is running in?
I guess formatDistanceToNow
is using something like Date.now()
as a reference which is using the system time.
Here is an example.
date-util.js
import { isToday, isTomorrow, formatDistanceToNow } from 'date-fns';
export function formatDate(date) {
if (isToday(date)) {
return formatDistanceToNow(value, { addSuffix: true });
}
if (isTomorrow(value)) {
return 'Tomorrow';
}
}
date-util.spec.js
describe('date-util', () => {
it('should show today date', () => {
const today = new Date();
expect(formatDate(today)).toBe('Today');
// plus 5 minutes
let testDate = new Date(today.getTime() + 5 * 60000);
expect(formatDate(testDate)).toBe('in 5 minutes');
// minus 5 minutes
testDate = new Date(today.getTime() - 5 * 60000);
expect(formatDate(testDate)).toBe('5 minutes ago');
// plus 4 hours and 20 minute
testDate = new Date(today.getTime() + 260 * 60000);
expect(formatDate(testDate)).toBe('in about 4 hours');
// minus 2 hours and 1 minute
testDate = new Date(today.getTime() - 121 * 60000);
expect(formatDate(testDate)).toBe('about 2 hours ago');
});
it('should show tomorrow date', () => {
const tomorrow = new Date();
tomorrow.setDate(tomorrow.getDate() + 1);
expect(formatDate(tomorrow)).toBe('Tomorrow');
// 5 minutes ahead
let testDate = new Date(tomorrow.getTime() + 5 * 60000);
expect(formatDate(testDate)).toBe('Tomorrow');
// minus 5 minutes
testDate = new Date(tomorrow.getTime() - 5 * 60000);
expect(formatDate(testDate)).toBe('Tomorrow');
});
});
In the test I'm adding 4 hours and 20 minutes. If the test runs at 8pm, it won't show "in about 4 hours" because it's already tomorrow.
Jest provides a solution to set a fixed date for the date object in all tests. I added this to the test to make it work independent of the daytime. The date being used as "now" in all tests is today at 12:00.
import { set } from 'date-fns';
describe('date-util', () => {
beforeAll(() => {
const today = set(new Date(), { hours: 12, minutes: 0, seconds: 0, milliseconds: 0 });
jest.useFakeTimers({ now: today });
});
afterAll(() => {
jest.useRealTimers();
});
it('should show today date', () => {
// tests
});
it('should show tomorrow date', () => {
// tests
});
});