Jest에서 모의 ​​데이트를 어떻게 설정하나요?


112

내 React 구성 요소에 대한 도우미 파일에서 대부분의 날짜 논리를 수행하기 위해 moment.js를 사용하고 있지만 Jest a la에서 날짜를 조롱하는 방법을 알아낼 수 없었습니다 sinon.useFakeTimers().

Jest 문서는 setTimeout, setInterval등과 같은 타이머 기능에 대해서만 설명 하지만 날짜를 설정 한 다음 내 날짜 함수가 의도 한대로 작동하는지 확인하는 데 도움이되지 않습니다.

다음은 내 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);
    });

  });

});

이제 모멘트를 사용하고 내 함수가 모멘트를 사용하기 때문에 이러한 테스트는 통과했지만 약간 불안정 해 보이며 테스트를 위해 날짜를 고정 시간으로 설정하고 싶습니다.

그것이 어떻게 성취 될 수 있는지에 대한 아이디어가 있습니까?

답변:


70

MockDatejest 테스트에서 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();

Date같은 다른 기능을 사용했기 때문에 훌륭하게 작동했습니다 valueOf().
Robin Zimmermann

143

momentjs는 Date내부적으로 사용하기 때문에 Date.now항상 같은 순간을 반환하도록 함수를 덮어 쓸 수 있습니다 .

Date.now = jest.fn(() => 1487076708000) //14.02.2017

또는

Date.now = jest.fn(() => new Date(Date.UTC(2017, 1, 14)).valueOf())

34
다음은 반환 될 실제 날짜를 설정하는 좀 더 예쁜 방법입니다.Date.now = jest.fn(() => new Date(Date.UTC(2017, 0, 1)).valueOf());
developering

