vitest 如何 mock 时间

399 阅读1分钟

要点:beforeEach mock、afterEach 复原。

方式 1:mock global method

const now = Date.now;

beforeEach(() => {
  // tell vitest we use mocked time
  global.Date.now = vi.fn(() => 1687233777420);
})

afterEach(() => {
  // restoring date after each test run
  global.Date.now = now;
})

优点:

  • 简单,易读。如果单个方法 mock 可以使用方式 1.

缺点:

  • 需要逐个方法 mock,若使用到了 Date.now 之外的方法还得新增 mock 实现。

方式 2:官方 setSystemTime

优点:

  • 一次 mock 所有 Date 方法都被 mock

缺点:

  • 需要涉及多个 api 和增加很多『仪式』:useFakeTimersuseRealTimerssetSystemTime

以下来自 vitest.dev/guide/mocki…

import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'

const businessHours = [9, 17]

function purchase() {
  const currentHour = new Date().getHours()
  const [open, close] = businessHours

  if (currentHour > open && currentHour < close)
    return { message: 'Success' }

  return { message: 'Error' }
}

describe('purchasing flow', () => {
  beforeEach(() => {
    // tell vitest we use mocked time
    vi.useFakeTimers()
  })

  afterEach(() => {
    // restoring date after each test run
    vi.useRealTimers()
  })

  it('allows purchases within business hours', () => {
    // set hour within business hours
    const date = new Date(2000, 1, 1, 13)
    vi.setSystemTime(date)

    // access Date.now() will result in the date set above
    expect(purchase()).toEqual({ message: 'Success' })
  })

  it('disallows purchases outside of business hours', () => {
    // set hour outside business hours
    const date = new Date(2000, 1, 1, 19)
    vi.setSystemTime(date)

    // access Date.now() will result in the date set above
    expect(purchase()).toEqual({ message: 'Error' })
  })
})