Jest: Moqueur de l'heure actuelle pour Date

Créé le 6 déc. 2016  ·  72Commentaires  ·  Source: facebook/jest

EDIT par @SimenB 25-05-2020 : Voir la réponse mise à jour : https://github.com/facebook/jest/issues/2234#issuecomment -633402727

Existe-t-il un moyen de se moquer de la date actuelle ? Alors que new Date() ou Date.now() renvoie une heure fictive au lieu de l'heure actuelle ?

Commentaire le plus utile

Pour quiconque rencontre des erreurs avec cela, j'ai eu quelques problèmes car l'objet Date global a des propriétés autres que le constructeur. J'ai fait ce qui suit :

const DATE_TO_USE = new Date('2016');
const _Date = Date;
global.Date = jest.fn(() => DATE_TO_USE);
global.Date.UTC = _Date.UTC;
global.Date.parse = _Date.parse;
global.Date.now = _Date.now;

Tous les 72 commentaires

Date.now = jest.fn ou global.Date = jest.fn() .

Pour quiconque rencontre des erreurs avec cela, j'ai eu quelques problèmes car l'objet Date global a des propriétés autres que le constructeur. J'ai fait ce qui suit :

const DATE_TO_USE = new Date('2016');
const _Date = Date;
global.Date = jest.fn(() => DATE_TO_USE);
global.Date.UTC = _Date.UTC;
global.Date.parse = _Date.parse;
global.Date.now = _Date.now;

Si vous n'avez pas besoin d'affirmer comment le constructeur est appelé, l'extension peut suffire :

const constantDate = new Date('2017-06-13T04:41:20')

/*eslint no-global-assign:off*/
Date = class extends Date {
  constructor() {
    return constantDate
  }
}

Cela fonctionne assez bien pour Date.now() .

const now = Date.now()
Date.now = jest.genMockFunction().mockReturnValue(now)

Chaque fois que vous vous moquez de la date, n'oubliez pas de remettre la vraie version.
Après le commentaire de @callemo , vous pouvez utiliser l'extrait suivant :

describe('getTimestamp', () => {
  const RealDate = Date

  function mockDate (isoDate) {
    global.Date = class extends RealDate {
      constructor () {
        return new RealDate(isoDate)
      }
    }
  }

  afterEach(() => {
    global.Date = RealDate
  })

  it('should return timestamp', () => {
    mockDate('2017-11-25T12:34:56z')
    expect(getTimestamp()).toEqual('20171125123456')
  })
})

On peut soutenir que la date devrait également être avancée lors de l'exécution de jest.runTimersToTime() et d'autres fonctions de moquerie temporelle. J'ai été piqué par le même problème, car une partie de mon code dépendait du temps et une partie des délais d'attente. Se moquer des deux en même temps - c'est-à-dire exécuter des minuteries simulées ET changer les simulations Date.now et Performance.now n'est pas la meilleure expérience.

Une solution pour une simulation de minuteries "unifiées" consistait à utiliser lolex au lieu de jest intégrés, comme ceci :

import lolex from 'lolex'

describe('tests', () => {
  let clock
  beforeEach(() => {clock = lolex.install()})
  afterEach(() => {clock = clock.uninstall()})

  test('garbage collects after keep alive', () => {
    // ...
    clock.tick(500)
    // ...
  })
})

Mais ce serait génial d'avoir cette fonctionnalité intégrée.

Ancien problème, mais mockdate facilite les choses : https://www.npmjs.com/package/mockdate

https://jasmine.github.io/2.2/introduction?spec=jasmine.any#section -Mocking_the_Date

   describe("Mocking the Date object", function(){
     it("mocks the Date object and sets it to a given time", function() {
       var baseTime = new Date(2013, 9, 23);
       jasmine.clock().mockDate(baseTime);
       jasmine.clock().tick(50);
       expect(new Date().getTime()).toEqual(baseTime.getTime() + 50);
     });
   });

