web-dev-qa-db-fra.com

Comment définir une date fictive dans Jest?

J'utilise moment.js pour faire la plupart de ma logique de date dans un fichier d'aide pour mes composants React mais je n'ai pas été en mesure de comprendre comment se moquer d'une date dans Jest a la sinon.useFakeTimers ().

Les documents Jest ne parlent que de fonctions de minuterie telles que setTimeout, setInveral, etc., mais ne vous aident pas à définir une date et à vérifier ensuite que mes fonctions de date font ce qu'elles sont censées faire.

Voici quelques-uns de mes fichiers 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;

et voici ce que j'ai mis en place en utilisant 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);
    });

  });

});

Maintenant, ces tests sont réussis parce que j'utilise moment et que mes fonctions utilisent moment, mais cela semble un peu instable et je voudrais régler la date à une heure fixe pour les tests.

Une idée sur la façon dont cela pourrait être accompli?

76
alengel

MockDate peut être utilisé dans les tests de plaisanterie pour changer ce que new Date() renvoie:

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();
50
eadmundo

Puisque momentjs utilise Date en interne, vous pouvez simplement écraser le Date.now fonction pour toujours retourner le même moment.

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

jest.spyOn fonctionne pour le temps de verrouillage:

let dateNowSpy;

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

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

jest-date-mock est un module Javascript complet que j'ai écrit et qui est utilisé pour tester Date sur jest.

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
});

Utilisez les 3 API seulement pour les cas de test.

  • advanceBy (ms): horodatage de la date avancée par ms.
  • advanceTo ([timestamp]): réinitialise la date à l’horodatage, 0 par défaut.
  • clear (): ferme le système fictif.
3
atool

Toutes les réponses basées uniquement sur le mock de Date.now() ne fonctionneront pas partout car certains paquets (par exemple moment.js) Utilisent new Date() à la place.

Dans ce contexte, la réponse basée sur MockDate est, à mon avis, la seule vraiment correcte. Si vous ne voulez pas utiliser de paquet externe, vous pouvez écrire directement dans votre 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
ClementWalter

Je voudrais proposer des approches alternatives.

Si vous avez besoin de stub format() (qui peut dépendre de la localisation et du fuseau horaire!)

import moment from "moment";
...
jest.mock("moment");
...
const format = jest.fn(() => 'April 11, 2019')
moment.mockReturnValue({ format })

Si vous avez seulement besoin de stub moment():

import moment from "moment";
...
jest.mock("moment");
...
const now = "moment(\"2019-04-11T09:44:57.299\")";
moment.mockReturnValue(now);

En ce qui concerne le test de la fonction isDateToday ci-dessus, je pense que le moyen le plus simple serait de ne pas se moquer de moment du tout.

1
Developer Davo

Je voudrais utiliser Manual Mocks, afin qu'il puisse être utilisé dans tous les tests.

// <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
codelegant