Mockdate функциональность

В процессе тестирования JavaScript-приложений часто возникает необходимость управлять временем: проверять поведение кода в разные моменты, фиксировать текущую дату для предсказуемых результатов или эмулировать истечение таймеров. Библиотека MockDate позволяет надежно контролировать объект Date, создавая предсказуемую среду для тестов. В сочетании с Jasmine, MockDate становится мощным инструментом для юнит-тестирования кода, зависящего от времени.


Установка и подключение

Для использования MockDate в проекте достаточно установить библиотеку через npm:

npm install mockdate --save-dev

После установки подключение в тестах Jasmine осуществляется стандартным способом:

const MockDate = require('mockdate');

Для браузерных сред возможна загрузка через <script> из CDN:

<script src="https://unpkg.com/mockdate"></script>

После подключения библиотека предоставляет методы для установки фиксированной даты и возврата системы к текущему времени.


Основные методы MockDate

1. Установка фиксированной даты

Метод MockDate.set(date, [timezoneOffset]) позволяет задать конкретную дату. date может быть строкой, числом (timestamp) или объектом Date.

MockDate.set('2026-01-11T12:00:00Z');
console.log(new Date().toISOString()); // 2026-01-11T12:00:00.000Z

Необязательный параметр timezoneOffset задает смещение часового пояса в минутах:

MockDate.set('2026-01-11T12:00:00Z', -120); // GMT+2

2. Сброс даты к реальному времени

Для возврата нормальной работы объекта Date используется метод MockDate.reset():

MockDate.reset();
console.log(new Date()); // текущая реальная дата

Интеграция с Jasmine

В Jasmine удобно использовать MockDate внутри хуков beforeEach и afterEach, чтобы каждый тест имел предсказуемое состояние времени, а после завершения теста среда возвращалась к нормальному состоянию.

describe('Примеры работы с датой', () => {
    beforeEach(() => {
        MockDate.set('2026-01-11T12:00:00Z');
    });

    afterEach(() => {
        MockDate.reset();
    });

    it('возвращает фиксированное время', () => {
        const now = new Date();
        expect(now.toISOString()).toBe('2026-01-11T12:00:00.000Z');
    });

    it('позволяет изменять время внутри теста', () => {
        MockDate.set('2026-01-12T15:30:00Z');
        expect(new Date().toISOString()).toBe('2026-01-12T15:30:00.000Z');
    });
});

Использование хуков позволяет изолировать состояние времени для каждого теста и предотвращает побочные эффекты между тестами.


Тестирование таймеров и асинхронного кода

Когда код зависит от задержек (setTimeout, setInterval) или вычисляет разницу между датами, MockDate позволяет управлять временем без реального ожидания.

describe('Тестирование задержек', () => {
    it('вычисляет разницу между датами', () => {
        MockDate.set('2026-01-11T12:00:00Z');
        const start = new Date();

        MockDate.set('2026-01-11T12:05:00Z'); // прошло 5 минут
        const end = new Date();

        const diffMinutes = (end - start) / 60000;
        expect(diffMinutes).toBe(5);
    });
});

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


Использование вместе с spyOn

Jasmine предоставляет метод spyOn для подмены функций. MockDate можно сочетать с этим инструментом для проверки вызовов функций с точным временем.

describe('Интеграция с spyOn', () => {
    it('вызывает функцию с текущей датой', () => {
        const logger = { logTime: () => new Date() };
        spyOn(logger, 'logTime').and.callThrough();

        MockDate.set('2026-01-11T12:00:00Z');
        logger.logTime();

        expect(logger.logTime).toHaveBeenCalled();
        expect(logger.logTime()).toEqual(new Date('2026-01-11T12:00:00Z'));
    });
});

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


Преимущества использования MockDate

  • Полная изоляция времени для тестов.
  • Возможность тестирования функций, зависящих от таймеров, без реальной задержки.
  • Совместимость с Jasmine и другими фреймворками тестирования.
  • Легкая интеграция с beforeEach и afterEach для предотвращения побочных эффектов.
  • Простая работа с разными часовыми поясами через параметр timezoneOffset.

Рекомендации по использованию

  • Всегда сбрасывать состояние даты в afterEach, чтобы избежать влияния на другие тесты.
  • Использовать фиксированную дату в начале теста, чтобы результаты были воспроизводимыми.
  • Комбинировать с Jasmine spy-функциями для проверки вызовов и аргументов, связанных с временем.
  • Для сложных сценариев с таймерами можно сочетать MockDate и jasmine.clock() для полного контроля времени и задержек.

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