@drpicox c'est une bonne solution, mais autant que je sache, cela ne se moque pas de performance.now() , qui est une horloge utile uniquement en avant (c'est-à-dire qu'elle ne sera pas retardée par l'utilisateur modifiant la date et l'heure de son système).

En fait ça ne marche pas dans Jest. Jest utilise Jasmine v1.5.2-lite, il n'a donc pas d'horloge. J'utilise lolex .

Date.now() est assez bon pour la plupart des applications, permofrmance.now() il n'est pas encore présent dans le nœud —ne peut pas être utilisé dans SSR par exemple—, donc ça ne semble pas être un gros problème.

Bien sûr, lolex n'est pas intégré à la plaisanterie.

@drpicox ah, bon à savoir que cela ne fonctionne pas alors.
performance.now() est présent dans le nœud, depuis la v8.5.0 je crois. Vous pouvez importer performance depuis le module intégré 'perf_hooks' .

Néanmoins, étant donné la situation actuelle et le nombre de votes/commentaires que cela obtient, je voudrais envoyer un ping à

FWIW J'aimerais intégrer Lolex - c'est la seule bibliothèque que j'utilise où je pense qu'il manque une batterie à Jest

@cpojer De toute façon, nous pouvons rouvrir cela. Pour l'instant, il n'y a pas vraiment de moyen de se moquer d'une date ET de simuler le passage du temps de manière simple.

jasmine a une classe d'horloge où vous pouvez vous moquer d'une date ET d' avancer l'heure, via :

jasmine.clock().install(); //in a beforeEach
jasmine.clock().uninstall(); // in a AfterEach
jasmine.clock().mockDate(new Date('1984/12/15'));

// and very important... the pass of time!
jasmine.clock().tick(100);

J'adorerais avoir des fonctionnalités similaires natives. https://github.com/jasmine/jasmine/blob/master/src/core/Clock.js

Nous essaierons de migrer vers Lolex, qui prend en charge votre cas d'utilisation. Voir #5165

Au cas où vous auriez besoin de vous moquer de la date _en dehors_ d'un environnement de test. J'avais besoin de prendre des instantanés d'images prévisibles de l'interface utilisateur où une date est affichée.

Cela a fonctionné pour moi:
https://github.com/schickling/timemachine

timemachine.config({
  dateString: 'December 25, 1991 13:12:59'
});
console.log(new Date()); // December 25, 1991 13:12:59

La suggestion de @omegdadisc est la meilleure je pense. Mocking Date de toujours renvoyer la même date (comme cela a été suggéré dans les premières réponses) gâcherait des choses comme new Date(2018, 2, 3) donc ce n'était pas une option valable pour moi.

Notez que vous devez également préciser le fuseau horaire pour qu'il fonctionne pleinement partout, par exemple sur Travis et produise le même résultat.

timemachine.config({
  dateString: 'December 25, 1991 13:12:59 GMT'
});

Les souches de test suivantes datent pour renvoyer une constante pendant le cycle de vie du test.

let timeNow;
const realDate = Date;

describe("Stubbed Date", () => {
  beforeAll(() => {
    timeNow = Date.now();
    const _GLOBAL: any = global;
    _GLOBAL.Date = class {
      public static now() {
        return timeNow;
      }

      constructor() {
        return timeNow;
      }

      public valueOf() {
        return timeNow;
      }
    };
  });

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

  it("provides constant timestamps", () => {
    const ts1 = Date.now();
    const ts2 = +new Date();
    expect(ts1).toEqual(ts2);
    expect(ts2).toEqual(timeNow);
  });
});

_GLOBAL n'est qu'une variable proxy pour satisfaire le texte dactylographié.

J'avais besoin de me moquer de Date.now()

définir la ligne ci-dessous dans la configuration ou avant que les tests ne fonctionnent pour moi :

jest.spyOn(Date, 'now').mockImplementation(() => 1479427200000)

J'ai aimé l' approche de

