Unit тестирование

Unit-тестирование позволяет проверять корректность работы отдельных частей приложения независимо от остальных компонентов системы. При использовании Pikaday тестирование обычно сосредоточено не на внутреннем устройстве библиотеки, а на логике интеграции календаря с пользовательским интерфейсом, обработчиками событий, бизнес-правилами и механизмами работы с датами.

Основная цель таких тестов заключается в выявлении ошибок на ранних этапах разработки и предотвращении регрессий после внесения изменений.

Наиболее распространённые сценарии тестирования включают:

  • корректную инициализацию календаря;
  • работу методов выбора даты;
  • обработку пользовательских событий;
  • ограничения выбора дат;
  • интеграцию с формами;
  • взаимодействие с внешними библиотеками форматирования;
  • синхронизацию нескольких календарей.

Особенности тестирования компонентов, использующих Pikaday

Pikaday активно взаимодействует с DOM-элементами браузера. Это создаёт дополнительные требования к тестовой среде.

Типичный экземпляр создаётся следующим образом:

const picker = new Pikaday({
    field: document.getElementById('date')
});

В ходе выполнения создаются:

  • HTML-элементы календаря;
  • обработчики событий;
  • внутренние объекты дат;
  • ссылки на элементы формы.

Поэтому для unit-тестов обычно используется среда, эмулирующая браузер.

Наиболее популярный вариант:

Jest + JSDOM

JSDOM предоставляет виртуальный DOM, позволяя выполнять тестирование без запуска реального браузера.


Подготовка тестовой среды

Перед каждым тестом желательно создавать новый DOM.

Пример:

beforeEach(() => {
    document.body.innerHTML = `
        <input id="date">
    `;
});

После завершения тестов ресурсы рекомендуется освобождать:

let picker;

afterEach(() => {
    picker.destroy();
});

Такой подход предотвращает влияние предыдущих тестов на последующие.


Проверка создания экземпляра

Первый уровень тестирования связан с успешной инициализацией объекта.

Пример:

test('создание экземпляра Pikaday', () => {
    const picker = new Pikaday({
        field: document.getElementById('date')
    });

    expect(picker).toBeDefined();
});

Тест подтверждает, что конструктор успешно создаёт объект календаря.


Проверка привязки к элементу формы

После инициализации важно убедиться, что календарь связан с нужным полем.

Пример:

test('привязка к input', () => {
    const input = document.getElementById('date');

    const picker = new Pikaday({
        field: input
    });

    expect(picker._o.field).toBe(input);
});

Подобные проверки позволяют обнаружить ошибки конфигурации.


Тестирование установки даты

Метод setDate() является одним из наиболее используемых.

Пример:

test('установка даты', () => {
    const picker = new Pikaday({
        field: document.getElementById('date')
    });

    const date = new Date(2025, 4, 10);

    picker.setDate(date);

    expect(
        picker.getDate().getTime()
    ).toBe(date.getTime());
});

Проверяется корректность сохранения выбранной даты.


Проверка обновления значения поля

После выбора даты содержимое поля должно измениться.

Пример:

test('обновление значения input', () => {
    const input = document.getElementById('date');

    const picker = new Pikaday({
        field: input,
        format: 'YYYY-MM-DD'
    });

    picker.setDate(new Date(2025, 0, 15));

    expect(input.value).not.toBe('');
});

В реальном проекте желательно проверять точное значение строки.


Тестирование метода getDate()

Метод должен возвращать выбранную дату.

Пример:

test('получение выбранной даты', () => {
    const picker = new Pikaday({
        field: document.getElementById('date')
    });

    picker.setDate(new Date(2025, 7, 20));

    const result = picker.getDate();

    expect(result instanceof Date).toBe(true);
});

Такой тест гарантирует корректность интерфейса объекта.


Проверка очистки даты

Во многих приложениях требуется удаление выбранного значения.

Пример:

test('очистка даты', () => {
    const picker = new Pikaday({
        field: document.getElementById('date')
    });

    picker.setDate(null);

    expect(picker.getDate()).toBeNull();
});

Подобные сценарии особенно важны для форм с необязательными полями.


Тестирование события onSelect

Событие onSelect используется практически во всех проектах.

Пример:

test('вызов onSelect', () => {
    const callback = jest.fn();

    const picker = new Pikaday({
        field: document.getElementById('date'),
        onSelect: callback
    });

    picker.setDate(new Date());

    expect(callback).toHaveBeenCalled();
});

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


Проверка количества вызовов обработчика

Иногда важно контролировать число срабатываний события.

Пример:

test('обработчик вызывается один раз', () => {
    const callback = jest.fn();

    const picker = new Pikaday({
        field: document.getElementById('date'),
        onSelect: callback
    });

    picker.setDate(new Date());

    expect(callback).toHaveBeenCalledTimes(1);
});

Это помогает выявлять дублирование событий.


Тестирование ограничения minDate

Минимальная дата часто используется в формах бронирования и регистрации.

Пример:

