Jest: Date์˜ ํ˜„์žฌ ์‹œ๊ฐ„ ์กฐ๋กฑ

์— ๋งŒ๋“  2016๋…„ 12์›” 06์ผ  ยท  72์ฝ”๋ฉ˜ํŠธ  ยท  ์ถœ์ฒ˜: facebook/jest

@SimenB 25-05-2020 ํŽธ์ง‘: ์—…๋ฐ์ดํŠธ๋œ ๋‹ต๋ณ€ ๋ณด๊ธฐ: https://github.com/facebook/jest/issues/2234#issuecomment -633402727

ํ˜„์žฌ ๋‚ ์งœ๋ฅผ ์กฐ๋กฑํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๊นŒ? new Date() ๋˜๋Š” Date.now() ๊ฐ€ ํ˜„์žฌ ์‹œ๊ฐ„ ๋Œ€์‹  ๋ชจ์˜ ์‹œ๊ฐ„์„ ๋ฐ˜ํ™˜ํ•˜๋„๋ก ํ•˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?

๊ฐ€์žฅ ์œ ์šฉํ•œ ๋Œ“๊ธ€

์ด๊ฒƒ์œผ๋กœ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ๋‹ค๋ฅธ ์‚ฌ๋žŒ์˜ ๊ฒฝ์šฐ ์ „์—ญ Date ๊ฐ์ฒด์— ์ƒ์„ฑ์ž ์ด์™ธ์˜ ์†์„ฑ์ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋ช‡ ๊ฐ€์ง€ ๋ฌธ์ œ๊ฐ€ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ๋‹ค์Œ์„ ์ˆ˜ํ–‰ํ–ˆ๋‹ค.

const DATE_TO_USE = new Date('2016');
const _Date = Date;
global.Date = jest.fn(() => DATE_TO_USE);
global.Date.UTC = _Date.UTC;
global.Date.parse = _Date.parse;
global.Date.now = _Date.now;

๋ชจ๋“  72 ๋Œ“๊ธ€

Date.now = jest.fn ๋˜๋Š” global.Date = jest.fn() .

์ด๊ฒƒ์œผ๋กœ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ๋‹ค๋ฅธ ์‚ฌ๋žŒ์˜ ๊ฒฝ์šฐ ์ „์—ญ Date ๊ฐ์ฒด์— ์ƒ์„ฑ์ž ์ด์™ธ์˜ ์†์„ฑ์ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋ช‡ ๊ฐ€์ง€ ๋ฌธ์ œ๊ฐ€ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ๋‹ค์Œ์„ ์ˆ˜ํ–‰ํ–ˆ๋‹ค.

const DATE_TO_USE = new Date('2016');
const _Date = Date;
global.Date = jest.fn(() => DATE_TO_USE);
global.Date.UTC = _Date.UTC;
global.Date.parse = _Date.parse;
global.Date.now = _Date.now;

์ƒ์„ฑ์ž๊ฐ€ ํ˜ธ์ถœ๋˜๋Š” ๋ฐฉ์‹์— ๋Œ€ํ•ด ์ฃผ์žฅํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค๋ฉด ํ™•์žฅ์œผ๋กœ ์ถฉ๋ถ„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

const constantDate = new Date('2017-06-13T04:41:20')

/*eslint no-global-assign:off*/
Date = class extends Date {
  constructor() {
    return constantDate
  }
}

์ด๊ฒƒ์€ Date.now() ๋Œ€ํ•ด ๊ฝค ์ž˜ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

const now = Date.now()
Date.now = jest.genMockFunction().mockReturnValue(now)

๋ชจ์˜ ๋ฐ์ดํŠธ๋ฅผ ํ•  ๋•Œ๋งˆ๋‹ค ์‹ค์ œ ๋ฒ„์ „์œผ๋กœ ๋˜๋Œ๋ฆฌ๋Š” ๊ฒƒ์„ ์žŠ์ง€ ๋งˆ์‹ญ์‹œ์˜ค.
@callemo ์ฃผ์„ ๋‹ค์Œ์— ๋‹ค์Œ ์Šค๋‹ˆํŽซ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

describe('getTimestamp', () => {
  const RealDate = Date

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

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

  it('should return timestamp', () => {
    mockDate('2017-11-25T12:34:56z')
    expect(getTimestamp()).toEqual('20171125123456')
  })
})

ํ‹€๋ฆผ์—†์ด Date๋Š” jest.runTimersToTime() ๋ฐ ๋‹ค๋ฅธ ์‹œ๊ฐ„ ๋ชจ์˜ ๊ธฐ๋Šฅ์„ ์‹คํ–‰ํ•  ๋•Œ๋„ ์•ž์œผ๋กœ ์ด๋™ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋‚ด ์ฝ”๋“œ์˜ ์ผ๋ถ€๋Š” ์‹œ๊ฐ„์— ์˜์กดํ•˜๊ณ  ์ผ๋ถ€๋Š” ์‹œ๊ฐ„ ์ดˆ๊ณผ์— ์˜์กดํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋™์ผํ•œ ๋ฌธ์ œ์— ๋ฌผ๋ ธ์Šต๋‹ˆ๋‹ค. ๋™์‹œ์— ์กฐ๋กฑํ•˜๋Š” ๊ฒƒ -- ์ฆ‰ ์กฐ๋กฑ๋œ ํƒ€์ด๋จธ๋ฅผ ์‹คํ–‰ํ•˜๊ณ  Date.now ๋ฐ Performance.now ์กฐ๋กฑ์„ ์ „ํ™˜ํ•˜๋Š” ๊ฒƒ์€ ์ตœ๊ณ ์˜ ๊ฒฝํ—˜์ด ์•„๋‹™๋‹ˆ๋‹ค.

"ํ†ตํ•ฉ" ํƒ€์ด๋จธ ๋ชจ์˜์— ๋Œ€ํ•œ ์†”๋ฃจ์…˜์€ ๋‹ค์Œ๊ณผ ๊ฐ™์ด jest ๋‚ด์žฅ ํ•จ์ˆ˜ ๋Œ€์‹  lolex ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

import lolex from 'lolex'

describe('tests', () => {
  let clock
  beforeEach(() => {clock = lolex.install()})
  afterEach(() => {clock = clock.uninstall()})

  test('garbage collects after keep alive', () => {
    // ...
    clock.tick(500)
    // ...
  })
})

ํ•˜์ง€๋งŒ ์ด ๊ธฐ๋Šฅ์ด ๋‚ด์žฅ๋˜์–ด ์žˆ์œผ๋ฉด ์ข‹์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์˜ค๋ž˜๋œ ๋ฌธ์ œ์ง€๋งŒ mockdate ์‚ฌ์šฉํ•˜๋ฉด ์‰ฝ๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. https://www.npmjs.com/package/mockdate

https://jasmine.github.io/2.2/introduction?spec=jasmine.any#section -Mocking_the_Date

   describe("Mocking the Date object", function(){
     it("mocks the Date object and sets it to a given time", function() {
       var baseTime = new Date(2013, 9, 23);
       jasmine.clock().mockDate(baseTime);
       jasmine.clock().tick(50);
       expect(new Date().getTime()).toEqual(baseTime.getTime() + 50);
     });
   });

@drpicox ๊ทธ๊ฒƒ์€ ์ข‹์€ ์†”๋ฃจ์…˜์ด์ง€๋งŒ AFAIK๋Š” performance.now() ์กฐ๋กฑํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์‚ฌ์‹ค Jest์—์„œ๋Š” ์ž‘๋™ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. Jest๋Š” Jasmine v1.5.2-lite๋ฅผ ์‚ฌ์šฉํ•˜๋ฏ€๋กœ ์‹œ๊ณ„๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. lolex ์žˆ์Šต๋‹ˆ๋‹ค.

