Hanz
Hanz

Reputation: 519

Jest testing function that involves current date

I have a function that check whether the param is the same with or later than today, in my function I used new Date() like so

import moment from "moment";

const validateDate = ({ date }) => {
  return moment(date, "DD-MM-YYYY").isSameOrAfter(
    moment(new Date(), "DD-MM-YYYY", "days")
  );
};

export default validateDate;

My test will be like so:

import validateDate from "./index";

it("is same or after today", () => {
  expect(validateDate({ date: "16-05-2019" })).toBeTruthy();
});

The problem is that the test will fail on 17-05-2019. How to solve this issue?

I tried this idea but not sure whether it's fine or not.

const validateDate = ({ date, today = new Date() }) => {
      return moment(date, "DD-MM-YYYY").isSameOrAfter(
        moment(today, "DD-MM-YYYY", "days")
      );
    };

My test:

expect(validateDate({ date: "16-05-2019" }, today: new Date())).toBeTruthy();

Upvotes: 1

Views: 5844

Answers (2)

hoangdv
hoangdv

Reputation: 16157

You can mock Date object to sure that new Date() returns a condition date.

global.Date = class extends RealDate {
  constructor() {
    super();
    return new RealDate(isoDate);
  }
};

Just overwrite global Date object before a test, then restore after you finish the test.

Final code:

describe("validateDate", () => {
  const RealDate = Date;

  function mockDate(isoDate) {
    global.Date = class extends RealDate {
      constructor() {
        super();
        return new RealDate(isoDate);
      }
    } as any;
  }

  afterEach(() => {
    global.Date = RealDate;
  });

  it("should return true", () => {
    mockDate(moment("15-05-2019", "DD-MM-YYYY").toISOString());
    expect(validateDate({date: "16-05-2019", today: new Date()})).toBeTruthy();
  });
});

Updated 2024-Oct-09

Using Timer Mocks (Jest latest version (29.7))

import moment from 'moment';
import validateDate from './index';

describe("validateDate()", () => {
    const today = moment('16-05-2019', 'DD-MM-YYYY');

    beforeEach(() => {
        jest.useFakeTimers().setSystemTime(today.valueOf());
    });

    afterEach(() => {
        jest.useRealTimers();
    });

    it('is same or after today', () => {
        expect(validateDate({ date: '15-05-2019' })).toBeFalsy();
        expect(validateDate({ date: '16-05-2019' })).toBeTruthy();
        expect(validateDate({ date: '17-05-2019' })).toBeTruthy();
    });
});

Upvotes: 4

Yossi
Yossi

Reputation: 445

I would try to supply dynamic date for the test. For example, the first test will be given today as the date, while the second will be yesterday, with the following code: moment().subtract(1, 'days').valueOf()

More detailed example:

desc("is same or after today", () => {
  it('should return true for today', () => {
    expect(validateDate({
      date: moment().format('DD-MM-YYYY').valueOf()
    })).toBeTruthy();
  })

  it('should return true for yesterday', () => {
    expect(validateDate({
      date: moment().subtract(1, 'days').format('DD-MM-YYYY').valueOf()
    })).toBeTruthy();
  })
});

Upvotes: 0

Related Questions