How To "Fake" Date/Time For Testing Mongoose Models How To "Fake" Date/Time For Testing Mongoose Models mongoose mongoose

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