Date.now() ๋Š” ๋Œ€๋ถ€๋ถ„์˜ ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์— ์ถฉ๋ถ„ํ•ฉ๋‹ˆ๋‹ค. permofrmance.now() ์•„์ง ๋…ธ๋“œ์— ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค(์˜ˆ: SSR์—์„œ๋Š” ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Œ). ๋”ฐ๋ผ์„œ ํฐ ๋ฌธ์ œ๋Š” ์•„๋‹Œ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

๋ฌผ๋ก  lolex๋Š” jest์™€ ํ†ตํ•ฉ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

@drpicox ์•„, ๊ทธ๋Ÿฌ๋ฉด ์ž‘๋™ํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฒƒ์„ ์•„๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.
performance.now() ๋Š” v8.5.0 ์ดํ›„๋กœ ๋…ธ๋“œ์— ์กด์žฌํ•ฉ๋‹ˆ๋‹ค. ๋‚ด์žฅ ๋ชจ๋“ˆ 'perf_hooks' ์—์„œ performance ๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋ž˜๋„ ํ˜„์žฌ ์ƒํ™ฉ๊ณผ ์ด์— ๋Œ€ํ•œ ํˆฌํ‘œ/๋Œ“๊ธ€ ์ˆ˜๋ฅผ ๊ฐ์•ˆํ•  ๋•Œ @cpojer ์— ping์„

FWIW lolex๋ฅผ ํ†ตํ•ฉํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค. Jest์— ๋ฐฐํ„ฐ๋ฆฌ๊ฐ€ ์—†๋‹ค๊ณ  ์ƒ๊ฐ๋˜๋Š” ๊ณณ์—์„œ ์‚ฌ์šฉํ•˜๋Š” ์œ ์ผํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ž…๋‹ˆ๋‹ค.

@cpojer ์–ด๋–ค ์‹์œผ๋กœ๋“  ์ด๊ฒƒ์„ ๋‹ค์‹œ ์—ด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ˜„์žฌ๋กœ์„œ๋Š”, ์ •๋ง ๋‚ ์งœ๋ฅผ ์กฐ๋กฑํ•˜๊ณ  ์‰ฌ์šด ๋ฐฉ๋ฒ•์œผ๋กœ ์‹œ๊ฐ„์˜ ํŒจ์Šค๋ฅผ ์‹œ๋ฎฌ๋ ˆ์ด์…˜ ํ•  ์ˆ˜์žˆ๋Š” ๋ฐฉ๋ฒ•์ด ์—†์Šต๋‹ˆ๋‹ค.

jasmine์—๋Š” ๋‹ค์Œ์„ ํ†ตํ•ด ๋‚ ์งœ ์™€ ์‚ฌ์ „ ์‹œ๊ฐ„์„ ์กฐ๋กฑํ•  ์ˆ˜ ์žˆ๋Š” ์‹œ๊ณ„ ํด๋ž˜์Šค๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

jasmine.clock().install(); //in a beforeEach
jasmine.clock().uninstall(); // in a AfterEach
jasmine.clock().mockDate(new Date('1984/12/15'));

// and very important... the pass of time!
jasmine.clock().tick(100);

๋น„์Šทํ•œ ๊ธฐ๋Šฅ์„ ๊ธฐ๋ณธ์ ์œผ๋กœ ๊ฐ–๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค. https://github.com/jasmine/jasmine/blob/master/src/core/Clock.js

๊ท€ํ•˜์˜ ์‚ฌ์šฉ ์‚ฌ๋ก€๋ฅผ ์ง€์›ํ•˜๋Š” Lolex๋กœ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜์„ ์‹œ๋„ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. #5165 ์ฐธ์กฐ

ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ์˜ _outside_ ๋‚ ์งœ๋ฅผ ์กฐ๋กฑํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ. ๋‚ ์งœ๊ฐ€ ํ‘œ์‹œ๋˜๋Š” UI์˜ ์˜ˆ์ธก ๊ฐ€๋Šฅํ•œ ์ด๋ฏธ์ง€ ์Šค๋ƒ…์ƒท์„ ์ฐ์–ด์•ผ ํ–ˆ์Šต๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ ๋‚˜๋ฅผ ์œ„ํ•ด ์ผํ–ˆ์Šต๋‹ˆ๋‹ค.
https://github.com/schickling/timemachine

timemachine.config({
  dateString: 'December 25, 1991 13:12:59'
});
console.log(new Date()); // December 25, 1991 13:12:59

@omegdadisc ์˜ ์ œ์•ˆ์€ ๋‚ด๊ฐ€ ์ƒ๊ฐํ•˜๋Š” ์ตœ๊ณ ์ž…๋‹ˆ๋‹ค. ํ•ญ์ƒ ๊ฐ™์€ ๋‚ ์งœ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” Mocking Date(์ฒซ ๋ฒˆ์งธ ๋‹ต๋ณ€์—์„œ ์ œ์•ˆํ•œ ๋Œ€๋กœ)๋Š” new Date(2018, 2, 3) ์™€ ๊ฐ™์€ ๊ฒƒ์„ ์—‰๋ง์œผ๋กœ ๋งŒ๋“ค๋ฏ€๋กœ ๋‚˜์—๊ฒŒ ์œ ํšจํ•œ ์˜ต์…˜์ด ์•„๋‹™๋‹ˆ๋‹ค.

๋˜ํ•œ Travis์—์„œ์™€ ๊ฐ™์ด ๋ชจ๋“  ๊ณณ์—์„œ ์™„์ „ํžˆ ์ž‘๋™ํ•˜๊ณ  ๋™์ผํ•œ ๊ฒฐ๊ณผ๋ฅผ ์ƒ์„ฑํ•˜๋ ค๋ฉด ์ •ํ™•ํ•œ ์‹œ๊ฐ„๋Œ€๋ฅผ ์ง€์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

timemachine.config({
  dateString: 'December 25, 1991 13:12:59 GMT'
});

๋‹ค์Œ ํ…Œ์ŠคํŠธ ์Šคํ… Date๋Š” ํ…Œ์ŠคํŠธ ์ˆ˜๋ช… ์ฃผ๊ธฐ ๋™์•ˆ ์ƒ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

let timeNow;
const realDate = Date;

describe("Stubbed Date", () => {
  beforeAll(() => {
    timeNow = Date.now();
    const _GLOBAL: any = global;
    _GLOBAL.Date = class {
      public static now() {
        return timeNow;
      }

      constructor() {
        return timeNow;
      }

      public valueOf() {
        return timeNow;
      }
    };
  });

  afterAll(() => {
    global.Date = realDate;
  });

  it("provides constant timestamps", () => {
    const ts1 = Date.now();
    const ts2 = +new Date();
    expect(ts1).toEqual(ts2);
    expect(ts2).toEqual(timeNow);
  });
});

_GLOBAL ๋Š” typescript๋ฅผ ๋งŒ์กฑ์‹œํ‚ค๊ธฐ ์œ„ํ•œ ํ”„๋ก์‹œ ๋ณ€์ˆ˜์ผ ๋ฟ์ž…๋‹ˆ๋‹ค.

๋‚˜๋Š” Date.now() ๋ฅผ ์กฐ๋กฑํ•ด์•ผ ํ–ˆ๋‹ค

๊ตฌ์„ฑ์—์„œ ๋˜๋Š” ํ…Œ์ŠคํŠธ๊ฐ€ ์ž‘๋™ํ•˜๊ธฐ ์ „์— ์•„๋ž˜ ์ค„์„ ์„ค์ •ํ•˜์‹ญ์‹œ์˜ค.

jest.spyOn(Date, 'now').mockImplementation(() => 1479427200000)

@vcarel ์˜ ์ ‘๊ทผ ๋ฐฉ์‹์ด ๋งˆ์Œ์—

