Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mocking moment() and moment().format using jest

I'm unable to mock moment() or moment().format functions. I have states where, currentDateMoment and currentDateFormatted are getting set as below.

currentDateMoment: moment() //2019-04-23T17:45:26.339Z
currentDateFormatted: moment().format('MM-DD-YYYY').valueOf() //"04-23-2019"

Trying to mock both moment() and moment().format in my snapshot tests to return a particular date, but was unable to. Tried below.

jest.mock('moment', () => () => '2018–01–30T12:34:56+00:00');

jest.mock('moment', () => ({
  constructor: () => '2018–01–30T12:34:56+00:00'
})); 

jest.mock('moment', () => () => ({ format: () => '01–30-2018' }));
like image 529
Zin Yackvaa Avatar asked Apr 24 '19 21:04

Zin Yackvaa


People also ask

How do you mock moment with jest?

mock to mock the moment by passing in a function that returns a function that returns the result of call moment with the given date. We use requireActual to import moment into our test code. In the test, we call tomorrow to return the moment date object from the mocked function and call format with the given date.

Can you mock an object in jest?

The jest object is automatically in scope within every test file. The methods in the jest object help create mocks and let you control Jest's overall behavior. It can also be imported explicitly by via import {jest} from '@jest/globals' .

Is jest mock hoisted?

If you're using ES module imports then you'll normally be inclined to put your import statements at the top of the test file. But often you need to instruct Jest to use a mock before modules use it. For this reason, Jest will automatically hoist jest. mock calls to the top of the module (before any imports).

Can I use jest mock inside a test?

mock() doesn't work inside tests, only outside tests. Bookmark this question.


Video Answer


3 Answers

The easiest way to mock moment() and any function that it uses (i.e. .day(), .format()) is to change the Date that moment() uses under the hood

Add the snippet below inside your test file

Date.now = jest.fn(() => new Date("2020-05-13T12:33:37.000Z"));

This makes it so anytime moment() is called in your tests, moment() thinks that today is Wednesday, May 13th 2020

like image 131
giantriant Avatar answered Oct 18 '22 23:10

giantriant


You can mock Moment to return a specific date, then format don't have to be mocked.

jest.mock('moment', () => {
  return () => jest.requireActual('moment')('2020-01-01T00:00:00.000Z');
});

By doing so, any call to Moment() will always return a moment object with date set to 2020-01-01 00:00:00

Here is an example with a function that return the date of tomorrow and the test for this function.

const moment = require('moment');
const tomorrow = () => {
  const now = moment();
  return now.add(1, 'days');
};

describe('tomorrow', () => {
  it('should return the next day in a specific format', () => {
    const date = tomorrow().format('YYYY-MM-DD');
    expect(date).toEqual('2020-01-02');
  });
});
like image 30
felixyadomi Avatar answered Oct 19 '22 01:10

felixyadomi


Here is the solution:

index.ts:

import moment from 'moment';

export function main() {
  return {
    currentDateMoment: moment().format(),
    currentDateFormatted: moment()
      .format('MM-DD-YYYY')
      .valueOf()
  };
}

index.spec.ts:

import { main } from './';
import moment from 'moment';

jest.mock('moment', () => {
  const mMoment = {
    format: jest.fn().mockReturnThis(),
    valueOf: jest.fn()
  };
  return jest.fn(() => mMoment);
});

describe('main', () => {
  test('should mock moment() and moment().format() correctly ', () => {
    (moment().format as jest.MockedFunction<any>)
      .mockReturnValueOnce('2018–01–30T12:34:56+00:00')
      .mockReturnValueOnce('01–30-2018');
    expect(jest.isMockFunction(moment)).toBeTruthy();
    expect(jest.isMockFunction(moment().format)).toBeTruthy();
    const actualValue = main();
    expect(actualValue).toEqual({ currentDateMoment: '2018–01–30T12:34:56+00:00', currentDateFormatted: '01–30-2018' });
  });
});

Unit test result with 100% coverage:

 PASS  src/stackoverflow/55838798/index.spec.ts
  main
    ✓ should mock moment() and moment().format() correctly  (7ms)

----------|----------|----------|----------|----------|-------------------|
File      |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
----------|----------|----------|----------|----------|-------------------|
All files |      100 |      100 |      100 |      100 |                   |
 index.ts |      100 |      100 |      100 |      100 |                   |
----------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        3.795s, estimated 8s

Source code: https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/55838798

like image 6
slideshowp2 Avatar answered Oct 18 '22 23:10

slideshowp2