How to mock Moment with Jest ?

Just-Tech-IT
Just-Tech-IT
Published in
3 min readMar 19, 2020

Par François DESCAMPSF

This post has to explain how to mock momentjs when you are testing some code with Jest.

It could be very weird to mock momentjs when you are dealing with dates in your code.

Often, you need to unit test some pieces of code and different behaviors but with “fake” dates or by altering the results of dates operations done by momentjs

Let’s create a small project to illustrate it :

mkdir jest-moment
npm init
npm install jest --save-dev
npm install moment --save

then modify the package.json scripts part :

"scripts": {
"test": "jest --no-cache --runInBand"
},
"devDependencies": {
"jest": "^25.1.0"
},
"dependencies": {
"moment": "^2.24.0"
}

and the most important the test file index.spec.js.

To my mind, the most “tricky” part is you have to mock the methods of moment but you have two kinds of methods :

  • the “static” methods on momentjs,
  • the “instance” methods on momentjs,

and the “attributes” on the top of momentjs,

In this story, we will mock these three members of momentjs and write some tests to illustrate it.

Here is my simple mock of momentjs with some comments

jest.mock('moment', () => {
// Here we are able to mock chain builder pattern
const mMoment = {
format: jest.fn(() => '12/07/1998'),
startOf: jest.fn().mockReturnThis(),
isValid: jest.fn().mockReturnValue(true)
};
// Here we are able to mock the constructor and to modify instance methods
const fn = jest.fn(newMoment => {
mMoment.format = jest.fn(() => newMoment);
return mMoment;
});
// Here we are able to mock moment methods that depend on moment not on a moment instance
fn.max = (arg0, arg1) => (arg0 > arg1 ? arg0 : arg1);
fn.version = '3.69';
fn.fn = jest.fn();
return fn;
});

In these tests, we mocked these methods :

  • max method,
  • version attribute,
  • format instance method,
  • startOf instance method,
  • isValid instance method,

And some unit tests that illustrate this “mock” module :

it('should mock moment version method by returning 3.69 instead of 2.24', async () => {// given
// actual
const actual = moment.version;

// then
expect(actual).toBe('3.69');
});

This one was pretty simple. Sometimes, this kind of tests is called “canary test”. Let’s code a more complicated one where we change the implementation of max. To remind you, “max” method is a method on the top of momentjs (not belongs on a particular instance of momentjs):

it('should mock moment max method and returning always the larger string (alphabetical order) arg as the max', async () => {
// given
// actual
const actual = moment.max(moment('12/07/1998'), moment('12/07/2018'));

// then
expect(actual.format()).toBe('12/07/2018');
});

Contrary to methods at the top of momentjs, we are able to mock instance methods too :

it('should mock moment() isValid method and lets return the default mock value true', async () => {
// given
// actual
const actual = moment().isValid();
// then
expect(actual).toBe(true);
});

and we are able to override our own mock implementation :

it('should mock moment() isValid method but override our default mock by returning false', async () => {// given
jest.spyOn(moment(), 'isValid').mockReturnValue(false);
// actual
const actual = moment().isValid();
// then
expect(actual).toBe(false);
});

And finally, a last example where we mock the startOf in a way that permits us to return a fake instance in order to test and respect the pattern builder of the startOf moment method :

it('should be able to mock moment() builder pattern like moment().startOf().format("L")', async () => {
// given
jest.spyOn(moment(), 'isValid').mockReturnValue(false);

// actual
const actual = moment('12/07/1998')
.startOf('day')
.format('L');
// then
expect(actual).toBe('12/07/1998');
});

I hope this story, and these examples will help you ;)

See you.

👉 Auteur : François DESCAMPSF

🔎 Lire les autres articles de François

--

--