describe('getTimestamp', () => {
  const RealDate = Date

  function mockDate (isoDate) {
    global.Date = class extends RealDate {
      constructor(...theArgs) {
        if (theArgs.length) {
          return new RealDate(...theArgs);
        }
        return new RealDate(isoDate);
      }

      static now() {
        return new RealDate(isoDate).getTime();
      }
    }
  }

  afterEach(() => {
    global.Date = RealDate
  })

  it('should return timestamp', () => {
    mockDate('2017-11-25T12:34:56z')
    expect(getTimestamp()).toEqual('20171125123456')
  })
})

J'utilise ceci, dont je suis satisfait : https://github.com/boblauer/MockDate

Je l'ai fait

~~~
décrire('Test', () => {
const constantDate = new Date('2018-01-01T12:00:00')

avantTous(() => {
global.Date = la classe étend la date {
constructeur () {
super()
return constanteDate
}
}
})
~~~

J'aimerais juste ajouter un peu à la @callemo et @iwarner .

Il est probablement moins sujet aux erreurs de faire quelque chose comme car il renvoie une nouvelle instance de date à chaque fois :

  const constantDate = new Date('2018-01-01T12:00:00')

  beforeAll(() => {
    global.Date = class extends Date {
      constructor () {
        super(constantDate.getTime())
      }
    }
  })

Cela permet aux fonctions qui modifient les objets de date (par exemple, setMinutes) d'être utilisées sans muter constantDate et donc modifier la date renvoyée à partir de la nouvelle date, par exemple

describe('Test', () => {
  const constantDate = new Date('2018-01-01T12:00:00')

  beforeAll(() => {
    global.Date = class extends Date {
      constructor () {
        super()
        return constantDate
      }
    }
  });

  it('it should not be possible to mutate the  original date but it is.', () => {
    const date1 = new Date();
    date1.setMinutes(5);
    const date2 = new Date();
    console.log(date2.getMinutes()); // Will print 5
  });
});

C'est ce que j'utilise après avoir lu tout ce qui précède :

let currentDate;

beforeAll(() => {
  currentDate = new Date();

  const RealDate = Date;
  global.Date = jest.fn(() => new RealDate(currentDate.toISOString()));
  Object.assign(Date, RealDate);
});

@samboylett Est-ce que cela afterAll ?

Cela n'affectera pas les tests dans différents fichiers. Pour moi, tout dans le fichier actuel nécessitait la date fictive, mais si vous devez la réinitialiser entre les tests dans le même fichier, vous devez utiliser un beforeEach et un afterEach, et le remettre simplement dans l'afterEach :

afterEach(() => {
  global.Date = RealDate;
});

@samboylett merci ! J'ai réussi à faire fonctionner mes tests de date en utilisant votre exemple comme base.

const myDate = new Date(2018, 6, 11);

const RealDate = Date;

describe('testcase', () => {
  beforeEach(() => {
    global.Date = jest.fn(
      (...props) =>
        props.length
          ? new RealDate(...props)
          : new RealDate(myDate)
    );
    Object.assign(Date, RealDate);
  });

  afterEach(() => {
    global.Date = RealDate;
  });
});

Peut-être avez-vous besoin de jest-date-mock .

Donnez-vous une API simple pour contrôler l'horodatage actuel de vos cas de test.

import { advanceBy, advanceTo, clear } 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
});

Les solutions ci-dessus ne couvraient pas mon cas d'utilisation. J'ai fait ce qui suit sur la base de @callemo qui manquait de support pour instanceof et de définition de dates spécifiques.

export function mockDate({year = 2017, month = 9, day = 16}) {
    const globalDate = global.Date
    global.Date = class MockDate extends Date {
        constructor() {
            super()
            this.setFullYear(year)
            this.setMonth(month)
            this.setDate(day)
        }
    }
    global.Date.mockRestore = () => global.Date = globalDate
}

@javadoug C'est quoi ton cas ?

@javadoug C'est quoi ton cas ?

@hustcc mockDate() instanceof Date === true .

