Jest: Имитация текущего времени для Date

Созданный на 6 дек. 2016  ·  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 - не лучший опыт.

Решением для имитации «унифицированных» таймеров было использование встроенных команд lolex вместо jest , например:

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() , который является полезными часами, работающими только в прямом направлении (т.е. не будет возвращен пользователем, изменяющим DateTime своей системы).

На самом деле в Jest это не работает. Jest использует Jasmine v1.5.2-lite, поэтому у него нет часов. Я использую lolex .

Date.now() достаточно хорош для большинства приложений, permofrmance.now() его еще нет в узле - например, нельзя использовать в SSR - так что это не кажется большой проблемой.

Конечно, lolex не интегрирован с шуткой.

@drpicox а, хорошо знать, что тогда это не работает.
performance.now() присутствует в узле, как я полагаю, начиная с версии 8.5.0. Вы можете импортировать performance из встроенного модуля 'perf_hooks' .

Тем не менее, учитывая текущую ситуацию и количество получаемых голосов / комментариев, я хотел бы пинговать @cpojer, чтобы рассмотреть возможность повторного открытия этого вопроса.

FWIW Я бы хотел интегрировать lolex - это единственная библиотека, которую я использую, где, как мне кажется, в Jest отсутствует батарея

@cpojer В любом случае, мы можем открыть это заново. На данный момент на самом деле нет способа имитировать свидание И имитировать течение времени простым способом.

У жасмина есть класс часов, в котором вы можете издеваться над датой И временем заранее с помощью:

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

Если вам нужно издеваться над Датой вне тестовой среды. Мне нужно было сделать предсказуемые снимки пользовательского интерфейса, где отображается дата.

Это сработало для меня:
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 - это просто прокси-переменная для соответствия машинописному тексту.

Мне нужно было издеваться над Date.now()

установка следующей строки в конфигурации или до того, как тесты сработали для меня:

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

Мне понравился подход @vcarel , но в моем случае конструктор Date в некоторых случаях использовался с аргументами, поэтому мне нужно было изменить его, чтобы он принимал другие даты. Я также добавил Date.now ()

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 = class extends Date {
constructor () {
супер()
return constantDate
}
}
})
~~~

Просто хотелось бы немного добавить к ответам @callemo и @iwarner .

Вероятно, менее подвержено ошибкам делать что-то вроде, поскольку он каждый раз возвращает новый экземпляр даты:

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

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

Это позволяет использовать функции, которые изменяют объекты даты (например, setMinutes), без изменения constantDate и, таким образом, изменения даты, возвращаемой из new 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;
  });
});

Может, тебе нужна шутка-насмешка на свидании .

Предоставляет вам простой 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
});

Приведенные выше решения не охватывают мой вариант использования. Я сделал следующее на основе @callemo, в котором отсутствовала поддержка instanceof и установка конкретных дат.

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 .

Поддерживается новая версия 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 могут подключиться к каким-то жасмимовым вещам, которые целенаправленно не поддерживаются, хотя

О, так вы говорите, что такой код не поддерживается?

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 ,

Решением для имитации «унифицированных» таймеров было использование встроенных команд lolex вместо jest , например:

Я попробовал этот пример, и в результате мои тесты зависли навсегда (в CRA, который использует [email protected]). У кого-нибудь есть успех при использовании lolex с Jest?

@kentcdodds не используйте одновременно фальшивые таймеры. Если он все еще зависает, не могли бы вы создать проблему с воспроизведением? Lolex определенно должен работать

Да, в изолированной ситуации у меня все работает нормально, так что я, вероятно, делаю что-то странное в другом месте. Спасибо!

Если вам нужно только поиздеваться над этими случаями:

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

Это сработало для меня в издевательстве над новой датой ()

@petromoldovan - определенно лучший ответ.

Добавьте вызов mockRestore в конце тестов, чтобы восстановить исходную дату:

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

Немного улучшено решение

    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 По этому твердо придерживается мнения по этому поводу)

Я не говорю, что предложенный вами метод не является допустимым вариантом, но, возможно, его можно было бы представить как ситуационно подходящий способ.

@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

Но это переопределение ничего не делает. Я нахожу это очень запутанным.

Я последовал руководству Хьюго и в итоге сделал:

  // @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')

Обновление: похоже, мои макеты Date не работали из-за ошибки, связанной с переносом babel в мою среду. Что-то связанное с тем, как мы используем @babel/runtime-corejs2

Окончательное решение: шутка-свидание-макет .

  • установить

В вашем package.json в разделе jest создайте массив 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)

В jest.config.js при входе setupFilesAfterEnv (или setupFiles в старой версии jest) добавьте '<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, казался идеальным.

Я не уверен, что это подходящий способ, но эти решения отлично работают в TypeScript, исправляя проблему с набором текста, как указано в @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

Но это переопределение ничего не делает. Я нахожу это очень запутанным.

У меня та же проблема: протестировал целую кучу примеров кода, найденных в этой проблеме, и ни один из них не помог мне: похоже, макет игнорируется.

Как ты решил свою проблему?

Мы также используем Babel, так что это тоже может быть связано.

Внутри тестового блока я делаю что-то вроде ...

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

Но это переопределение ничего не делает. Я нахожу это очень запутанным.

У меня та же проблема: протестировал целую кучу примеров кода, найденных в этой проблеме, и ни один из них не помог мне: похоже, макет игнорируется.

Как ты решил свою проблему?

Мы также используем Babel, так что это тоже может быть связано.

@warpdesign это решение, похоже, работает для меня с Jest в TypeScript.

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 .

Окончательное решение: шутка-свидание-макет .

  • установить

В вашем package.json в разделе jest создайте массив 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
});

Я думаю: все остальные решения не являются систематическими или временными.

Спасибо, сработало !!

Я последовал руководству Хьюго и в итоге сделал:

  // @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')

Что за хрень этот человек. Вы говорите учебник Хьюго, а Хьюго говорит ваш .... пожалуйста, не вводите нас в заблуждение.

Jest 26 поддерживает имитацию Date с использованием современных фальшивых таймеров: https://jestjs.io/blog/2020/05/05/jest-26#new -fake-timers

Если вы застряли в попытках имитировать конструктор Date в TS, попробуйте следующее:

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 Это здорово, я только что обновился до версии 26, но не могу понять, как мы используем шутку, чтобы имитировать дату. Документы-шутки говорят только о том, как имитировать таймеры, чтобы вы могли протестировать setTimeOut, но как вы это делаете, чтобы имитировать «new Date ()»?

@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());
    });
});

_Update: Included afterEach() за @alexdanilowicz «s комментарий below._

Обновление от ноября 2020 г.

_Bolding, что ^ поскольку этот поток стареет и связан с популярным сообщением 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 рейтинги

Смежные вопросы

iffy picture iffy  ·  137Комментарии

eldh picture eldh  ·  84Комментарии

SimenB picture SimenB  ·  131Комментарии

benmonro picture benmonro  ·  119Комментарии

pfftdammitchris picture pfftdammitchris  ·  76Комментарии