LoginSignup
16
4

More than 1 year has passed since last update.

【Jest】new Date()をモック化する方法

Last updated at Posted at 2021-12-22

この記事の概要

new Date()はテスト時には固定の値を返して欲しいのでその方法を記載した簡易メモ

方法1:useFakeTimers, setSystemTimeを使う

hoge.spec.ts
const mockDate = new Date(2021, 0, 1, 1, 1, 1);
jest.useFakeTimers();
jest.setSystemTime(mockDate);

Jest公式通りの多分一番簡単なベストな方法
https://jestjs.io/ja/docs/timer-mocks

【追記】
非同期処理が入っているとreactのコンポーネント生成が終わる前にDOMの判定をしてしまったり、Timeoutになってしまったりします。
その場合は

.useFakeTimers({
    doNotFake: [
      "nextTick",
      "setImmediate",
      "clearImmediate",
      "setInterval",
      "clearInterval",
      "setTimeout",
      "clearTimeout",
    ],
  })

と記述すると直ります
参考: https://github.com/nock/nock/issues/2200#issuecomment-1280957462
なので個人的に方法2の方が良いのではないかと思えてきました・・

@types/jestのversionが古いとdoNotFake指定できません

方法2:globalのDateにspy

hoge.spec.ts
const mockDate = new Date(2021, 1, 2, 2, 2, 2);
const spy = jest.spyOn(global, 'Date').mockImplementation(() => mockDate);

※dayjsも内部ではnew Dateしているので、mock化できます
@types/jestのversionが古い場合はmockDate as unknown as string
※Date.now()を使っている箇所があるとエラーになるので方法1にした方が良いかもしれません

方法3:spy用の関数を別途用意

date-utls.ts
export function getNow() {
    return new Date();
}
hoge.spec.ts
import * as DateUtils from './date-utils';

const mockDate = new Date(2021, 2, 3, 3, 3, 3);
const spy = jest.spyOn(DateUtils, 'getNow').mockReturnValue(mockDate);

new Date()を使うのはgetNow()だけ。他は全てgetNow()を使わないといけない

ひと手間かかるけど個別のテストごとに値変えて確認する時などに割と便利

その他

Math.random()の固定化も上記2、3の感じでイケる
https://stackoverflow.com/questions/41570273/how-to-test-a-function-that-output-is-random-using-jest

コード全体、バージョン情報等はこちら

https://github.com/yamatoto/jest-sample
https://github.com/yamatoto/jest-sample/tree/master/src/views/clock

16
4
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
16
4