@javadoug nouvelle version jest-date-mock prise en charge. https://github.com/hustcc/jest-date-mock/pull/7

"Je ne me moque pas toujours du temps, mais quand je le fais, c'est pour plaisanter" - la tristement célèbre @satub

J'avais besoin de me moquer de new Date() mais j'avais besoin du reste des fonctionnalités de Date pour fonctionner normalement. C'est la solution qui a fonctionné pour moi.

describe('...', () => {
  const RealDate = Date;

  function mockDate(isoDate) {
    global.Date = class extends RealDate {
      constructor(...args) {
        if (args.length) return new RealDate(...args);
        return new RealDate(isoDate);
      }
    };
  }

  afterEach(() => {
    global.Date = RealDate;
  });

  it('...', () => {
    mockDate('2018-01-01');
    // rest of the code
  });
})

J'obtiens une erreur chaque fois que j'essaie d'attribuer à global.Date :

Error: Error: ReferenceError: Date is not defined
    at Object.<anonymous>.exportObject.JUnitXmlReporter.self.specDone (/src/node_modules/jasmine-reporters/src/junit_reporter.js:274:33)
    at dispatch (/src/node_modules/jest-jasmine2/build/jasmine/report_dispatcher.js:70:26)
    at ReportDispatcher.specDone (/src/node_modules/jest-jasmine2/build/jasmine/report_dispatcher.js:62:247)
    at Object.specResultCallback (/src/node_modules/jest-jasmine2/build/jasmine/Env.js:411:18)
    at Spec.attr.resultCallback (/src/node_modules/jest-jasmine2/build/setup_jest_globals.js:67:24)
    at complete (/src/node_modules/jest-jasmine2/build/jasmine/Spec.js:111:10)
    at currentRun.then (/src/node_modules/jest-jasmine2/build/jasmine/Spec.js:107:30)

Il semble que le problème soit que j'utilise JUnit reporter qui est exécuté dans le contexte du test et utilise Date qui est déjà détruite car la classe anonyme est détruite.

Alors oui, la date globale est perturbée lorsque vous utilisez des suggestions comme celles ci-dessus. Et ce n'est un problème que lorsque vous utilisez des reporters non standard.

Les reporters ne doivent pas être exécutés à l'intérieur du bac à sable. Les journalistes de Jasmine pourraient s'accrocher à des trucs de jasmime qui ne sont pas pris en charge à dessein, cependant

Oh, alors vous dites que ce genre de code n'est pas supporté ?

const jasmine = global.jasmine;
jasmine.getEnv().addReporter(junitReporter)

L'erreur se produit ici :
https://github.com/facebook/jest/blob/f9fd98fd4e38978e96a86f1c8796593cad7ac470/packages/jest-jasmine2/src/jasmine/ReportDispatcher.js#L63 -L72

Exact, vous devez utiliser
https://jestjs.io/docs/en/configuration#reporters -array-modulename-modulename-options.
Par exemple https://github.com/jest-community/jest-junit

@niieani ,

Une solution pour une simulation de minuteries "unifiées" consistait à utiliser lolex au lieu de jest intégrés, comme ceci :

J'ai essayé cet exemple et mes tests ont été suspendus pour toujours (dans un ARC qui utilise [email protected]). Quelqu'un a-t-il réussi à utiliser Lolex avec Jest ?

@kentcdodds s'assure de ne pas utiliser de faux temporisateurs en même temps. S'il se bloque toujours, cela vous dérange de créer un problème avec une reproduction ? Lolex devrait certainement fonctionner

Ouais, ça marche bien pour moi dans une situation isolée, donc je fais probablement quelque chose d'étrange ailleurs. Merci!

Si vous avez seulement besoin de vous moquer de ces cas :

new Date()
new Date('2018-09-20T23:00:00Z') 
const currentDate = new Date('2018-09-20T23:00:00Z');
Date = class extends Date {
  constructor(date) {
    if (date) {
        return super(date);
    }

    return currentDate;
  }
}

