I'm using Enzyme with enzyme-to-json to do Jest snapshot testing of my React components. I'm testing shallow snapshots of a DateRange
component that renders a display field with the current range (e.g. 5/20/2016 - 7/18/2016
) and two DateInput
components that allow selecting a Date
value. This means that my snapshot contains the Date
s I pass to the component both in the DateInput
props and in a text representation it resolves itself. In my test I'm creating some fixed dates using new Date(1995, 4, 23)
.
When I run my test in different timezones, this produces different snapshots, because the Date(year, month, ...)
constructor creates the date in the local timezone. E.g. use of new Date()
produces this difference in snapshot between runs in my local timezone and on our CI server.
- value={1995-05-22T22:00:00.000Z}
+ value={1995-05-23T00:00:00.000Z}
I tried removing the timezone offset from the dates, but then the snapshot differed in the display field value, where the local timezone-dependent representation is used.
- value={5/20/2016 - 7/18/2016}
+ value={5/19/2016 - 7/17/2016}
How can I make my tests produce the same Date
s in snapshots regardless of the timezone they're run in?
Snapshot tests are a very useful tool whenever you want to make sure your UI does not change unexpectedly. A typical snapshot test case renders a UI component, takes a snapshot, then compares it to a reference snapshot file stored alongside the test.
- [Instructor] Snapshot tests are useful for making sure that the UI will not change unexpectedly. An additional Facebook package needs to be added to the project via npm to help us do that. It's called react-test-renderer, and it allows us to render React components as pure JavaScript objects.
When you use toMatchSnapshot you are testing the 'overall' rendering of your component at a given time. This is why, say, you add an element inside your component you have to update the snapshot otherwise your test will fail.
I struggled with this for hours/days and only this worked for me:
1) In your test:
Date.now = jest.fn(() => new Date(Date.UTC(2017, 7, 9, 8)).valueOf())
2) Then change the TZ
env var before running your tests.
So the script in my package.json:
(Mac & Linux only)
"test": "TZ=America/New_York react-scripts test --env=jsdom",
(Windows)
"test": "set TZ=America/New_York && react-scripts test --env=jsdom",
I ended up with a solution comprised of two parts.
Never create Date
objects in tests in timezone-dependent manner. If you don't want to use timestamps directly to have readable test code, use Date.UTC
, e.g.
new Date(Date.UTC(1995, 4, 23))
Date
s into display values, so that it returns a timezone-independent representation, e.g. use Date::toISOString()
. Fortunately this was easy in my case, as I just needed to mock the formatDate
function in my localization module. It might be harder if the component is somehow turning Date
s into strings on its own.
Before I arrived at the above solution, I tried to somehow change how the snapshots are created. It was ugly, because enzyme-to-json saves a local copy of toISOString()
, so I had to use _.cloneDeepWith
and modify all the Date
s. It didn't work out for me anyway, because my tests also contained cases of Date
creation from timestamps (the component is quite a bit more complicated than I described above) and interactions between those and the dates I was creating in the tests explicitly. So I first had to make sure all my date definitions were referring to the same timezone and the rest followed.
Update (11/3/2017): When I checked enzyme-to-json
recently, I haven't been able to find the local saving of toISOString()
, so maybe that's no longer an issue and it could be mocked. I haven't been able to find it in history either though, so maybe I just incorrectly noted which library did it. Test at your own peril :)
I did this by using timezone-mock
, it internally replaces the global Date
object and it's the easiest solution I could find.
The package supports a few test timezones.
import timezoneMock from 'timezone-mock';
describe('when in PT timezone', () => {
beforeAll(() => {
timezoneMock.register('US/Pacific');
});
afterAll(() => {
timezoneMock.unregister();
});
// ...
https://www.npmjs.com/package/timezone-mock
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With