test('установка minDate', () => {
    const minDate = new Date(2025, 0, 1);

    const picker = new Pikaday({
        field: document.getElementById('date'),
        minDate
    });

    expect(
        picker._o.minDate.getTime()
    ).toBe(minDate.getTime());
});

Проверяется корректность сохранения ограничения.


Тестирование ограничения maxDate

Аналогичная проверка выполняется для верхней границы диапазона.

test('установка maxDate', () => {
    const maxDate = new Date(2025, 11, 31);

    const picker = new Pikaday({
        field: document.getElementById('date'),
        maxDate
    });

    expect(
        picker._o.maxDate.getTime()
    ).toBe(maxDate.getTime());
});

Проверка отображения календаря

Для интерфейсной логики важно тестировать показ календаря.

Пример:

test('открытие календаря', () => {
    const picker = new Pikaday({
        field: document.getElementById('date')
    });

    picker.show();

    expect(picker.isVisible()).toBe(true);
});

Проверка скрытия календаря

Пример:

test('скрытие календаря', () => {
    const picker = new Pikaday({
        field: document.getElementById('date')
    });

    picker.show();
    picker.hide();

    expect(picker.isVisible()).toBe(false);
});

Тестирование уничтожения экземпляра

После вызова destroy() обработчики должны удаляться.

Пример:

test('уничтожение календаря', () => {
    const picker = new Pikaday({
        field: document.getElementById('date')
    });

    picker.destroy();

    expect(picker._o).toBeNull();
});

Конкретная реализация проверки может отличаться в зависимости от версии библиотеки.


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

При тестировании интеграционной логики часто применяются моки.

Пример функции:

function initializeCalendar(callback) {
    return new Pikaday({
        field: document.getElementById('date'),
        onSelect: callback
    });
}

Тест:

test('callback вызывается после выбора даты', () => {
    const callback = jest.fn();

    const picker = initializeCalendar(callback);

    picker.setDate(new Date());

    expect(callback).toHaveBeenCalled();
});

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


Тестирование пользовательских функций вокруг Pikaday

Чаще всего проверяется собственный код проекта.

Пример:

function getSelectedDate(picker) {
    return picker.getDate();
}

Тест:

test('возвращается дата из календаря', () => {
    const picker = new Pikaday({
        field: document.getElementById('date')
    });

    const date = new Date();

    picker.setDate(date);

    expect(
        getSelectedDate(picker)
    ).toEqual(date);
});

Такой подход соответствует классической концепции unit-тестирования.


Изоляция внешних зависимостей

Если вокруг Pikaday существует дополнительный сервис, его желательно подменять.

Пример:

const api = {
    saveDate: jest.fn()
};

Код приложения:

function handleDateSelection(date) {
    api.saveDate(date);
}

Тест:

test('дата отправляется в сервис', () => {
    const date = new Date();

    handleDateSelection(date);

    expect(api.saveDate)
        .toHaveBeenCalledWith(date);
});

В результате тестируется только собственная логика проекта.


Проверка нескольких календарей

Во многих системах используются поля начала и окончания периода.

Создание:

const startPicker = new Pikaday({
    field: startInput
});

const endPicker = new Pikaday({
    field: endInput
});

Тест:

test('создаются два независимых календаря', () => {
    expect(startPicker).not.toBe(endPicker);
});

Подобные проверки помогают избежать конфликтов состояния.


Тестирование диапазонов дат

Пример пользовательской функции:

function isRangeValid(start, end) {
    return start <= end;
}

Тест:

test('корректный диапазон дат', () => {
    const start = new Date(2025, 0, 1);
    const end = new Date(2025, 0, 5);

    expect(
        isRangeValid(start, end)
    ).toBe(true);
});

Хотя функция напрямую не относится к Pikaday, именно такие проверки составляют большую часть реального тестового покрытия.


Проверка форматирования даты

При использовании Moment.js или собственных форматтеров необходимо тестировать итоговую строку.

Пример:

function formatDate(date) {
    return date.toISOString().split('T')[0];
}

Тест:

test('форматирование даты', () => {
    const date = new Date('2025-01-10');

    expect(
        formatDate(date)
    ).toBe('2025-01-10');
});

Стратегия покрытия тестами

Наиболее полезное покрытие обычно включает:

  1. Создание экземпляра Pikaday.
  2. Выбор даты.
  3. Получение даты.
  4. Очистку значения.
  5. Пользовательские обработчики событий.
  6. Ограничения диапазона.
  7. Отображение и скрытие календаря.
  8. Интеграцию с формами.
  9. Бизнес-логику, использующую выбранные даты.
  10. Пользовательские сервисы и API-обёртки.

Основной акцент unit-тестирования рекомендуется делать на собственном коде приложения, рассматривая Pikaday как внешнюю зависимость с уже проверенной внутренней реализацией. Такой подход обеспечивает быстрые, стабильные и легко поддерживаемые тесты, позволяющие своевременно обнаруживать ошибки при работе с датами и пользовательскими интерфейсами.