web-dev-qa-db-fra.com

Les composants utilisant des objets Date produisent différents instantanés dans différents fuseaux horaires.

J'utilise Enzyme avec enzyme-à-json à faire Jest test instantané de mes composants React. Je teste des instantanés peu profonds d'un composant DateRange qui restitue un champ d'affichage avec la plage actuelle (par exemple 5/20/2016 - 7/18/2016) et deux composants DateInput qui permettent de sélectionner une valeur Date. Cela signifie que mon instantané contient la Dates que je transmets au composant à la fois dans les accessoires DateInput et dans une représentation textuelle, il se résout lui-même. Dans mon test, je crée des dates fixes en utilisant les deux new Date(1995, 4, 23).

Lorsque j'exécute mon test dans des fuseaux horaires différents, des instantanés différents sont générés, car le constructeur Date(year, month, ...) crée la date dans le fuseau horaire local. Par exemple. L'utilisation de new Date() produit cette différence d'instantané entre les exécutions effectuées dans mon fuseau horaire local et sur notre serveur de CI.

- value={1995-05-22T22:00:00.000Z}
+ value={1995-05-23T00:00:00.000Z}

J'ai essayé de supprimer le décalage de fuseau horaire des dates, mais l'instantané a ensuite différé par la valeur du champ d'affichage, où la représentation locale dépend du fuseau horaire est utilisée.

- value={5/20/2016 - 7/18/2016}
+ value={5/19/2016 - 7/17/2016}

Comment puis-je faire en sorte que mes tests produisent la même valeur Dates dans les instantanés quel que soit le fuseau horaire dans lequel ils sont exécutés?

24
hon2a

J'ai eu du mal avec cela pendant des heures/jours et seulement cela a fonctionné pour moi:

1) Dans votre test: 

Date.now = jest.fn(() => new Date(Date.UTC(2017, 7, 9, 8)).valueOf())

2) Puis modifiez la TZ env var avant d'exécuter vos tests . Donc le script de mon package.json: 

  • ( Mac et Linux uniquement )

    "test": "TZ=America/New_York react-scripts test --env=jsdom",
    
  • ( Les fenêtres

    "test": "set TZ=America/New_York && react-scripts test --env=jsdom",
    
40
morgs32

Je me suis retrouvé avec une solution composée de deux parties.

  1. Ne créez jamais d'objets Date dans les tests de manière dépendante du fuseau horaire. Si vous ne souhaitez pas utiliser directement les horodatages pour obtenir un code de test lisible, utilisez Date.UTC, par exemple.

    new Date(Date.UTC(1995, 4, 23))
    
  2. Simulez le formateur de date utilisé pour transformer Dates en valeurs d'affichage, afin qu'il renvoie une représentation indépendante du fuseau horaire, par ex. utilisez Date::toISOString(). Heureusement, c'était facile dans mon cas, car je devais me moquer de la fonction formatDate dans mon module de localisation. Cela peut être plus difficile si le composant transforme d'une manière ou d'une autre Dates en chaînes.

Avant d'arriver à la solution ci-dessus, j'ai essayé de changer la façon dont les instantanés sont créés. C'était moche, parce que enzyme-to-json enregistre une copie locale de toISOString(); j'ai donc dû utiliser _.cloneDeepWith et modifier tous les Dates. Cela n’a pas fonctionné pour moi de toute façon, car mes tests contenaient également des cas de création de Date à partir d’horodatages (le composant est un peu plus compliqué que je n’ai décrit ci-dessus) et d’interactions explicites entre ceux-ci et les dates que je créais. Je devais donc d'abord m'assurer que toutes mes définitions de date faisaient référence au même fuseau horaire et que le reste suivait.


Mise à jour (03/11/2017): Lorsque j'ai vérifié enzyme-to-json récemment, je n'ai pas pu trouver l'enregistrement local de toISOString(), alors peut-être que ce n'est plus un problème et on pourrait s'en moquer. Cependant, je n’ai pas pu le trouver dans l’histoire, alors j’ai peut-être mal noté quelle bibliothèque l’a fait. Testez à vos risques et périls :)

4
hon2a

J'ai fini par contourner le problème en moquant le prototype toLocaleString (ou la méthode toString que vous utilisez). En utilisant sinon j'ai fait:

var toLocaleString;

beforeAll(() => {
    toLocaleString = sinon.stub(Date.prototype, 'toLocaleString', () => 'fake time')
})

afterAll(() => {
    toLocaleString.restore()
})

De cette façon, si vous générez des chaînes directement à partir d'un objet Date, vous pouvez continuer.

0
Matt