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

React Native日期选择器组件:Jest测试/模拟moment.js求助

测试React Native中基于moment.js的日期选择器组件

我之前在React Native项目里用moment.js做日期选择器时,也踩过测试模拟的坑,给你分享几个实用的思路和示例,应该能帮你顺利写好测试用例!

一、先搞定moment.js的基础模拟

不管是单元测试还是集成测试,固定moment的时间是关键——不然每次跑测试的时间不一样,结果也会乱。常用的有两种方式:

1. 全局统一mock(适合大部分测试)

在你的测试入口文件(比如jest.setup.js)或者单个测试文件顶部,这么配置:

jest.mock('moment', () => {
  // 先拿到真实的moment模块,避免完全mock掉所有功能
  const actualMoment = jest.requireActual('moment');
  // 固定当前时间为2024-05-20,你可以改成自己需要的测试基准时间
  actualMoment.now = () => new Date('2024-05-20').valueOf();
  return actualMoment;
});

这样所有测试里的moment()都会默认返回这个固定时间,测试结果就稳定了。

2. 单个测试用例单独mock

如果某个测试需要特殊时间,就在用例里临时覆盖:

test('测试选择"明天"的逻辑', () => {
  // 临时把当前时间改成2024-05-20
  const mockNow = jest.spyOn(moment, 'now').mockReturnValue(new Date('2024-05-20').valueOf());
  
  // 这里写你的测试逻辑:渲染组件、模拟操作、断言...
  
  // 测试完记得恢复,别影响其他用例
  mockNow.mockRestore();
});

二、常见日期函数的测试示例

虽然你没贴具体的两个函数,但我举两个最常用的场景,你可以套到自己的代码上:

示例1:测试日期格式化函数(比如formatDisplayDate)

假设这个函数接收moment对象,返回指定格式的字符串:

import moment from 'moment';
import { formatDisplayDate } from '../your-date-picker-component';

describe('formatDisplayDate', () => {
  it('能把moment对象转成"YYYY-MM-DD"格式', () => {
    const testDate = moment('2024-05-20');
    expect(formatDisplayDate(testDate)).toBe('2024-05-20');
  });

  it('传入null时返回空字符串', () => {
    expect(formatDisplayDate(null)).toBe('');
  });

  // 进阶:验证是否正确调用了moment的format方法
  it('调用moment.format时传入了正确的格式参数', () => {
    const mockFormat = jest.fn(() => '2024-05-20');
    // mock moment的实例方法
    jest.mock('moment', () => jest.fn(() => ({ format: mockFormat })));
    
    const testDate = new Date('2024-05-20');
    formatDisplayDate(testDate);
    
    expect(mockFormat).toHaveBeenCalledWith('YYYY-MM-DD');
  });
});

示例2:测试日期范围判断函数(比如isDateInRange)

假设这个函数判断某个日期是否在[start, end]范围内:

import moment from 'moment';
import { isDateInRange } from '../your-date-picker-component';

describe('isDateInRange', () => {
  // 每个用例前固定时间
  beforeEach(() => {
    jest.spyOn(moment, 'now').mockReturnValue(new Date('2024-05-20').valueOf());
  });

  // 每个用例后恢复mock
  afterEach(() => {
    jest.spyOn(moment, 'now').mockRestore();
  });

  it('日期在范围内时返回true', () => {
    const start = moment('2024-05-15');
    const end = moment('2024-05-25');
    const testDate = moment('2024-05-20');
    
    expect(isDateInRange(testDate, start, end)).toBe(true);
  });

  it('日期等于开始/结束日期时返回true', () => {
    const start = moment('2024-05-20');
    const end = moment('2024-05-20');
    const testDate = moment('2024-05-20');
    
    expect(isDateInRange(testDate, start, end)).toBe(true);
  });

  it('日期超出范围时返回false', () => {
    const start = moment('2024-05-10');
    const end = moment('2024-05-19');
    const testDate = moment('2024-05-20');
    
    expect(isDateInRange(testDate, start, end)).toBe(false);
  });
});

三、React Native组件的集成测试技巧

如果要测试整个日期选择器的交互(比如点击选择日期后,组件更新显示),可以结合@testing-library/react-native来模拟用户操作:

import { render, fireEvent } from '@testing-library/react-native';
import moment from 'moment';
import DatePicker from '../DatePicker';

// 全局mock moment,固定基准时间
jest.mock('moment', () => {
  const actualMoment = jest.requireActual('moment');
  actualMoment.now = () => new Date('2024-05-20').valueOf();
  return actualMoment;
});

test('选择日期后,组件正确更新显示并触发回调', () => {
  const mockOnChange = jest.fn();
  // 渲染组件,传入回调
  const { getByTestId, getByText } = render(<DatePicker onChange={mockOnChange} />);

  // 模拟点击日期输入框,弹出选择面板
  fireEvent.press(getByTestId('date-picker-trigger'));

  // 模拟选择22号这个日期
  fireEvent.press(getByText('22'));

  // 验证回调被调用,传入的是正确的moment对象
  expect(mockOnChange).toHaveBeenCalledWith(moment('2024-05-22'));
  // 验证组件显示的日期正确
  expect(getByTestId('selected-date')).toHaveTextContent('2024-05-22');
});

四、踩过的坑要注意

  • 别完全mock掉moment:如果直接jest.mock('moment', () => {}),会把moment所有方法都干掉,很多功能用不了。最好用jest.requireActual保留真实模块,只覆盖需要修改的部分(比如now方法)。
  • 时区问题:如果你的组件涉及时区,记得在mock时设置默认时区,比如moment.tz.setDefault('Asia/Shanghai'),避免测试结果和实际运行不一致。
  • 清理mock:用spyOn做的mock,一定要在测试后用mockRestore()恢复,不然会影响其他测试用例的结果。

内容的提问来源于stack exchange,提问作者StuffedPoblano

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 04:03:30