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

В Flatpickr событийная система построена вокруг набора callback-функций, которые срабатывают в ответ на действия пользователя или изменения состояния календаря. Эти события формируют контракт поведения компонента, поэтому именно они становятся ключевой точкой при автоматизированном тестировании.

Основные события:

  • onChange — изменение выбранной даты
  • onOpen — открытие календаря
  • onClose — закрытие календаря
  • onMonthChange — смена месяца
  • onYearChange — смена года
  • onReady — завершение инициализации
  • onValueUpdate — синхронизация значения

Каждое событие передаёт контекст инстанса, массив выбранных дат и строковое представление значения, что позволяет проверять не только факт вызова, но и корректность состояния.


Подготовка окружения для тестирования событий

Тестирование событий требует изолированной DOM-среды. В большинстве случаев используется Jest с jsdom или Vitest в аналогичной конфигурации.

Типичная базовая настройка:

/**
 * jsdom предоставляет виртуальный DOM
 * Flatpickr требует реального input-элемента
 */

document.body.innerHTML = `<input id="date" type="text" />`;

Ключевым моментом является создание реального input-узла, так как Flatpickr привязывает своё поведение к DOM-элементу напрямую.


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

Событие onReady используется как индикатор полной инициализации компонента.

import flatpickr from "flatpickr";

test("onReady вызывается при инициализации", () => {
  const mock = jest.fn();

  flatpickr("#date", {
    onReady: mock,
  });

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

Особенности проверки:

  • вызов происходит синхронно при создании инстанса
  • важно учитывать, что DOM уже должен существовать
  • часто используется для проверки начального состояния

Проверка onOpen и onClose

События открытия и закрытия зависят от пользовательских действий или программного вызова методов open() и close().

test("onOpen и onClose вызываются при управлении календарём", () => {
  const onO pen = jest.fn();
  const onCl ose = jest.fn();

  const instance = flatpickr("#date", {
    onOpen,
    onClose,
  });

  instance.open();
  instance.close();

  expect(onOpen).toHaveBeenCalledTimes(1);
  expect(onClose).toHaveBeenCalledTimes(1);
});

Особенности поведения

  • onOpen может вызываться только при изменении состояния isOpen
  • повторный вызов open() не всегда генерирует событие
  • onClose зависит от факта активного состояния

Тестирование onChange и работа с вводом

Событие onChange является центральным для проверки корректности выбора даты.

test("onChange срабатывает при выборе даты", () => {
  const onCha nge = jest.fn();

  const instance = flatpickr("#date", {
    onChange,
  });

  const input = document.querySelector("#date");
  instance.setDate("2026-06-01");

  expect(onChange).toHaveBeenCalled();
  expect(onChange.mock.calls[0][0].length).toBe(1);
});

Важные аспекты:

  • первый аргумент — массив выбранных дат
  • второй — строковое представление
  • третий — экземпляр календаря
  • вызов может происходить как через UI, так и через API

Проверка onMonthChange и onYearChange

Эти события связаны с навигацией внутри календаря.

test("onMonthChange реагирует на смену месяца", () => {
  const onMonthCha nge = jest.fn();

  const instance = flatpickr("#date", {
    defaultDate: "2026-06-01",
    onMonthChange,
  });

  instance.changeMonth(1);

  expect(onMonthChange).toHaveBeenCalled();
});
test("onYearChange реагирует на смену года", () => {
  const onYearCha nge = jest.fn();

  const instance = flatpickr("#date", {
    defaultDate: "2026-06-01",
    onYearChange,
  });

  instance.changeYear(1);

  expect(onYearChange).toHaveBeenCalled();
});

Поведенческие нюансы

  • changeMonth может триггерить ререндер календаря
  • событие не вызывается при отсутствии реального изменения значения
  • некоторые конфигурации (disable, minDate, maxDate) влияют на срабатывание

Тестирование onValueUpdate

onValueUpdate используется для синхронизации внутреннего состояния и input-значения.

test("onValueUpdate вызывается при обновлении значения", () => {
  const onValueUpd ate = jest.fn();

  const instance = flatpickr("#date", {
    onValueUpdate,
  });

  instance.setDate("2026-06-01");

  expect(onValueUpdate).toHaveBeenCalled();
});

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


Эмуляция пользовательских действий

Для проверки событий часто требуется имитация взаимодействия с DOM:

test("открытие через клик по input вызывает onOpen", () => {
  const onO pen = jest.fn();

  flatpickr("#date", {
    onOpen,
  });

  const input = document.querySelector("#date");
  input.dispatchEvent(new Event("focus"));

  expect(onOpen).toHaveBeenCalled();
});

Используемые техники:

  • dispatchEvent
  • focus / blur
  • симуляция кликов
  • программные вызовы API

Работа с таймерами и асинхронностью

Некоторые сценарии требуют контроля времени, особенно при debounce-логике или анимациях.

jest.useFakeTimers();

test("отложенные события обрабатываются корректно", () => {
  const onCha nge = jest.fn();

  const instance = flatpickr("#date", {
    onChange,
  });

  instance.setDate("2026-06-01");

  jest.runAllTimers();

  expect(onChange).toHaveBeenCalled();
});

Контроль времени особенно важен при тестировании сложных UI-сценариев, где обновления происходят не мгновенно.


Проверка порядка вызова событий

При комплексных сценариях важен порядок выполнения:

test("соблюдение порядка событий", () => {
  const events = [];

  flatpickr("#date", {
    onOpen: () => events.push("open"),
    onChange: () => events.push("change"),
    onClose: () => events.push("close"),
  });

  const instance = flatpickr("#date");
  instance.open();
  instance.setDate("2026-06-01");
  instance.close();

  expect(events).toEqual(["open", "change", "close"]);
});

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


Изоляция и сброс состояния между тестами

Для стабильности тестов важно очищать DOM и уничтожать экземпляры:

afterEach(() => {
  document.body.innerHTML = "";
  jest.clearAllMocks();
});

Некорректная очистка приводит к:

  • утечкам состояния инстанса
  • повторным вызовам событий
  • конфликтам DOM-элементов

Моки и шпионы в тестировании событий

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

const spy = jest.fn();

flatpickr("#date", {
  onChange: spy,
});

expect(spy.mock.calls[0][1]).toBeDefined();

Проверка аргументов позволяет контролировать:

  • корректность выбранных дат
  • форматирование строки значения
  • ссылку на инстанс

Типичные ошибки при тестировании событий

  • использование неинициализированного DOM
  • отсутствие очистки после тестов
  • проверка вызова без учета асинхронности
  • игнорирование повторных триггеров
  • тестирование UI без учета внутреннего состояния инстанса

Эти ошибки приводят к нестабильным и флаки-тестам, особенно при использовании реальных браузерных событий вместо изолированной среды.