C'est ce que j'utilise après avoir lu tout ce qui précède :

let currentDate;

beforeAll(() => {
  currentDate = new Date();

  const RealDate = Date;
  global.Date = jest.fn(() => new RealDate(currentDate.toISOString()));
  Object.assign(Date, RealDate);
});

Merci @samboylett

Cela a fonctionné pour moi en se moquant de la nouvelle date ()

@petromoldovan est certainement la meilleure réponse.

Ajoutez un appel à mockRestore à la fin des tests pour restaurer la date d'origine :

const dateNowMockFn = jest.spyOn(Date, 'now').mockImplementation(() => 1479427200000);
// ... code with tests
dateNowMockFn.mockRestore();

Solution @vcarel améliorée un peu, au cas où vous voudriez que la simulation renvoie une instance de Date au lieu de l'une des nouvelles classes :

    const RealDate = Date

    const mockDate = (isoDate) => {
      global.Date = class extends RealDate {
        constructor () {
          return super(isoDate)
        }
      }
    }

    afterEach(() => {
      global.Date = RealDate
    })

Je pense peut-être aux moulins à vent ici, mais cela vaut la peine de souligner le vieil adage : ne vous moquez pas de ce que vous ne possédez pas . Au lieu de cela, enveloppez-le dans une fonction. De nos jours, c'est tellement pratique avec les valeurs d'argument par défaut :

const myFunc = (msg, date = new Date()) => console.log(`${msg}! ${date}`);

Maintenant, dans le code de production, vous pouvez profiter de la valeur par défaut :

myFunc("Hello"); // => Hello! Fri Mar 22 2019 21:11:26 GMT-0400 (EDT)

Et dans le code de test, vous pouvez passer la date explicitement, vous moquant ainsi :

myFunc("Hello", dateObj) // => Hello! ...

@yawaramin Il y a certainement des points de vue divergents à ce sujet. Il y a un camp qui pense que les tests devraient vivre au service du code d'application, et il y a un moment passé où la queue commence à remuer le chien (Pete Hunt a des opinions bien arrêtées à ce sujet)

Je ne dis pas que la méthode que vous proposez n'est pas une option valable, mais plutôt elle pourrait peut-être être présentée comme une voie à suivre adaptée à la situation

@cheapsteak Je pense que l'adéquation situationnelle est l'état des choses par défaut. Cela ne fait pas de mal de rappeler gentiment aux gens qu'il y a toujours une opportunité d'améliorer la testabilité et que cela améliore généralement la maintenabilité :-)

Existe-t-il un moyen d'obtenir l'heure actuelle de Jest car il envoie des minuteries ? Quelque chose comme jest.now?

Supposons que j'ai des minuteurs ET des appels à Date.now(). J'appelle jest.runAllTimers(). Ce serait cool si je pouvais appeler jest.spyOn(Date, 'now').mockImplementation(() => quelque chose ) pour que les rappels de la minuterie s'exécutent et puissent vérifier l'heure simulée.

J'avais besoin de me moquer de Date.now()

définir la ligne ci-dessous dans la configuration ou avant que les tests ne fonctionnent pour moi :

jest.spyOn(Date, 'now').mockImplementation(() => 1479427200000)

C'est marrant comme ça marche pour tant de gens mais pas pour moi. Hmm.

Je ne sais pas ce qui se passe, mais peu importe comment je réaffecte Date , Date.now() existe toujours et renvoie toujours une valeur valide.

Date.now = null ne fait rien.
global.Date.now = null ne fait rien.
jest.spyOn(Date, 'now').mockImplementation(() => 1479427200000); ne fait rien.
L'installation et l'utilisation de lolex fonctionnent sur les délais d'attente, mais n'ont aucun effet sur Date.now()
MockDate n'a aucun effet.

Il me manque quelque chose d'évident, je pense. Peut-être qu'une autre dépendance fait quelque chose... si confus.

@mherodev vérifie votre test, vous moquez-vous de la date avant l'exécution de votre fonction de test / le rendu des composants ?

