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 Date
s 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 Date
s dans les instantanés quel que soit le fuseau horaire dans lequel ils sont exécutés?
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",
Je me suis retrouvé avec une solution composée de deux parties.
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))
Date
s 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 Date
s 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 Date
s. 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 :)
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.