How to mock dayjs chained methods
Asked Answered
G

5

13

I have this dayjs objects:

const today = dayjs.utc(date).startOf("day")

I am trying to mock it using jest but to no avail. Here is the approach I tried:

jest.mock("dayjs", () => ({
  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 : mockDate)
      .startOf("day");
  }),
  startOf: jest.fn().mockReturnThis(),
}));

I also tried this:

jest.mock("dayjs", () => ({
  extend: jest.fn(),
  utc: jest.fn((...args) => ({
    startOf: jest.fn(() => {
      const dayjs = jest.requireActual("dayjs");
      dayjs.extend(jest.requireActual("dayjs/plugin/utc"));

      return dayjs
        .utc(args.filter((arg) => arg).length > 0 ? args : mockEventData)
        .startOf("day");
    }),
  })),
}));

Both are not working. Anyone got an advice?

Gessner answered 14/7, 2020 at 15:14 Comment(3)
Shouldn't it be utc(...args) instead of utc(args)? What exactly does 'not working' mean? If there are errors, please, show them. The question should contain a clear problem statement and a way to reproduce the problem.Castoff
@Gessner Can you share the working example? Also, how can I mock the default dayjs() function within current implementation?Kinesics
What is mockDate and mockDateData for your args above?Caucasus
E
4

Presuming you're trying to create a consistent output disregarding the given date argument, you can create Node Module mock like this:

src/__mocks__/dayjs.js
const mock = jest.genMockFromModule('dayjs');

const dayjs = jest.requireActual("dayjs");
const utc = jest.requireActual('dayjs/plugin/utc')
dayjs.extend(utc);

mock.utc = jest.fn().mockReturnValue(dayjs.utc(new Date('1995-12-17T03:24:00')))

module.exports = mock;

and then in your tests within the src folder dayjs.utc will always be using the mocked date

src/today.spec.js
const today = require("./today");
const dayjs = require("dayjs");

describe("today", () => {
  let result;
  beforeAll(() => {
    result = today();
  });

  it("should be called with a date", () => {
    expect(dayjs.utc).toHaveBeenCalledWith(expect.any(Date));
  });

  it("should return consistent date", () => {
    expect(result).toMatchInlineSnapshot(`"1995-12-17T00:00:00.000Z"`);
  });
});

example on github

Electrotherapy answered 15/7, 2020 at 7:2 Comment(1)
I've discovered that my initial approach was actually working (with small modification), I was just feeding it the wrong input data. But thanks for the answer, it sure is a valid approach, albeit different.Gessner
P
9

The best solution that I found is using jest fake timers, see docs.

describe('myDayjsFunction', () => {
  it('returns my value', () => {
    const param = 3

    jest.useFakeTimers().setSystemTime(new Date('2023-01-10'))

    const actual = myDayjsFunction(param)
    const expected = 5

    expect(actual).toEqual(5)

    jest.useRealTimers()
  })
})
Peltate answered 11/1, 2023 at 8:39 Comment(0)
T
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'
import utc from 'dayjs/plugin/utc'
dayjs.extend(utc)

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

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

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

Towery answered 31/12, 2020 at 17:47 Comment(0)
E
4

Presuming you're trying to create a consistent output disregarding the given date argument, you can create Node Module mock like this:

src/__mocks__/dayjs.js
const mock = jest.genMockFromModule('dayjs');

const dayjs = jest.requireActual("dayjs");
const utc = jest.requireActual('dayjs/plugin/utc')
dayjs.extend(utc);

mock.utc = jest.fn().mockReturnValue(dayjs.utc(new Date('1995-12-17T03:24:00')))

module.exports = mock;

and then in your tests within the src folder dayjs.utc will always be using the mocked date

src/today.spec.js
const today = require("./today");
const dayjs = require("dayjs");

describe("today", () => {
  let result;
  beforeAll(() => {
    result = today();
  });

  it("should be called with a date", () => {
    expect(dayjs.utc).toHaveBeenCalledWith(expect.any(Date));
  });

  it("should return consistent date", () => {
    expect(result).toMatchInlineSnapshot(`"1995-12-17T00:00:00.000Z"`);
  });
});

example on github

Electrotherapy answered 15/7, 2020 at 7:2 Comment(1)
I've discovered that my initial approach was actually working (with small modification), I was just feeding it the wrong input data. But thanks for the answer, it sure is a valid approach, albeit different.Gessner
C
0

I'm using plugin customParseFormat and I just mock like this:

jest.mock('dayjs/plugin/customParseFormat', () => ({
  default: jest.requireActual('dayjs/plugin/customParseFormat'),
}));

It works for me.

Conclusion answered 29/11, 2022 at 10:6 Comment(0)
S
0

I've solved my problem with expect.any(Date) in a simple way! When I need to do an update, I record the actual date and in the test I used the expect.any(Date) to see if any date have been passed on query in the updatedAt field.

expect(prisma.transaction.update).toBeCalledWith({
    where: {
      id: 'any_id'
    },
    data: {
      error: 'Error message here',
      tries: 1,
      updatedAt: expect.any(Date)
    }
});
Strangle answered 29/12, 2022 at 20:10 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.