Dans un bloc de test, je fais quelque chose comme...

      Date.now = () => 1;
      Date = null;
      global.Date = null;
      console.log(`Date.now()`, Date.now()); // Date.now() 1560239936091

Mais cette dérogation ne fait rien. Je trouve ça très déroutant.

J'ai suivi le tuto d'Hugo et j'ai fini par faire :

  // @ts-ignore
  .spyOn(global.Date, 'constructor')
  .mockImplementationOnce(() => new Date('2019-06-19T00:07:19.309Z'))

Ainsi, new Date() renverra toujours new Date('2019-06-19T00:07:19.309Z')

Mise à jour : il semble que mes simulations de date ne fonctionnaient pas à cause d'un bug avec la façon dont babel se transpile dans mon environnement. Quelque chose lié à la façon dont nous utilisons @babel/runtime-corejs2

Solution ultime: jest-date-mock .

  • installer

Dans votre package.json sous le jest, créez un tableau setupFiles et ajoutez jest-date-mock au tableau.

{
  "jest": {
    "setupFiles": ["./__setups__/other.js", "jest-date-mock"]
  }
}
  • usage

Donnez-vous une API simple pour contrôler l'horodatage actuel de vos cas de test.

import { advanceBy, advanceTo, clear } 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
});

Je pense : Toutes les autres solutions ne sont pas systématiques, ni temporaires.

il semble que la transformation de babel casse les solutions de contournement précédentes.

Ma solution consiste à ajouter un nouveau fichier nommé setupMockDate.js

const mockDate = DateClass => {
  function Mock(...args) {
    return args.length === 0
      ? new DateClass(Mock.now())
      : new DateClass(...args)
  }
  Object.setPrototypeOf(Mock, DateClass)
  Mock.prototype = DateClass.prototype
  let now
  Mock.now = () => now === undefined ? DateClass.now() : now
  Mock.mockNow = value => now = value
  Mock.mockRestore = () => Mock.mockNow()
  return Mock
}
global.Date = mockDate(Date)

Dans jest.config.js à l'entrée setupFilesAfterEnv (ou setupFiles dans l'ancienne version de plaisanterie), ajoutez '<rootDir>/jest/setupMockDate.js' .

Maintenant, vous pouvez courir

Date.mockNow(10)
expect(Date.now()).toBe(10)
Date.mockRestore()
expect(Date.now()).not.toBe(10)

Sinon fonctionne bien pour moi https://sinonjs.org/releases/v1.17.7/fake-timers/

En retard à la fête, mais je pense que jest a toutes les fonctionnalités dont vous avez besoin pour cela.

