How To "Fake" Date/Time For Testing Mongoose Models
Solution
Just wrap Date.now
in an anonymous function, just like that:
function() { return Date.now(); }
Or an ES6 version
() => Date.now()
So the Schema would become something like:
const messageSchema = mongoose.Schema({ user: { type: String, required: true }, message: { type: String, required: true }, created: { type: Date, default: () => Date.now() },});
why it works?
Because when you do sinon.useFakeTimers()
, what sinon does at the back is to override the global
property Date
.
And calling Date
is the same than calling global.Date
.
When you pass Date.now
to mongoose, you're essentially passing the Node internal method referenced by global.Date
, and mongoose will call this method, without accessing the global.Date
reference anymore.
But, with my solution, we're passing a method that, when called, accesses the reference of global.Date
, which now is stubbed by Sinon.
In order to see this behavior in practice, you can do in Javascript something like:
var nativeDate = Date; // accessing global.DateDate = { now: () => 1 }; // overrides global.Date reference to a entirely new objectconsole.log(Date.now()); // now it outputs 1console.log(nativeDate.now()); // outputs current date, stub doesn't work here, because it's calling the javascript native Date method, and not global.Date anymore