You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 14:01:35