Moment.jsを使用して、Reactコンポーネントのヘルパーファイルで日付ロジックのほとんどを実行していますが、Jest a la sinon.useFakeTimersで日付をモックする方法を理解できていません。 ()。
Jestのドキュメントは、setTimeout、setInveralなどのタイマー機能についてのみ説明していますが、日付を設定してから、日付機能が意図したとおりに動作するかどうかを確認することはできません。
これが私のJSファイルの一部です。
var moment = require('moment');
var DateHelper = {
DATE_FORMAT: 'MMMM D',
API_DATE_FORMAT: 'YYYY-MM-DD',
formatDate: function(date) {
return date.format(this.DATE_FORMAT);
},
isDateToday: function(date) {
return this.formatDate(date) === this.formatDate(moment());
}
};
module.exports = DateHelper;
jestを使用して設定したものは次のとおりです。
jest.dontMock('../../../dashboard/calendar/date-helper')
.dontMock('moment');
describe('DateHelper', function() {
var DateHelper = require('../../../dashboard/calendar/date-helper'),
moment = require('moment'),
DATE_FORMAT = 'MMMM D';
describe('formatDate', function() {
it('should return the date formatted as DATE_FORMAT', function() {
var unformattedDate = moment('2014-05-12T00:00:00.000Z'),
formattedDate = DateHelper.formatDate(unformattedDate);
expect(formattedDate).toEqual('May 12');
});
});
describe('isDateToday', function() {
it('should return true if the passed in date is today', function() {
var today = moment();
expect(DateHelper.isDateToday(today)).toEqual(true);
});
});
});
私はモーメントを使用しており、関数はモーメントを使用しているため、これらのテストに合格しましたが、少し不安定なようで、テストの日付を固定時間に設定したいと思います。
それをどのように達成できるかについてのアイデアはありますか?
MockDate は、jestテストでnew Date()
が返すものを変更するために使用できます。
var MockDate = require('mockdate');
// I use a timestamp to make sure the date stays fixed to the ms
MockDate.set(1434319925275);
// test code here
// reset to native Date()
MockDate.reset();
MomentjsはDate
を内部で使用するため、Date.now
関数を上書きするだけで、常に同じ瞬間を返すことができます。
Date.now = jest.fn(() => 1487076708000) //14.02.2017
jest.spyOn はロック時間に対して機能します:
let dateNowSpy;
beforeAll(() => {
// Lock Time
dateNowSpy = jest.spyOn(Date, 'now').mockImplementation(() => 1487076708000);
});
afterAll(() => {
// Unlock Time
dateNowSpy.mockRestore();
});
jest-date-mock は私が書いた完全なJavaScriptモジュールであり、jestでDateをテストするために使用されます。
import { advanceBy, advanceTo } from 'jest-date-mock';
test('usage', () => {
advanceTo(new Date(2018, 5, 27, 0, 0, 0)); // reset to date time.
const now = Date.now();
advanceBy(3000); // advance time 3 seconds
expect(+new Date() - now).toBe(3000);
advanceBy(-1000); // advance time -1 second
expect(+new Date() - now).toBe(2000);
clear();
Date.now(); // will got current timestamp
});
テストケースには3つのAPIのみを使用します。
一部のパッケージ(たとえばmoment.js
)は代わりにDate.now()
を使用するため、new Date()
のモックのみに基づくすべての答えはどこでも機能しません。
この文脈では、MockDate
に基づいた答えは、唯一正しいと思う。外部パッケージを使用したくない場合は、beforeAll
に直接書き込むことができます。
const DATE_TO_USE = new Date('2017-02-02T12:54:59.218Z');
// eslint-disable-next-line no-underscore-dangle
const _Date = Date;
const MockDate = (...args) => {
switch (args.length) {
case 0:
return DATE_TO_USE;
default:
return new _Date(...args);
}
};
MockDate.UTC = _Date.UTC;
MockDate.now = () => DATE_TO_USE.getTime();
MockDate.parse = _Date.parse;
MockDate.toString = _Date.toString;
MockDate.prototype = _Date.prototype;
global.Date = MockDate;
いくつかの代替アプローチを提供したいと思います。
format()
をスタブする必要がある場合(ロケールとタイムゾーンに依存する可能性があります!)
import moment from "moment";
...
jest.mock("moment");
...
const format = jest.fn(() => 'April 11, 2019')
moment.mockReturnValue({ format })
スタブmoment()
のみが必要な場合:
import moment from "moment";
...
jest.mock("moment");
...
const now = "moment(\"2019-04-11T09:44:57.299\")";
moment.mockReturnValue(now);
上記のisDateToday
関数のテストに関して、moment
をモックしないことが最も簡単な方法だと思います
Manual Mocksを使用したいので、すべてのテストで使用できます。
// <rootDir>/__mocks__/moment.js
const moment = jest.requireActual('moment')
Date.now = jest.fn(() => 1558281600000) // 2019-05-20 00:00:00.000+08:00
module.exports = moment