describe('how to mock date.now()', function() {
  beforeEach(() => {
    this.timestamp = 0
    global.Date.now = jest.fn().mockImplementation(() => this.timestamp)
  })

  afterEach(() => {
    jest.clearAllMocks()
  })

  it('can advance in time', () => {
    const then = Date.now()

    this.timestamp += 1000

    const now = Date.now()

    expect(now - then).toBe(1000)
  })

J'utilise vue-moment et jest, et j'ai trouvé que le meilleur moyen est de faire quelque chose comme ceci :

import { mount, createLocalVue } from '@vue/test-utils';
import TripList from 'components/trip-list.vue';

const localVue = createLocalVue();
localVue.use(require('vue-moment'));

describe('TripList', () => {

it('text shows current date', () => {
    const myDate = new Date(2019, 5, 5);

    const wrapper = mount(TripList, {
      localVue,
    });

    wrapper.vm.$moment.now = () => myDate;
    wrapper.vm.$forceUpdate();

    expect(wrapper.html()).toContain('Thu, Oct 3rd');
  });
})

Utiliser ES6

const fixedDate = new Date('2019-03-1');
const RealDate = Date;

beforeEach(() => { Date.now = () => fixedDate; });
afterEach(() => { global.Date = RealDate; });

Si vous utilisez Date.now()

const dateSpy = jest.spyOn(Date, 'now');
dateSpy.mockReturnValue(TIMESTAMP);

Pour quiconque rencontre des erreurs avec cela, j'ai eu quelques problèmes car l'objet Date global a des propriétés autres que le constructeur. J'ai fait ce qui suit :

const DATE_TO_USE = new Date('2016');
const _Date = Date;
global.Date = jest.fn(() => DATE_TO_USE);
global.Date.UTC = _Date.UTC;
global.Date.parse = _Date.parse;
global.Date.now = _Date.now;

Je voulais me moquer de toute la classe Date et la méthode suggérée par @kristojorg me semblait idéale.

Je ne sais pas si c'est la bonne façon de procéder, mais cette solution fonctionne bien dans TypeScript en résolvant le problème de frappe mentionné par @nilobarp :

describe('Mock Date', () => {
  const realDateNow = Date.bind(global.Date);

  beforeAll(() => {
    // Fix the time to 2020-1-1 1hr:1min:1sec in order to match
    // snapshots for the DownloadConfirmDialog component.
    const fixedDate = new Date(2020, 0, 1, 1, 1, 1);
    const d = Date;

    // This will only mock any Date objects instantiated with new 
    // and not Date.now().
    const _global: NodeJS.Global = global;
    _global.Date = jest.fn(() => fixedDate);
    _global.Date.parse = d.parse;
    _global.Date.UTC = d.UTC;
    _global.Date.now = d.now;
  });

  it('shows mocked date', () => {
    // Shows 2020-01-01T01:01:01.000Z as the current Date
    // for an instantiated Date object.
    console.log(new Date().toISOString());
  });

  afterAll(() => {
    // Reverts to the current Date object.
    global.Date = realDateNow;
    console.log(new Date().toISOString());
  });
});

Il convient de mentionner que cela ne fonctionne que lorsque vous instanciez un nouvel objet Date et ne fonctionnera pas pour Date.now() . Il y a un commentaire concernant Date.now .

Dans un bloc de test, je fais quelque chose comme...

      Date.now = () => 1;
      Date = null;
      global.Date = null;
      console.log(`Date.now()`, Date.now()); // Date.now() 1560239936091

Mais cette dérogation ne fait rien. Je trouve ça très déroutant.

J'ai le même problème : j'ai testé tout un tas d'exemples de code trouvés dans ce problème et aucun n'a fonctionné pour moi : la simulation semble être ignorée.

Comment as-tu résolu ton problème ?

Nous utilisons également Babel, donc cela peut aussi être lié.

Dans un bloc de test, je fais quelque chose comme...

      Date.now = () => 1;
      Date = null;
      global.Date = null;
      console.log(`Date.now()`, Date.now()); // Date.now() 1560239936091

Mais cette dérogation ne fait rien. Je trouve ça très déroutant.

J'ai le même problème : j'ai testé tout un tas d'exemples de code trouvés dans ce problème et aucun n'a fonctionné pour moi : la simulation semble être ignorée.

Comment as-tu résolu ton problème ?

Nous utilisons également Babel, donc cela peut aussi être lié.

@warpdesign cette solution semble fonctionner pour moi avec Jest dans TypeScript.

describe('Mock Date.now', () => {
  // Bind to the original Date so we can set it back after all tests are finished.
  const realDateNow = Date.now.bind(global.Date);

  beforeAll(() => {
    // Return 1 millisecond when calling Date.now() in tests.
    const dateNowStub = jest.fn(() => 1);
    global.Date.now = dateNowStub;
  });

  it('shows mocked date', () => {
    console.log(Date.now());  // Returns 1.
  });

  afterAll(() => {
    // Set back to the original Date object.
    global.Date.now = realDateNow;
    console.log(Date.now()); // Returns current time in milliseconds.
  });
});

De cet article sur la moquerie de la date actuelle dans Jest .

Solution ultime: jest-date-mock .

  • installer

Dans votre package.json sous le jest, créez un tableau setupFiles et ajoutez jest-date-mock au tableau.

{
  "jest": {
    "setupFiles": ["./__setups__/other.js", "jest-date-mock"]
  }
}
  • usage

Donnez-vous une API simple pour contrôler l'horodatage actuel de vos cas de test.

import { advanceBy, advanceTo, clear } 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
});