4
또는 조금 더 예쁘게 :Date.now = jest.fn(() => +new Date('2017-01-01');
mrzmyr 19

3
또는 :Date.now = jest.fn(() => Date.parse('2017-02-14))
Jeremy Eaton

93

jest.spyOn 은 잠금 시간에 대해 작동합니다.

let dateNowSpy;

beforeAll(() => {
    // Lock Time
    dateNowSpy = jest.spyOn(Date, 'now').mockImplementation(() => 1487076708000);
});

afterAll(() => {
    // Unlock Time
    dateNowSpy.mockRestore();
});

3
훌륭한 솔루션; 종속성이없고 재설정 가능하게 유지하면 단일 테스트에 쉽게 적용 할 수 있습니다.
Caleb Miller

14
dateNowSpy변수 가 필요 없으며 jestjs.io/docs/en/mock-function-api.html#mockfnmockrestoremockReset() 에 따라 중복됩니다 . 에서 간단하게 할 수 있습니다afterAllDate.now.mockRestore()
Jimmy

이것은 훌륭하므로 추가 라이브러리가 필요하지 않습니다. 그러나 이것은 정적 Date 메서드를 사용하는 경우에만 작동합니다 (많지 않음)
hellatan

1
@Jimmy Date.now.mockRestore();속성 'mockRestore'가 '() => number'유형에 존재하지 않습니다. 오류를 제공합니다
Marco Lackovic

3
@Marco는 jest.spyOn (Date, "now"). mockRestore ();
sab apr

6

jest-date-mock 은 내가 작성한 완전한 자바 스크립트 모듈이며, 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 만 사용하십시오.

  • advanceBy (ms) : ms 단위로 날짜 타임 스탬프를 진행합니다.
  • advanceTo ([timestamp]) : 날짜를 타임 스탬프로 재설정하고 기본값은 0입니다.
  • clear () : 모의 시스템을 종료합니다.

당신의 경우는 무엇입니까?
atool

5

새 Date 객체에 대한 모의 메서드를 원하는 사람들을 위해 다음을 수행 할 수 있습니다.

beforeEach(() => {
    jest.spyOn(Date.prototype, 'getDay').mockReturnValue(2);
    jest.spyOn(Date.prototype, 'toISOString').mockReturnValue('2000-01-01T00:00:00.000Z');
});

afterEach(() => {
    jest.restoreAll()
});

감사합니다. 이것은 내가 가진 문제를 해결했습니다.
Grayson Langford

2

의 모의만을 기반으로 한 모든 대답 Date.now()은 일부 패키지 (예 :)가 대신 moment.js사용 하기 때문에 모든 곳에서 작동하지 않습니다 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;

2

몇 가지 대안을 제시하고 싶습니다.

스텁이 필요한 경우 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전혀


2
첫 번째 예를 들어, 내가 얻을TypeError: moment.mockReturnValue is not a function
mkelley33

2
jest.mock("moment")가져 오기 문 같은 수준에서? 그렇지 않으면, 당신은 행동에서 그것을보고 환영 이 프로젝트
데이비드

1

이것은 내가 내 조롱 어떻게 Date.now()내 테스트를 위해 2010 년 설정하는 방법을

jest
  .spyOn(global.Date, 'now')
  .mockImplementationOnce(() => new Date(`2010`).valueOf());

1

다음은 다양한 사용 사례에 대해 읽을 수있는 몇 가지 방법입니다. 다른 코드에서 실수로 덮어 쓸 수있는 원본 개체에 대한 참조를 저장하는 것보다 스파이를 사용하는 것을 선호합니다.

일회성 조롱

jest
  .spyOn(global.Date, 'now')
  .mockImplementationOnce(() => Date.parse('2020-02-14'));

몇 가지 테스트

let dateSpy;

beforeAll(() => {
  dateSpy = jest
    .spyOn(global.Date, 'now')
    .mockImplementation(() => Date.parse('2020-02-14'));
});

afterAll(() => {
  dateSpy.mockRestore();
});


0

모든 테스트에서 사용할 수 있도록 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

0

목표는 테스트 목적으로 구성 요소 렌더링 중에 사용되는 위치에 상관없이 고정 날짜로 new Date ()를 모의하는 것입니다. 라이브러리를 사용하는 것은 new Date () fn을 모의하는 것뿐이라면 오버 헤드가 될 것입니다.

아이디어는 전역 날짜를 임시 변수에 저장하고 전역 dae를 모의 한 다음 사용 후 임시를 전역 날짜로 다시 할당하는 것입니다.

export const stubbifyDate = (mockedDate: Date) => {
    /**
     * Set Date to a new Variable
     */
    const MockedRealDate = global.Date;

    /**
     *  Mock Real date with the date passed from the test
     */
    (global.Date as any) = class extends MockedRealDate {
        constructor() {
            super()
            return new MockedRealDate(mockedDate)
        }
    }

    /**
     * Reset global.Date to original Date (MockedRealDate) after every test
     */
    afterEach(() => {
        global.Date = MockedRealDate
    })
}

Usage in your test would be like

import { stubbyifyDate } from './AboveMethodImplementedFile'

describe('<YourComponent />', () => {
    it('renders and matches snapshot', () => {
        const date = new Date('2019-02-18')
        stubbifyDate(date)

        const component = renderer.create(
            <YourComponent data={}/>
        );
        const tree = component.toJSON();
        expect(tree).toMatchSnapshot();
    });
});



귀하의 답변도 설명하십시오. 단지 코드를 넣는 것은 좋은 접근하지 않습니다
Intsab 하이더

1
제안 해 주셔서 감사합니다. 댓글로 업데이트되었습니다.
Pranava S Balugari

0

Date특정 스위트에서만 개체 를 조롱하려는 경우 문제를 해결하지 못했기 때문에 여기에 차임하고 싶었습니다 .

각 제품군, jest 문서에 대한 설정 및 해체 방법을 사용하여 조롱 할 수 있습니다.

/**
 * Mocking Date for this test suite
 */
const globalDate = Date;

beforeAll(() => {
  // Mocked Date: 2020-01-08
  Date.now = jest.fn(() => new Date(Date.UTC(2020, 0, 8)).valueOf());
});

afterAll(() => {
  global.Date = globalDate;
});

도움이 되었기를 바랍니다!


0

date-faker를 사용할 수 있습니다 . 현재 날짜를 상대적으로 변경할 수 있습니다.

import { dateFaker } from 'date-faker';
// or require if you wish: var { dateFaker } = require('date-faker');

// make current date to be tomorrow
dateFaker.add(1, 'day'); // 'year' | 'month' | 'day' | 'hour' | 'minute' | 'second' | 'millisecond'.

// change using many units
dateFaker.add({ year: 1, month: -2, day: 3 });

// set specific date, type: Date or string
dateFaker.set('2019/01/24');

// reset
dateFaker.reset();
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.