describe('getTimestamp', () => {
  const RealDate = Date

  function mockDate (isoDate) {
    global.Date = class extends RealDate {
      constructor(...theArgs) {
        if (theArgs.length) {
          return new RealDate(...theArgs);
        }
        return new RealDate(isoDate);
      }

      static now() {
        return new RealDate(isoDate).getTime();
      }
    }
  }

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

  it('should return timestamp', () => {
    mockDate('2017-11-25T12:34:56z')
    expect(getTimestamp()).toEqual('20171125123456')
  })
})

https://github.com/boblauer/MockDate์— ๋งŒ์กฑํ•˜๋Š” ์ด๊ฒƒ์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” ์ด๊ฒƒ์„ํ–ˆ๋‹ค

~~~
์„ค๋ช…('ํ…Œ์ŠคํŠธ', () => {
const constantDate = ์ƒˆ๋กœ์šด ๋‚ ์งœ('2018-01-01T12:00:00')

beforeAll(() => {
global.Date = ํด๋ž˜์Šค ํ™•์žฅ ๋‚ ์งœ {
์ƒ์„ฑ์ž() {
๊ฐ๋…์ž()
์ƒ์ˆ˜ ๋‚ ์งœ ๋ฐ˜ํ™˜
}
}
})
~~~

@callemo ๋ฐ @iwarner ์˜ ๋‹ต๋ณ€์— ์•ฝ๊ฐ„ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

๋งค๋ฒˆ ์ƒˆ๋กœ์šด ๋‚ ์งœ ์ธ์Šคํ„ด์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฏ€๋กœ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๊ธฐ ์‰ฌ์šด ์˜ค๋ฅ˜๊ฐ€ ์ ์Šต๋‹ˆ๋‹ค.

  const constantDate = new Date('2018-01-01T12:00:00')

  beforeAll(() => {
    global.Date = class extends Date {
      constructor () {
        super(constantDate.getTime())
      }
    }
  })

์ด๋ฅผ ํ†ตํ•ด date ๊ฐ์ฒด(์˜ˆ: setMinutes)๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ constantDate๋ฅผ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๊ณ  ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ์ƒˆ Date์—์„œ ๋ฐ˜ํ™˜๋˜๋Š” ๋‚ ์งœ๋ฅผ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

describe('Test', () => {
  const constantDate = new Date('2018-01-01T12:00:00')

  beforeAll(() => {
    global.Date = class extends Date {
      constructor () {
        super()
        return constantDate
      }
    }
  });

  it('it should not be possible to mutate the  original date but it is.', () => {
    const date1 = new Date();
    date1.setMinutes(5);
    const date2 = new Date();
    console.log(date2.getMinutes()); // Will print 5
  });
});

์ด๊ฒƒ์€ ์œ„์˜ ๋ชจ๋“  ๋‚ด์šฉ์„ ์ฝ์€ ํ›„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

let currentDate;

beforeAll(() => {
  currentDate = new Date();

  const RealDate = Date;
  global.Date = jest.fn(() => new RealDate(currentDate.toISOString()));
  Object.assign(Date, RealDate);
});

@samboylett ์ด๊ฒƒ์ด ํ–ฅํ›„ ํ…Œ์ŠคํŠธ์˜ ๊ธ€๋กœ๋ฒŒ ๋‚ ์งœ๋ฅผ ์—‰๋ง์œผ๋กœ afterAll ํ•จ์ˆ˜์—์„œ๋„ ์žฌ์„ค์ • ํ–ˆ์Šต๋‹ˆ๊นŒ?

๋‹ค๋ฅธ ํŒŒ์ผ์˜ ํ…Œ์ŠคํŠธ์—๋Š” ์˜ํ–ฅ์„ ๋ฏธ์น˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋‚˜์—๊ฒŒ ํ˜„์žฌ ํŒŒ์ผ์˜ ๋ชจ๋“  ๊ฒƒ์€ ๋ชจ์˜ ๋‚ ์งœ๊ฐ€ ํ•„์š”ํ–ˆ์ง€๋งŒ ๋™์ผํ•œ ํŒŒ์ผ์˜ ํ…Œ์ŠคํŠธ ์‚ฌ์ด์— ์žฌ์„ค์ •ํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ beforeEach ๋ฐ afterEach๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  afterEach์—์„œ ๋‹ค์‹œ ์„ค์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

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

@samboylett ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค! ๊ท€ํ•˜์˜ ์˜ˆ์ œ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์‚ฌ์šฉํ•˜์—ฌ ๋‚ ์งœ ํ…Œ์ŠคํŠธ๋ฅผ ์ž‘๋™์‹œํ‚ฌ ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

const myDate = new Date(2018, 6, 11);

const RealDate = Date;

describe('testcase', () => {
  beforeEach(() => {
    global.Date = jest.fn(
      (...props) =>
        props.length
          ? new RealDate(...props)
          : new RealDate(myDate)
    );
    Object.assign(Date, RealDate);
  });

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

์•„๋งˆ๋„ jest-date-mock ์ด ํ•„์š”ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค์˜ ํ˜„์žฌ ํƒ€์ž„์Šคํƒฌํ”„๋ฅผ ์ œ์–ดํ•˜๋Š” โ€‹โ€‹๊ฐ„๋‹จํ•œ API๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

import { advanceBy, advanceTo, clear } from 'jest-date-mock';

test('usage', () => {
  advanceTo(new Date(2018, 5, 27, 0, 0, 0)); // reset to date time.

  const now = Date.now();

  advanceBy(3000); // advance time 3 seconds
  expect(+new Date() - now).toBe(3000);

  advanceBy(-1000); // advance time -1 second
  expect(+new Date() - now).toBe(2000);

  clear();
  Date.now(); // will got current timestamp
});

์œ„์˜ ์†”๋ฃจ์…˜์€ ๋‚ด ์‚ฌ์šฉ ์‚ฌ๋ก€๋ฅผ ๋‹ค๋ฃจ์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. instanceof ๋ฐ ํŠน์ • ๋‚ ์งœ ์„ค์ •์— ๋Œ€ํ•œ ์ง€์›์ด ๋ˆ„๋ฝ๋œ @callemo ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ๋‹ค์Œ์„ ์ˆ˜ํ–‰ํ–ˆ์Šต๋‹ˆ๋‹ค.

export function mockDate({year = 2017, month = 9, day = 16}) {
    const globalDate = global.Date
    global.Date = class MockDate extends Date {
        constructor() {
            super()
            this.setFullYear(year)
            this.setMonth(month)
            this.setDate(day)
        }
    }
    global.Date.mockRestore = () => global.Date = globalDate
}

@javadoug ๋‹น์‹ ์˜ ๊ฒฝ์šฐ๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

@javadoug ๋‹น์‹ ์˜ ๊ฒฝ์šฐ๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

@hustcc mockDate() instanceof Date === true .

@javadoug ์ƒˆ ๋ฒ„์ „ jest-date-mock ์ง€์›. https://github.com/hustcc/jest-date-mock/pull/7

'๋‚˜๋Š” ํ•ญ์ƒ ์‹œ๊ฐ„์„ ์กฐ๋กฑํ•˜์ง€๋Š” ์•Š์ง€๋งŒ ํ•  ๋•Œ ๋†๋‹ด์ž…๋‹ˆ๋‹ค` - ์•…๋ช… ๋†’์€ @satub

new Date() ๋ฅผ ์กฐ๋กฑํ•ด์•ผ ํ–ˆ์ง€๋งŒ ๋‚˜๋จธ์ง€ Date ๊ธฐ๋Šฅ์€ ์ •์ƒ์ ์œผ๋กœ ์ž‘๋™ํ•ด์•ผ ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ๋‚˜๋ฅผ ์œ„ํ•ด ์ผํ•œ ์†”๋ฃจ์…˜์ž…๋‹ˆ๋‹ค.

describe('...', () => {
  const RealDate = Date;

  function mockDate(isoDate) {
    global.Date = class extends RealDate {
      constructor(...args) {
        if (args.length) return new RealDate(...args);
        return new RealDate(isoDate);
      }
    };
  }

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

  it('...', () => {
    mockDate('2018-01-01');
    // rest of the code
  });
})

global.Date์— ํ• ๋‹นํ•˜๋ ค๊ณ  ํ•  ๋•Œ๋งˆ๋‹ค ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

Error: Error: ReferenceError: Date is not defined
    at Object.<anonymous>.exportObject.JUnitXmlReporter.self.specDone (/src/node_modules/jasmine-reporters/src/junit_reporter.js:274:33)
    at dispatch (/src/node_modules/jest-jasmine2/build/jasmine/report_dispatcher.js:70:26)
    at ReportDispatcher.specDone (/src/node_modules/jest-jasmine2/build/jasmine/report_dispatcher.js:62:247)
    at Object.specResultCallback (/src/node_modules/jest-jasmine2/build/jasmine/Env.js:411:18)
    at Spec.attr.resultCallback (/src/node_modules/jest-jasmine2/build/setup_jest_globals.js:67:24)
    at complete (/src/node_modules/jest-jasmine2/build/jasmine/Spec.js:111:10)
    at currentRun.then (/src/node_modules/jest-jasmine2/build/jasmine/Spec.js:107:30)

๋ฌธ์ œ๋Š” ํ…Œ์ŠคํŠธ ์ปจํ…์ŠคํŠธ์—์„œ ์‹คํ–‰๋˜๋Š” JUnit ๋ฆฌํฌํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๊ณ  ์ต๋ช… ํด๋ž˜์Šค๊ฐ€ ํŒŒ๊ดด๋˜์–ด ์ด๋ฏธ ํŒŒ๊ดด๋œ Date๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์˜ˆ, ์œ„์˜ ๋ชจ๋“  ๊ฒƒ๊ณผ ๊ฐ™์€ ์ œ์•ˆ์„ ์‚ฌ์šฉํ•˜๋ฉด ์ „์—ญ ๋‚ ์งœ๊ฐ€ ์—‰๋ง์ด ๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋น„ํ‘œ์ค€ ๋ฆฌํฌํ„ฐ๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ๋งŒ ๋ฌธ์ œ๊ฐ€ ๋ฉ๋‹ˆ๋‹ค.

๊ธฐ์ž๋Š” ์ƒŒ๋“œ๋ฐ•์Šค ๋‚ด์—์„œ ์‹คํ–‰๋˜์–ด์„œ๋Š” ์•ˆ ๋ฉ๋‹ˆ๋‹ค. Jasmine ๊ธฐ์ž๋Š” ์˜๋„์ ์œผ๋กœ ์ง€์›๋˜์ง€ ์•Š๋Š” ์ผ๋ถ€ jasmime ํ•ญ๋ชฉ์— ์—ฐ๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์•„, ๊ทธ๋Ÿผ ์ด๋Ÿฐ ์ข…๋ฅ˜์˜ ์ฝ”๋“œ๋Š” ์ง€์›ํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๋ง์”€์ด์‹ ๊ฐ€์š”?

const jasmine = global.jasmine;
jasmine.getEnv().addReporter(junitReporter)

์—ฌ๊ธฐ์—์„œ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.
https://github.com/facebook/jest/blob/f9fd98fd4e38978e96a86f1c8796593cad7ac470/packages/jest-jasmine2/src/jasmine/ReportDispatcher.js#L63 -L72

๋งž์Šต๋‹ˆ๋‹ค, ๋‹น์‹ ์€ ์‚ฌ์šฉํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค
https://jestjs.io/docs/en/configuration#reporters -array-modulename-modulename-options.
์˜ˆ: https://github.com/jest-community/jest-junit

@niieani ,

"ํ†ตํ•ฉ" ํƒ€์ด๋จธ ๋ชจ์˜์— ๋Œ€ํ•œ ์†”๋ฃจ์…˜์€ ๋‹ค์Œ๊ณผ ๊ฐ™์ด jest ๋‚ด์žฅ ํ•จ์ˆ˜ ๋Œ€์‹  lolex ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋‚˜๋Š” ๊ทธ ์˜ˆ๋ฅผ ์‹œ๋„ํ–ˆ๊ณ  ๊ทธ ๊ฒฐ๊ณผ ๋‚ด ํ…Œ์ŠคํŠธ๊ฐ€ ์˜์›ํžˆ ์ค‘๋‹จ๋˜์—ˆ์Šต๋‹ˆ๋‹ค([email protected]์„ ์‚ฌ์šฉํ•˜๋Š” CRA์—์„œ). Jest์™€ ํ•จ๊ป˜ lolex๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์„ฑ๊ณตํ•œ ์‚ฌ๋žŒ์ด ์žˆ์Šต๋‹ˆ๊นŒ?

@kentcdodds ๋Š” ๋†๋‹ด ๊ฐ€์งœ ํƒ€์ด๋จธ๋ฅผ ๋™์‹œ์— ์‚ฌ์šฉํ•˜์ง€ ์•Š๋„๋ก ํ•ฉ๋‹ˆ๋‹ค. ์—ฌ์ „ํžˆ ๋ฉˆ์ถ”๋ฉด ์žฌ์ƒ์‚ฐ์— ๋ฌธ์ œ๋ฅผ ์ผ์œผํ‚ค์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ? ๋กค๋ ‰์Šค๋Š” ํ™•์‹คํžˆ ์ž‘๋™ํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค

์˜ˆ, ๊ณ ๋ฆฝ๋œ ์ƒํ™ฉ์—์„œ๋Š” ์ž˜ ์ž‘๋™ํ•˜๋ฏ€๋กœ ๋‹ค๋ฅธ ๊ณณ์—์„œ ์ด์ƒํ•œ ์ผ์„ ํ•˜๊ณ  ์žˆ๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๊ฐ์‚ฌ ํ•ด์š”!

์ด๋Ÿฌํ•œ ๊ฒฝ์šฐ๋งŒ ์กฐ๋กฑํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ:

new Date()
new Date('2018-09-20T23:00:00Z') 
const currentDate = new Date('2018-09-20T23:00:00Z');
Date = class extends Date {
  constructor(date) {
    if (date) {
        return super(date);
    }

    return currentDate;
  }
}

์ด๊ฒƒ์€ ์œ„์˜ ๋ชจ๋“  ๋‚ด์šฉ์„ ์ฝ์€ ํ›„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

let currentDate;

beforeAll(() => {
  currentDate = new Date();

  const RealDate = Date;
  global.Date = jest.fn(() => new RealDate(currentDate.toISOString()));
  Object.assign(Date, RealDate);
});

@samboylett ๊ฐ์‚ฌ

์ด๊ฒƒ์€ new Date()๋ฅผ ์กฐ๋กฑํ•˜๋Š” ๋ฐ ํšจ๊ณผ์ ์ด์—ˆ์Šต๋‹ˆ๋‹ค.

@petromoldovan ์€ ํ™•์‹คํžˆ ์ตœ๊ณ ์˜ ๋‹ต๋ณ€์ž…๋‹ˆ๋‹ค.

ํ…Œ์ŠคํŠธ๊ฐ€ ๋๋‚  ๋•Œ mockRestore ์— ๋Œ€ํ•œ ํ˜ธ์ถœ์„ ์ถ”๊ฐ€ํ•˜์—ฌ ์›๋ž˜ ๋‚ ์งœ๋ฅผ ๋ณต์›ํ•ฉ๋‹ˆ๋‹ค.

const dateNowMockFn = jest.spyOn(Date, 'now').mockImplementation(() => 1479427200000);
// ... code with tests
dateNowMockFn.mockRestore();

๋ชจ์˜ ๊ฐ์ฒด๊ฐ€ ์ƒˆ ํด๋ž˜์Šค ์ค‘ ํ•˜๋‚˜ ๋Œ€์‹  Date ์ธ์Šคํ„ด์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋„๋ก ํ•˜๋ ค๋Š” ๊ฒฝ์šฐ์— ๋Œ€๋น„ํ•˜์—ฌ @vcarel ์†”๋ฃจ์…˜์„ ์•ฝ๊ฐ„ ๊ฐœ์„ 

    const RealDate = Date

    const mockDate = (isoDate) => {
      global.Date = class extends RealDate {
        constructor () {
          return super(isoDate)
        }
      }
    }

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

๋‚˜๋Š” ์—ฌ๊ธฐ์—์„œ ํ’์ฐจ๋ฅผ ๋ฐ”๋ผ๋ณด๊ณ  ์žˆ์„์ง€ ๋ชจ๋ฅด์ง€๋งŒ ์˜ค๋ž˜๋œ ๊ฒฉ์–ธ์„ ์ง€์ ํ•  ๊ฐ€์น˜๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค .

const myFunc = (msg, date = new Date()) => console.log(`${msg}! ${date}`);

์ด์ œ ํ”„๋กœ๋•์…˜ ์ฝ”๋“œ์—์„œ ๊ธฐ๋ณธ๊ฐ’์„ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

myFunc("Hello"); // => Hello! Fri Mar 22 2019 21:11:26 GMT-0400 (EDT)

๊ทธ๋ฆฌ๊ณ  ํ…Œ์ŠคํŠธ ์ฝ”๋“œ์—์„œ ๋‚ ์งœ๋ฅผ ๋ช…์‹œ์ ์œผ๋กœ ์ „๋‹ฌํ•˜์—ฌ ์ด๋ฅผ ์กฐ๋กฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

myFunc("Hello", dateObj) // => Hello! ...

@yawaramin ์ด๊ฒƒ์— ๋Œ€ํ•ด์„œ๋Š” ํ™•์‹คํžˆ ๋ช‡ ๊ฐ€์ง€ ๋‹ค๋ฅธ ๊ด€์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ํ…Œ์ŠคํŠธ๊ฐ€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ฝ”๋“œ๋ฅผ ์œ„ํ•ด ์กด์žฌํ•ด์•ผ ํ•œ๋‹ค๊ณ  ๋ฏฟ๋Š” ์ง„์˜์ด ์žˆ๊ณ , ๊ผฌ๋ฆฌ๊ฐ€ ๊ฐœ๋ฅผ ํ”๋“œ๋Š” ๊ณผ๊ฑฐ ์ง€์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค(Pete Hunt๋Š” ์ด์— ๋Œ€ํ•ด ๊ฐ•ํ•œ ์˜๊ฒฌ ์„ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค)

์ œ์•ˆํ•œ ๋ฐฉ๋ฒ•์ด ์œ ํšจํ•œ ์˜ต์…˜์ด ์•„๋‹ˆ๋ผ๊ณ  ๋งํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ์ƒํ™ฉ์— ๋”ฐ๋ผ ์ ์ ˆํ•œ ๋ฐฉ๋ฒ•์œผ๋กœ ์ œ์‹œ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

@cheapsteak ์ƒํ™ฉ์  ์ ์ ˆ์„ฑ์ด ์‚ฌ๋ฌผ์˜ ๊ธฐ๋ณธ ์ƒํƒœ๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์‚ฌ๋žŒ๋“ค์—๊ฒŒ ํ•ญ์ƒ ํ…Œ์ŠคํŠธ ๊ฐ€๋Šฅ์„ฑ์„ ๊ฐœ์„ ํ•  ๊ธฐํšŒ๊ฐ€ ์žˆ์œผ๋ฉฐ ๊ทธ๋ ‡๊ฒŒ ํ•˜๋ฉด ์ผ๋ฐ˜์ ์œผ๋กœ ์œ ์ง€ ๊ด€๋ฆฌ ๊ฐ€๋Šฅ์„ฑ์ด ํ–ฅ์ƒ๋œ๋‹ค๋Š” ์ ์„ ๋ถ€๋“œ๋Ÿฝ๊ฒŒ ์ƒ๊ธฐ์‹œํ‚ค๋Š” ๊ฒƒ์€ ๋‚˜์˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค :-)

ํƒ€์ด๋จธ๋ฅผ ๋ฐœ์†กํ•  ๋•Œ ๋†๋‹ด์˜ ํ˜„์žฌ ์‹œ๊ฐ„์„ ์–ป๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๊นŒ? jest.now์™€ ๊ฐ™์€ ๊ฒƒ?

Date.now()์— ๋Œ€ํ•œ ํƒ€์ด๋จธ์™€ ํ˜ธ์ถœ์ด ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•ฉ๋‹ˆ๋‹ค. jest.runAllTimers()๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค. ํƒ€์ด๋จธ ์ฝœ๋ฐฑ์ด ์‹คํ–‰๋˜๊ณ  ์‹œ๋ฎฌ๋ ˆ์ด์…˜๋œ ์‹œ๊ฐ„์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋„๋ก jest.spyOn(Date, 'now').mockImplementation(() => something )์„ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด ๋ฉ‹์งˆ

๋‚˜๋Š” Date.now() ๋ฅผ ์กฐ๋กฑํ•ด์•ผ ํ–ˆ๋‹ค

๊ตฌ์„ฑ์—์„œ ๋˜๋Š” ํ…Œ์ŠคํŠธ๊ฐ€ ์ž‘๋™ํ•˜๊ธฐ ์ „์— ์•„๋ž˜ ์ค„์„ ์„ค์ •ํ•˜์‹ญ์‹œ์˜ค.

jest.spyOn(Date, 'now').mockImplementation(() => 1479427200000)

๋งŽ์€ ์‚ฌ๋žŒ๋“ค์—๊ฒŒ ํšจ๊ณผ๊ฐ€ ์žˆ์ง€๋งŒ ๋‚˜์—๊ฒŒ๋Š” ๊ทธ๋ ‡์ง€ ์•Š์€ ๋ฐฉ๋ฒ•์ด ์žฌ๋ฏธ์žˆ์Šต๋‹ˆ๋‹ค. ํ .

๋ฌด์Šจ ์ผ์ด ์ผ์–ด๋‚˜๊ณ  ์žˆ๋Š”์ง€ ๋ชจ๋ฅด๊ฒ ์ง€๋งŒ Date ์žฌํ• ๋‹นํ•˜๋Š” ๋ฐฉ๋ฒ•์— ์ƒ๊ด€์—†์ด Date.now() ํ•ญ์ƒ ์กด์žฌํ•˜๋ฉฐ ํ•ญ์ƒ ์œ ํšจํ•œ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

Date.now = null ๋Š” ์•„๋ฌด ์ž‘์—…๋„ ์ˆ˜ํ–‰ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
global.Date.now = null ๋Š” ์•„๋ฌด ์ž‘์—…๋„ ์ˆ˜ํ–‰ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
jest.spyOn(Date, 'now').mockImplementation(() => 1479427200000); ๋Š” ์•„๋ฌด ์ž‘์—…๋„ ์ˆ˜ํ–‰ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
lolex ์„ค์น˜ ๋ฐ ์‚ฌ์šฉ์€ ์‹œ๊ฐ„ ์ดˆ๊ณผ ์‹œ ์ž‘๋™ํ•˜์ง€๋งŒ Date.now() ์—๋Š” ์˜ํ–ฅ์„ ๋ฏธ์น˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
MockDate ๋Š” ํšจ๊ณผ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” ๋ถ„๋ช…ํ•œ ๊ฒƒ์„ ๋†“์น˜๊ณ  ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ์ข…์†์„ฑ์ด ๋ญ”๊ฐ€๋ฅผ ํ•˜๊ณ  ์žˆ๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค... ๋„ˆ๋ฌด ํ˜ผ๋ž€์Šค๋Ÿฝ์Šต๋‹ˆ๋‹ค.

@mherodev ๋Š” ํ…Œ์ŠคํŠธ๋ฅผ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค. ํ…Œ์ŠคํŠธ ๊ธฐ๋Šฅ์ด ์‹คํ–‰๋˜๊ธฐ ์ „์— / ๊ตฌ์„ฑ ์š”์†Œ๊ฐ€ ๋ Œ๋”๋ง๋˜๊ธฐ ์ „์— ๋ชจ์˜ ๋‚ ์งœ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๊นŒ?

ํ…Œ์ŠคํŠธ ๋ธ”๋ก ๋‚ด์—์„œ ๋‚˜๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ผ์„ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค ...

      Date.now = () => 1;
      Date = null;
      global.Date = null;
      console.log(`Date.now()`, Date.now()); // Date.now() 1560239936091

๊ทธ๋Ÿฌ๋‚˜ ๊ทธ ์žฌ์ •์˜๋Š” ์•„๋ฌด ๊ฒƒ๋„ ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ๊ทธ๊ฒƒ์ด ๋งค์šฐ ํ˜ผ๋ž€์Šค๋Ÿฝ๋‹ค๊ณ  ์ƒ๊ฐํ•œ๋‹ค.

๋‚˜๋Š” Hugo์˜ ํŠœํ† ๋ฆฌ์–ผ์„ ๋”ฐ๋ž๊ณ  ๊ฒฐ๊ตญ ๋‹ค์Œ์„ ์ˆ˜ํ–‰ํ–ˆ์Šต๋‹ˆ๋‹ค.

  // @ts-ignore
  .spyOn(global.Date, 'constructor')
  .mockImplementationOnce(() => new Date('2019-06-19T00:07:19.309Z'))

๋”ฐ๋ผ์„œ new Date() ๋Š” ํ•ญ์ƒ new Date('2019-06-19T00:07:19.309Z') ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

์—…๋ฐ์ดํŠธ: ๋‚ด ํ™˜๊ฒฝ์—์„œ babel์ด ์–ด๋–ป๊ฒŒ ๋ณ€ํ™˜๋˜๋Š”์ง€์— ๋Œ€ํ•œ ๋ฒ„๊ทธ๋กœ ์ธํ•ด ๋‚ด Date ๋ชจ์˜๊ฐ€ ์ž‘๋™ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. @babel/runtime-corejs2 ์‚ฌ์šฉ ๋ฐฉ๋ฒ•๊ณผ ๊ด€๋ จ๋œ ๊ฒƒ

๊ถ๊ทน์ ์ธ ์†”๋ฃจ์…˜: jest-date-mock .

  • ์„ค์น˜

jest ์•„๋ž˜์˜ package.json์—์„œ setupFiles ๋ฐฐ์—ด์„ ๋งŒ๋“ค๊ณ  ๋ฐฐ์—ด์— jest-date-mock์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

{
  "jest": {
    "setupFiles": ["./__setups__/other.js", "jest-date-mock"]
  }
}
  • ์šฉ๋ฒ•

ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค์˜ ํ˜„์žฌ ํƒ€์ž„์Šคํƒฌํ”„๋ฅผ ์ œ์–ดํ•˜๋Š” โ€‹โ€‹๊ฐ„๋‹จํ•œ API๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

import { advanceBy, advanceTo, clear } from 'jest-date-mock';

test('usage', () => {
  advanceTo(new Date(2018, 5, 27, 0, 0, 0)); // reset to date time.

  const now = Date.now();

  advanceBy(3000); // advance time 3 seconds
  expect(+new Date() - now).toBe(3000);

  advanceBy(-1000); // advance time -1 second
  expect(+new Date() - now).toBe(2000);

  clear();
  Date.now(); // will got current timestamp
});

๋‚ด ์ƒ๊ฐ์—: ๋‹ค๋ฅธ ๋ชจ๋“  ์†”๋ฃจ์…˜์€ ์ฒด๊ณ„์ ์ด์ง€ ์•Š๊ฑฐ๋‚˜ ์ผ์‹œ์ ์ด์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

babel ๋ณ€ํ™˜์ด ์ด์ „ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์„ ๊นจ๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ž…๋‹ˆ๋‹ค.

๋‚ด ์†”๋ฃจ์…˜์€ setupMockDate.js ๋ผ๋Š” ์ƒˆ ํŒŒ์ผ์„ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

const mockDate = DateClass => {
  function Mock(...args) {
    return args.length === 0
      ? new DateClass(Mock.now())
      : new DateClass(...args)
  }
  Object.setPrototypeOf(Mock, DateClass)
  Mock.prototype = DateClass.prototype
  let now
  Mock.now = () => now === undefined ? DateClass.now() : now
  Mock.mockNow = value => now = value
  Mock.mockRestore = () => Mock.mockNow()
  return Mock
}
global.Date = mockDate(Date)

setupFilesAfterEnv ํ•ญ๋ชฉ์˜ jest.config.js (๋˜๋Š” ์ด์ „ jest ๋ฒ„์ „์˜ ๊ฒฝ์šฐ setupFiles )์— '<rootDir>/jest/setupMockDate.js' ํ•ฉ๋‹ˆ๋‹ค.

์ด์ œ, ๋‹น์‹ ์€ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค

Date.mockNow(10)
expect(Date.now()).toBe(10)
Date.mockRestore()
expect(Date.now()).not.toBe(10)

Sinon์€ ์ €์—๊ฒŒ ์ž˜ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. https://sinonjs.org/releases/v1.17.7/fake-timers/

ํŒŒํ‹ฐ์— ๋Šฆ์—ˆ์ง€๋งŒ jest์—๋Š” ํ•„์š”ํ•œ ๋ชจ๋“  ๊ธฐ๋Šฅ์ด ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

describe('how to mock date.now()', function() {
  beforeEach(() => {
    this.timestamp = 0
    global.Date.now = jest.fn().mockImplementation(() => this.timestamp)
  })

  afterEach(() => {
    jest.clearAllMocks()
  })

  it('can advance in time', () => {
    const then = Date.now()

    this.timestamp += 1000

    const now = Date.now()

    expect(now - then).toBe(1000)
  })

๋‚˜๋Š” vue-moment์™€ jest๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์œผ๋ฉฐ ๊ฐ€์žฅ ์ข‹์€ ๋ฐฉ๋ฒ•์€ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

import { mount, createLocalVue } from '@vue/test-utils';
import TripList from 'components/trip-list.vue';

const localVue = createLocalVue();
localVue.use(require('vue-moment'));

describe('TripList', () => {

it('text shows current date', () => {
    const myDate = new Date(2019, 5, 5);

    const wrapper = mount(TripList, {
      localVue,
    });

    wrapper.vm.$moment.now = () => myDate;
    wrapper.vm.$forceUpdate();

    expect(wrapper.html()).toContain('Thu, Oct 3rd');
  });
})

ES6 ์‚ฌ์šฉ

const fixedDate = new Date('2019-03-1');
const RealDate = Date;

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

Date.now()

const dateSpy = jest.spyOn(Date, 'now');
dateSpy.mockReturnValue(TIMESTAMP);

์ด๊ฒƒ์œผ๋กœ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ๋‹ค๋ฅธ ์‚ฌ๋žŒ์˜ ๊ฒฝ์šฐ ์ „์—ญ Date ๊ฐ์ฒด์— ์ƒ์„ฑ์ž ์ด์™ธ์˜ ์†์„ฑ์ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋ช‡ ๊ฐ€์ง€ ๋ฌธ์ œ๊ฐ€ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ๋‹ค์Œ์„ ์ˆ˜ํ–‰ํ–ˆ๋‹ค.

const DATE_TO_USE = new Date('2016');
const _Date = Date;
global.Date = jest.fn(() => DATE_TO_USE);
global.Date.UTC = _Date.UTC;
global.Date.parse = _Date.parse;
global.Date.now = _Date.now;

๋‚˜๋Š” ์ „์ฒด Date ํด๋ž˜์Šค๋ฅผ ์กฐ๋กฑํ•˜๊ณ  ์‹ถ์—ˆ๊ณ  @kristojorg๊ฐ€ ์ œ์•ˆํ•œ ๋ฐฉ๋ฒ•์ด ์ด์ƒ์ ์œผ๋กœ ๋ณด์˜€์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” ํ™•์‹คํ•˜์ง€์ด ๊ทธ๊ฒƒ์„ ํ•  ์ˆ˜์žˆ๋Š” ์ ์ ˆํ•œ ๋ฐฉ๋ฒ•์ด์ง€๋งŒ,์ด ์†”๋ฃจ์…˜์€ @nilobarp์—์„œ ์–ธ๊ธ‰ ํ•œ ๋ฐ”์™€ ๊ฐ™์ด ํƒ€์ดํ•‘ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜์—ฌ ํƒ€์ดํ”„์— ๋ฒŒ๊ธˆ์„ ์ž‘๋™ํ•˜๋Š” ๊ฒฝ์šฐ์ž…๋‹ˆ๋‹ค :

describe('Mock Date', () => {
  const realDateNow = Date.bind(global.Date);

  beforeAll(() => {
    // Fix the time to 2020-1-1 1hr:1min:1sec in order to match
    // snapshots for the DownloadConfirmDialog component.
    const fixedDate = new Date(2020, 0, 1, 1, 1, 1);
    const d = Date;

    // This will only mock any Date objects instantiated with new 
    // and not Date.now().
    const _global: NodeJS.Global = global;
    _global.Date = jest.fn(() => fixedDate);
    _global.Date.parse = d.parse;
    _global.Date.UTC = d.UTC;
    _global.Date.now = d.now;
  });

  it('shows mocked date', () => {
    // Shows 2020-01-01T01:01:01.000Z as the current Date
    // for an instantiated Date object.
    console.log(new Date().toISOString());
  });

  afterAll(() => {
    // Reverts to the current Date object.
    global.Date = realDateNow;
    console.log(new Date().toISOString());
  });
});

์ด๊ฒƒ์€ ์ƒˆ๋กœ์šด Date ๊ฐœ์ฒด๋ฅผ ์ธ์Šคํ„ด์Šคํ™”ํ•  ๋•Œ๋งŒ ์ž‘๋™ํ•˜๊ณ  Date.now() ์—์„œ๋Š” ์ž‘๋™ํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ์ ์„ ์–ธ๊ธ‰ํ•  ๊ฐ€์น˜๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. Date.now์— ๋Œ€ํ•œ

ํ…Œ์ŠคํŠธ ๋ธ”๋ก ๋‚ด์—์„œ ๋‚˜๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ผ์„ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค ...

      Date.now = () => 1;
      Date = null;
      global.Date = null;
      console.log(`Date.now()`, Date.now()); // Date.now() 1560239936091

๊ทธ๋Ÿฌ๋‚˜ ๊ทธ ์žฌ์ •์˜๋Š” ์•„๋ฌด ๊ฒƒ๋„ ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ๊ทธ๊ฒƒ์ด ๋งค์šฐ ํ˜ผ๋ž€์Šค๋Ÿฝ๋‹ค๊ณ  ์ƒ๊ฐํ•œ๋‹ค.

๋™์ผํ•œ ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๋ฌธ์ œ์—์„œ ๋ฐœ๊ฒฌ๋œ ์ „์ฒด ์ฝ”๋“œ ์˜ˆ์ œ๋ฅผ ํ…Œ์ŠคํŠธํ–ˆ์ง€๋งŒ ์•„๋ฌด ๊ฒƒ๋„ ํšจ๊ณผ๊ฐ€ ์—†์—ˆ์Šต๋‹ˆ๋‹ค. mock์€ ๋ฌด์‹œ๋œ ๊ฒƒ์œผ๋กœ ๋ณด์ž…๋‹ˆ๋‹ค.

๋ฌธ์ œ๋ฅผ ์–ด๋–ป๊ฒŒ ํ•ด๊ฒฐํ–ˆ์Šต๋‹ˆ๊นŒ?

์šฐ๋ฆฌ๋Š” ๋˜ํ•œ Babel์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์œผ๋ฏ€๋กœ ์ด๊ฒƒ ์—ญ์‹œ ๊ด€๋ จ์ด ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ…Œ์ŠคํŠธ ๋ธ”๋ก ๋‚ด์—์„œ ๋‚˜๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ผ์„ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค ...

      Date.now = () => 1;
      Date = null;
      global.Date = null;
      console.log(`Date.now()`, Date.now()); // Date.now() 1560239936091

๊ทธ๋Ÿฌ๋‚˜ ๊ทธ ์žฌ์ •์˜๋Š” ์•„๋ฌด ๊ฒƒ๋„ ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ๊ทธ๊ฒƒ์ด ๋งค์šฐ ํ˜ผ๋ž€์Šค๋Ÿฝ๋‹ค๊ณ  ์ƒ๊ฐํ•œ๋‹ค.

๋™์ผํ•œ ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๋ฌธ์ œ์—์„œ ๋ฐœ๊ฒฌ๋œ ์ „์ฒด ์ฝ”๋“œ ์˜ˆ์ œ๋ฅผ ํ…Œ์ŠคํŠธํ–ˆ์ง€๋งŒ ์•„๋ฌด ๊ฒƒ๋„ ํšจ๊ณผ๊ฐ€ ์—†์—ˆ์Šต๋‹ˆ๋‹ค. mock์€ ๋ฌด์‹œ๋œ ๊ฒƒ์œผ๋กœ ๋ณด์ž…๋‹ˆ๋‹ค.

๋ฌธ์ œ๋ฅผ ์–ด๋–ป๊ฒŒ ํ•ด๊ฒฐํ–ˆ์Šต๋‹ˆ๊นŒ?

์šฐ๋ฆฌ๋Š” ๋˜ํ•œ Babel์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์œผ๋ฏ€๋กœ ์ด๊ฒƒ ์—ญ์‹œ ๊ด€๋ จ์ด ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

@warpdesign ์ด ์†”๋ฃจ์…˜์€ TypeScript์˜ Jest์™€ ํ•จ๊ป˜ ์ž‘๋™ํ•˜๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

describe('Mock Date.now', () => {
  // Bind to the original Date so we can set it back after all tests are finished.
  const realDateNow = Date.now.bind(global.Date);

  beforeAll(() => {
    // Return 1 millisecond when calling Date.now() in tests.
    const dateNowStub = jest.fn(() => 1);
    global.Date.now = dateNowStub;
  });

  it('shows mocked date', () => {
    console.log(Date.now());  // Returns 1.
  });

  afterAll(() => {
    // Set back to the original Date object.
    global.Date.now = realDateNow;
    console.log(Date.now()); // Returns current time in milliseconds.
  });
});

Jest์˜ ํ˜„์žฌ Date ๋ฅผ

๊ถ๊ทน์ ์ธ ์†”๋ฃจ์…˜: jest-date-mock .

  • ์„ค์น˜

jest ์•„๋ž˜์˜ package.json์—์„œ setupFiles ๋ฐฐ์—ด์„ ๋งŒ๋“ค๊ณ  ๋ฐฐ์—ด์— jest-date-mock์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

{
  "jest": {
    "setupFiles": ["./__setups__/other.js", "jest-date-mock"]
  }
}
  • ์šฉ๋ฒ•

ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค์˜ ํ˜„์žฌ ํƒ€์ž„์Šคํƒฌํ”„๋ฅผ ์ œ์–ดํ•˜๋Š” โ€‹โ€‹๊ฐ„๋‹จํ•œ API๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

import { advanceBy, advanceTo, clear } from 'jest-date-mock';

test('usage', () => {
  advanceTo(new Date(2018, 5, 27, 0, 0, 0)); // reset to date time.

  const now = Date.now();

  advanceBy(3000); // advance time 3 seconds
  expect(+new Date() - now).toBe(3000);

  advanceBy(-1000); // advance time -1 second
  expect(+new Date() - now).toBe(2000);

  clear();
  Date.now(); // will got current timestamp
});

๋‚ด ์ƒ๊ฐ์—: ๋‹ค๋ฅธ ๋ชจ๋“  ์†”๋ฃจ์…˜์€ ์ฒด๊ณ„์ ์ด์ง€ ์•Š๊ฑฐ๋‚˜ ์ผ์‹œ์ ์ด์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค!

๋‚˜๋Š” Hugo์˜ ํŠœํ† ๋ฆฌ์–ผ์„ ๋”ฐ๋ž๊ณ  ๊ฒฐ๊ตญ ๋‹ค์Œ์„ ์ˆ˜ํ–‰ํ–ˆ์Šต๋‹ˆ๋‹ค.

  // @ts-ignore
  .spyOn(global.Date, 'constructor')
  .mockImplementationOnce(() => new Date('2019-06-19T00:07:19.309Z'))

๋”ฐ๋ผ์„œ new Date() ๋Š” ํ•ญ์ƒ new Date('2019-06-19T00:07:19.309Z') ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

์ด ์‚ฌ๋žŒ์€ ๋ฌด์Šจ ๊ฐœ์†Œ๋ฆฌ์•ผ. U๋Š” Hugo์˜ ํŠœํ† ๋ฆฌ์–ผ์„ ๋งํ•˜๊ณ  Hugo๋Š” ๋‹น์‹ ์˜ ํŠœํ† ๋ฆฌ์–ผ์„ ๋งํ•ฉ๋‹ˆ๋‹ค.... ์ œ๋ฐœ ์šฐ๋ฆฌ๋ฅผ ์˜ค๋„ํ•˜์ง€ ๋งˆ์‹ญ์‹œ์˜ค.

Jest 26์€ ์ตœ์‹  ๊ฐ€์งœ ํƒ€์ด๋จธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ Date ์กฐ๋กฑ์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค. https://jestjs.io/blog/2020/05/05/jest-26#new -fake-timers

TS์—์„œ Date ์ƒ์„ฑ์ž๋ฅผ ์กฐ๋กฑํ•˜๋Š” ๋ฐ ์–ด๋ ค์›€์„ ๊ฒช๊ณ  ์žˆ๋‹ค๋ฉด ๋‹ค์Œ์„ ์‹œ๋„ํ•˜์‹ญ์‹œ์˜ค.

const mockDate = new Date('Tue, 23 Jun 2020 14:34:56');
const RealDate = Date;
(global as any).Date = class extends RealDate {
  constructor() {
    super();
    return mockDate;
  }
};

// test some date related functionality

global.Date = RealDate;

Jest 26์€ ์ตœ์‹  ๊ฐ€์งœ ํƒ€์ด๋จธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ Date ์กฐ๋กฑ์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค. https://jestjs.io/blog/2020/05/05/jest-26#new -fake-timers

@SimenB ํ›Œ๋ฅญํ•˜๊ณ  ๋ฐฉ๊ธˆ v26์œผ๋กœ ์—…๋ฐ์ดํŠธํ–ˆ์ง€๋งŒ

@gregveres ๋‹ค์Œ์€ ์‹œ์Šคํ…œ ์‹œ๊ฐ„( Date ๋ฉ”์„œ๋“œ)์„ ๊ณ ์ • ๋‚ ์งœ๋กœ ์„ค์ •ํ•˜๊ณ  ํ•ด๋‹น ์‹œ๊ฐ„์„ ์•ž๋‹น๊ธฐ๋Š” ๊ฒƒ์„ ์ฒ˜๋ฆฌํ•˜๋Š” ์˜ˆ์ œ ํ…Œ์ŠคํŠธ ๋ชจ์Œ์ž…๋‹ˆ๋‹ค.

const FIXED_SYSTEM_TIME = '2020-11-18T00:00:00Z';

describe('Set Fixed Date', () => {
    beforeEach(() => {
        jest.useFakeTimers('modern');
        jest.setSystemTime(Date.parse(FIXED_SYSTEM_TIME));
    });

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

    it('Should reflect fixed date', () => {
        expect(new Date().toISOString()).toEqual(FIXED_SYSTEM_TIME);

        const MS_TO_ADVANCE = 5000;

        jest.advanceTimersByTime(MS_TO_ADVANCE);

        expect(new Date().toISOString()).toEqual(new Date(Date.parse(FIXED_SYSTEM_TIME) + MS_TO_ADVANCE).toISOString());
    });
});

_์—…๋ฐ์ดํŠธ: ์•„๋ž˜ @alexdanilowicz ์˜ ๋Œ“๊ธ€๋‹น afterEach() ํฌํ•จ._

2020๋…„ 11์›”๋ถ€ํ„ฐ ์—…๋ฐ์ดํŠธ

_์ด ์Šค๋ ˆ๋“œ๊ฐ€ ์˜ค๋ž˜๋˜๊ณ  ์ธ๊ธฐ ์žˆ๋Š” stackoverflow ๊ฒŒ์‹œ๋ฌผ์— ์—ฐ๊ฒฐ๋จ์— ๋”ฐ๋ผ ^ ๊ตต๊ฒŒ ํ‘œ์‹œ_

@seansullivan ๊ต‰์žฅํ•ฉ๋‹ˆ๋‹ค! ์ฐธ๊ณ ๋กœ, ์ œ๊ฐ€ ํ‹€๋ ธ๋‹ค๋ฉด ์ •์ •ํ•ด ์ฃผ์„ธ์š”. ํ•˜์ง€๋งŒ ์‚ฌ์–‘์— afterEach(๋˜๋Š” afterAll)๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ๋‚ ์งœ๋ฅผ ๋‹ค์‹œ ํ˜„์‹ค๋กœ ๋˜๋Œ๋ฆฌ๋Š” ๊ฒƒ์ด ์ข‹์„ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๋‹จ์ง€ ์•ˆ์ „ํ•˜๊ธฐ ์œ„ํ•ด์„œ์ž…๋‹ˆ๋‹ค.

describe('Test', () => {
  // to avoid race conditions between expected and actual date values
  beforeAll(() => {
    jest.useFakeTimers('modern'); // tell Jest to use a different timer implementation.
    jest.setSystemTime(new Date('20 Aug 2020 00:12:00 GMT').getTime())
  });

  afterAll(() => {
    // Back to reality...
    jest.useRealTimers();
  });

@alexdanilowicz ์™„๋ฒฝํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ, ๋‚˜๋Š” ๋‚ด ์˜ˆ์— ์ •๋ฆฌ๋ฅผ ํฌํ•จํ•˜๋Š” ๊ฒƒ์„ ๊ฒŒ์„๋ฆฌํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด ์Šค๋ ˆ๋“œ๋ฅผ ์ฐพ๋Š” ๋ชจ๋“  ์‚ฌ๋žŒ์ด ์˜จ์ „ํ•œ ์ƒํƒœ๋ฅผ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ๋„๋ก afterEach() ๋กœ ์—…๋ฐ์ดํŠธํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ๊ฐ์‚ฌ ํ•ด์š”!

์ด ํŽ˜์ด์ง€๊ฐ€ ๋„์›€์ด ๋˜์—ˆ๋‚˜์š”?
0 / 5 - 0 ๋“ฑ๊ธ‰