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
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 getting around this by mocking the toLocaleString
(or whatever toString method you are using) prototype. Using sinon
I did:
var toLocaleString;
beforeAll(() => {
toLocaleString = sinon.stub(Date.prototype, 'toLocaleString', () => 'fake time')
})
afterAll(() => {
toLocaleString.restore()
})
This way if you are generating strings straight from a Date
object, you're still OK.
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
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 :)
If you're using new Date()
constructor instead of Date.now you can do like below:
const RealDate = Date;
beforeEach(() => {
// @ts-ignore
global.Date = class extends RealDate {
constructor() {
super();
return new RealDate("2016");
}
};
})
afterEach(() => {
global.Date = RealDate;
});
This issue is a must visit if you're here.