5

I'm trying to mock dayjs() default function with specific date & time and also wants to mock its nested methods i.e .utc() & .add()

This is what I've tried so far:

abc.ts:

getEarliestDate() {
    const {
        minHour,
        maxHour
    } = operatingHours;
    const earliestDateTime = dayjs().add(sla + 1, 'minute');
    const earliestDateTimeUTC = earliestDateTime.utc();

    return dayjs().add(121, 'minute').format('YYYY-MM-DD HH:mm');
}

abc.test.ts:

import { abc } from '../../src/common/serviceFactory';
import dayjs from 'dayjs';

jest.mock('dayjs', () =>
  jest.fn((...args) => jest.requireActual('dayjs')(args.filter((arg) => arg).length > 0 ? args : '2020-08-12')),
);

jest.mock('dayjs', () => ({
  default: jest.requireActual('dayjs')(`2020-08-18 12:00:00`),
  extend: jest.fn(),
  utc: jest.fn((...args) => {
    const dayjs = jest.requireActual('dayjs');
    dayjs.extend(jest.requireActual('dayjs/plugin/utc'));

    return dayjs.utc(args.filter((arg) => arg).length > 0 ? args : '12:00:00').startOf('day');
  }),
  add: jest.requireActual('dayjs')(`2020-08-18 12:00:00`),
}));

describe('getEarliestDate Function', () => {
  it('should return earliest date response', () => {
    const earliestDate = abc.getEarliestDate();
    expect(earliestDate).toMatch(dayjs().add(121, 'minute').format('YYYY-MM-DD HH:mm'));
  });

But getting this: TypeError: dayjs_1.default is not a function

Any help/suggestion are appreciated.

skyboyer
  • 22,209
  • 7
  • 57
  • 64
Mohammed Amir Ansari
  • 2,311
  • 2
  • 12
  • 26

3 Answers3

6

MockDate works great for this, no intense mocking code required.

https://www.npmjs.com/package/mockdate

import MockDate from 'mockdate'
import dayjs from 'dayjs'

MockDate.set('2000-11-22')
console.log(dayjs.format())

// >>> 2000-11-22T00:00:00Z

Remember to clear the mock after your test with: MockDate.reset();

John Culviner
  • 22,235
  • 6
  • 55
  • 51
4

For basics operations with dayjs this code works:

jest.mock('dayjs', () => jest.fn((...args) => jest.requireActual('dayjs')(args.filter((arg) => arg).length > 0 ? args : '2020-08-12')),);

When '2020-08-12' is the date you want to mock.

1

I think the problem is the default function of mocked module is supposed to be the function instead of the result of return of dayjs(). Try as following would work then:

jest.mock('dayjs', () => ({
  default: jest.fn((...args) => {
    const yourDay = jest.requireActual('dayjs')(args.filter((arg) => arg).length > 0 ? args : '2020-08-11');
    // Mock add function
    yourDay.add = jest.fn(() => jest.requireActual('dayjs')(`2020-08-10 12:00:00`));
    // more mock
    return yourDay;
  })
}));

Also remove the other mock since it would replace:

jest.mock('dayjs', () => ({
  default: jest.requireActual('dayjs')(`2020-08-18 12:00:00`),
  extend: jest.fn(),
  // ...
}));

Another solution, you can change and keep your first mock stay the same:

jest.mock('dayjs', () =>
  jest.fn((...args) => jest.requireActual('dayjs')(args.filter((arg) => arg).length > 0 ? args : '2020-08-12')),
);

The only thing you would do is to enable the option esModuleInterop in your tsconfig.json since this option will add default function for you automatically:

{
  "compilerOptions": {
    // ...
    "esModuleInterop": true,
  },
}
tmhao2005
  • 14,776
  • 2
  • 37
  • 44