如何使用Jest测试date-fns的formatDistanceToNow函数?
如何固定Jest测试中date-fns的基准时间,避免测试受运行时间影响
你的核心问题是测试依赖系统当前时间,导致跨场景(比如接近午夜时加小时会跨天)的测试结果不稳定。这里提供两种可靠的解决方法,同时先修正你代码里的一个明显bug:date-util.js里的value变量未定义,应该替换为入参date。
方案一:修改业务函数,支持传入基准时间(推荐)
date-fns的isToday、isTomorrow、formatDistanceToNow都支持通过配置参数传入基准参照时间,不需要依赖系统时间。修改后函数不仅能稳定测试,还能在业务场景中复用(比如基于某个固定时间计算相对值)。
修改后的date-util.js
import { isToday, isTomorrow, formatDistanceToNow } from 'date-fns'; export function formatDate(date, baseDate = new Date()) { if (isToday(date, { referenceDate: baseDate })) { return formatDistanceToNow(date, { addSuffix: true, referenceDate: baseDate }); } if (isTomorrow(date, { referenceDate: baseDate })) { return 'Tomorrow'; } }
固定基准时间的测试用例date-util.spec.js
选一个不会跨天的基准时间(比如上午10点),所有测试都基于这个时间计算:
describe('date-util', () => { // 固定基准时间:2024年6月15日上午10点 const fixedBaseDate = new Date('2024-06-15T10:00:00'); it('should show today relative time', () => { expect(formatDate(fixedBaseDate, fixedBaseDate)).toBe('in a few seconds'); // 基准时间加5分钟 let testDate = new Date(fixedBaseDate.getTime() + 5 * 60000); expect(formatDate(testDate, fixedBaseDate)).toBe('in 5 minutes'); // 基准时间减5分钟 testDate = new Date(fixedBaseDate.getTime() - 5 * 60000); expect(formatDate(testDate, fixedBaseDate)).toBe('5 minutes ago'); // 基准时间加4小时20分钟(仍为当天) testDate = new Date(fixedBaseDate.getTime() + 260 * 60000); expect(formatDate(testDate, fixedBaseDate)).toBe('in about 4 hours'); // 基准时间减2小时1分钟 testDate = new Date(fixedBaseDate.getTime() - 121 * 60000); expect(formatDate(testDate, fixedBaseDate)).toBe('about 2 hours ago'); }); it('should show "Tomorrow" for next day dates', () => { const tomorrow = new Date(fixedBaseDate); tomorrow.setDate(tomorrow.getDate() + 1); expect(formatDate(tomorrow, fixedBaseDate)).toBe('Tomorrow'); // 次日加5分钟 let testDate = new Date(tomorrow.getTime() + 5 * 60000); expect(formatDate(testDate, fixedBaseDate)).toBe('Tomorrow'); // 次日减5分钟(仍属于次日) testDate = new Date(tomorrow.getTime() - 5 * 60000); expect(formatDate(testDate, fixedBaseDate)).toBe('Tomorrow'); }); });
方案二:用Jest模拟系统时间(无需修改业务代码)
如果不想改动业务函数,可以用Jest的useFakeTimers直接固定Date.now()的返回值,date-fns会默认使用这个时间作为基准。
修改后的date-util.spec.js
describe('date-util', () => { // 固定系统时间为2024年6月15日上午10点 const fixedTime = new Date('2024-06-15T10:00:00').getTime(); beforeEach(() => { jest.useFakeTimers().setSystemTime(fixedTime); }); afterEach(() => { jest.useRealTimers(); // 测试结束后恢复真实时间 }); it('should show today relative time', () => { const today = new Date(); expect(formatDate(today)).toBe('in a few seconds'); let testDate = new Date(today.getTime() + 5 * 60000); expect(formatDate(testDate)).toBe('in 5 minutes'); testDate = new Date(today.getTime() - 5 * 60000); expect(formatDate(testDate)).toBe('5 minutes ago'); testDate = new Date(today.getTime() + 260 * 60000); expect(formatDate(testDate)).toBe('in about 4 hours'); testDate = new Date(today.getTime() - 121 * 60000); expect(formatDate(testDate)).toBe('about 2 hours ago'); }); it('should show "Tomorrow" for next day dates', () => { const tomorrow = new Date(); tomorrow.setDate(tomorrow.getDate() + 1); expect(formatDate(tomorrow)).toBe('Tomorrow'); let testDate = new Date(tomorrow.getTime() + 5 * 60000); expect(formatDate(testDate)).toBe('Tomorrow'); testDate = new Date(tomorrow.getTime() - 5 * 60000); expect(formatDate(testDate)).toBe('Tomorrow'); }); });
内容的提问来源于stack exchange,提问作者Christof Aenderl
相关产品推荐
相关产品推荐