Je pense : Toutes les autres solutions ne sont pas systématiques, ni temporaires.

Merci ça a marché !!

J'ai suivi le tuto d'Hugo et j'ai fini par faire :

  // @ts-ignore
  .spyOn(global.Date, 'constructor')
  .mockImplementationOnce(() => new Date('2019-06-19T00:07:19.309Z'))

Ainsi, new Date() renverra toujours new Date('2019-06-19T00:07:19.309Z')

Quelle merde cet homme. Vous dites le tutoriel d'Hugo et Hugo dit le vôtre.... s'il vous plaît ne nous induisez pas en erreur.

Jest 26 prend en charge la moquerie de Date à l'aide de faux minuteurs modernes : https://jestjs.io/blog/2020/05/05/jest-26#new -fake-timers

Si vous ne parvenez pas à vous moquer du constructeur Date dans TS, essayez ceci :

const mockDate = new Date('Tue, 23 Jun 2020 14:34:56');
const RealDate = Date;
(global as any).Date = class extends RealDate {
  constructor() {
    super();
    return mockDate;
  }
};

// test some date related functionality

global.Date = RealDate;

Jest 26 prend en charge la moquerie de Date à l'aide de faux minuteurs modernes : https://jestjs.io/blog/2020/05/05/jest-26#new -fake-timers

@SimenB C'est super et je viens de mettre à jour vers la v26 mais je ne peux pas comprendre comment nous utilisons la plaisanterie pour se moquer de la date. Les docs de plaisanterie ne parlent que de la façon de se moquer des minuteries afin que vous puissiez tester setTimeOut, mais comment faites-vous pour vous moquer de la "nouvelle date ()" ?

@gregveres Voici un exemple de suite de tests qui définit l'heure système (méthodes Date ) à une date fixe et gère l'avancement de cette heure.

const FIXED_SYSTEM_TIME = '2020-11-18T00:00:00Z';

describe('Set Fixed Date', () => {
    beforeEach(() => {
        jest.useFakeTimers('modern');
        jest.setSystemTime(Date.parse(FIXED_SYSTEM_TIME));
    });

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

    it('Should reflect fixed date', () => {
        expect(new Date().toISOString()).toEqual(FIXED_SYSTEM_TIME);

        const MS_TO_ADVANCE = 5000;

        jest.advanceTimersByTime(MS_TO_ADVANCE);

        expect(new Date().toISOString()).toEqual(new Date(Date.parse(FIXED_SYSTEM_TIME) + MS_TO_ADVANCE).toISOString());
    });
});

_Mise à jour : afterEach() inclus par le commentaire de @alexdanilowicz ci-dessous._

Mise à jour de novembre 2020

_En gras ^ car ce fil vieillit et est lié à un post de débordement de pile populaire_

@seansullivan Génial ! Pour info, corrigez-moi si je me trompe, mais je pense qu'il serait bien d'ajouter un afterEach (ou afterAll) à vos spécifications pour réinitialiser la date à la réalité. Juste pour être sûr.

describe('Test', () => {
  // to avoid race conditions between expected and actual date values
  beforeAll(() => {
    jest.useFakeTimers('modern'); // tell Jest to use a different timer implementation.
    jest.setSystemTime(new Date('20 Aug 2020 00:12:00 GMT').getTime())
  });

  afterAll(() => {
    // Back to reality...
    jest.useRealTimers();
  });

@alexdanilowicz Parfait. Oui, j'ai négligé d'inclure le nettoyage dans mon exemple. Je mettrai à jour avec le afterEach() pour m'assurer que la raison est maintenue pour tous ceux qui trouvent ce fil. Merci!

Cette page vous a été utile?
0 / 5 - 0 notes