-
-
Notifications
You must be signed in to change notification settings - Fork 6.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Mocking current time for Date #2234
Comments
|
For anyone else out there running in to errors with this, I had some issues because global Date object has properties other than constructor. I did the following:
|
If you do not need to assert on how the constructor is being called then extending could be enough: const constantDate = new Date('2017-06-13T04:41:20')
/*eslint no-global-assign:off*/
Date = class extends Date {
constructor() {
return constantDate
}
} |
This works pretty well for const now = Date.now()
Date.now = jest.genMockFunction().mockReturnValue(now) |
Whenever you mock date, don't forget to put back the real version. 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')
})
}) |
Arguably, Date should also be moved forward when running A solution for a "unified" timers mock was to use 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)
// ...
})
}) But it would be great to have this feature builtin. |
Old issue, but |
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 that's a nice solution, however AFAIK it doesn't mock |
In fact it does not work in Jest. Jest uses Jasmine v1.5.2-lite, so it has no clock. I am using
Of course, lolex is not integrated with jest. |
@drpicox ah, good to know it doesn't work then. Still, given the current situation and the number of votes/comments this is getting, I would like to ping @cpojer to consider re-opening this issue. |
FWIW I'd love to integrate lolex - it's the only library I use where I think Jest is missing a battery |
@cpojer Any way we can reopen this. As of now, there is not really a way to mock a date AND simulate the pass of time in an easy way. jasmine has a clock class where you can mock a date AND advance time, via:
Would love to have similar functionality native. https://github.com/jasmine/jasmine/blob/master/src/core/Clock.js |
We will attempt to migrate to Lolex, which supports your use case. See #5165 |
In case you need to mock Date outside of a test environment. I needed to take predictable image snapshots of UI where a date is displayed. This worked for me:
|
@omegdadisc 's suggestion is the best I think. Mocking Date to always return the same date (as it was suggested in the first answers) would mess up with things like Note that you also need to precise the timezone for it to fully work everywhere, e.g. on Travis and produce same result. timemachine.config({
dateString: 'December 25, 1991 13:12:59 GMT'
}); |
The following test stubs Date to return a constant during the test lifecycle. 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);
});
});
|
I needed to mock setting the below line in config or before tests worked for me:
|
I liked @vcarel's approach, but in my case the Date constructor was used with arguments in some cases, so I needed to modify it to accept other dates. I also added Date.now() 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')
})
}) |
I'm using this, which I'm happy with: https://github.com/boblauer/MockDate |
I have done this
|
Just like to add slightly to @callemo's and @iwarner's answer. It's probably less error prone to do something like as it returns a new date instance each time:
This allows functions that mutate date objects (e.g. setMinutes) to be used without mutating constantDate and thus altering the date that is returned from new Date e.g.
|
This is what I'm using after reading all of the above: let currentDate;
beforeAll(() => {
currentDate = new Date();
const RealDate = Date;
global.Date = jest.fn(() => new RealDate(currentDate.toISOString()));
Object.assign(Date, RealDate);
}); |
@samboylett Does this mess up the global date for tests in the future? Did you also reset it in an |
It won't affect tests in different files. For me everything in the current file needed the mocked date, but if you need to reset it between tests in the same file you should use a beforeEach and afterEach, and just set it back in the afterEach: afterEach(() => {
global.Date = RealDate;
}); |
@samboylett thanks! I managed to get my date tests working by using your example as a 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;
});
}); |
Sinon works well for me https://sinonjs.org/releases/v1.17.7/fake-timers/ |
Late to the party, but I think jest has all the functionality you need for this. 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)
}) |
I'm using vue-moment and jest, and have found the best way is to do something like this: 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');
});
}) |
Using ES6
|
If you are using const dateSpy = jest.spyOn(Date, 'now');
dateSpy.mockReturnValue(TIMESTAMP); |
I wanted to mock the whole Date class and the method suggested by @kristojorg seemed ideal. I am not sure if this is the appropriate way to do it, but this solution works fine in TypeScript by fixing the typing issue as mentioned by @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());
});
}); It is worth mentioning that this only works when you instantiate a new |
I am having the same problem: tested a whole bunch of code examples found in this issue and none worked for me: mock appears to be ignored. How did you fix your problem? We are also using Babel so this may be related too. |
@warpdesign this solution seems to work for me with Jest in 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.
});
}); From this article on mocking the current Date in Jest. |
Thank you it worked !! |
What crap is this man. U say Hugo's tutorial and Hugo says yours.... please don't mislead us. |
Jest 26 supports mocking |
If you are stuck with trying to mock the Date constructor in TS, try this:
|
this fixes jestjs/jest#2234 and allows us to properly mock the combination of setTimeout and Date.now()
@SimenB That's great and I just updated to v26 but can't figure out how we use jest to mock the date. The jest docs only talk about how to mock timers so you can test setTimeOut, but how do you do it to mock "new Date()"? |
@gregveres Here is an example test suite that sets the system time (
Update: Included |
Update from Nov. 2020Bolding that ^ as this thread is growing old and linked to a popular stackoverflow post @seansullivan Awesome! FYI, correct me if I'm wrong, but I think it would be nice to add an afterEach (or afterAll) to your specs to reset the date back to reality. Just to be safe.
|
@alexdanilowicz Perfect. Yes, I neglected to include the cleanup in my example. I will update with the |
It's work to me. Thank you ! |
This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs. |
EDIT by @SimenB 25-05-2020: See updated answer: #2234 (comment)
Is there a way to mock the current date? So that
new Date()
orDate.now()
returns a mocked time instead of the current time?The text was updated successfully, but these errors were encountered: