Автоматизация тестирования

Автоматизация тестирования календарных компонентов представляет отдельный класс задач из-за сочетания DOM-логики, работы со временем и сложного пользовательского взаимодействия. Flatpickr как lightweight datepicker добавляет собственный слой абстракции над датами, событиями и рендерингом, что требует продуманного подхода к проверке корректности поведения в разных уровнях тестирования.

Flatpickr работает напрямую с DOM, создаёт всплывающий календарь, управляет состоянием выбранной даты и активно использует системное время. Это формирует несколько ключевых сложностей:

  • зависимость от текущего времени (new Date())
  • асинхронное обновление DOM при открытии/закрытии календаря
  • обработка пользовательских событий (click, input, blur)
  • внутренняя нормализация дат с учётом локали и форматов
  • динамическая генерация календарной сетки

Любая нестабильность времени или DOM-среды приводит к флаки-тестам, поэтому основой автоматизации становится изоляция времени и предсказуемость окружения.


Юнит-тестирование конфигурации и логики

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

Кандидаты для юнит-тестов:

  • dateFormat
  • defaultDate
  • minDate / maxDate
  • enable / disable
  • пользовательские парсеры parseDate и форматтеры formatDate

Пример тестирования форматирования:

import flatpickr from "flatpickr";

test("formatDate применяет кастомный формат", () => {
  const instance = flatpickr(document.createElement("input"), {
    dateFormat: "Y-m-d"
  });

  const date = new Date(2026, 0, 15);
  const formatted = instance.formatDate(date, "Y-m-d");

  expect(formatted).toBe("2026-01-15");
});

В подобных тестах важно избегать рендера UI — проверяется только логика преобразования данных.


Использование JSDOM и изоляция DOM

Для тестов, затрагивающих инициализацию Flatpickr, используется среда JSDOM (например, через Jest). Она позволяет создавать виртуальный DOM и подключать input-элементы.

import flatpickr from "flatpickr";

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

test("инициализация создаёт экземпляр", () => {
  const input = document.getElementById("date");
  const fp = flatpickr(input, {});

  expect(fp.input).toBe(input);
});

Ключевой момент — каждый тест должен работать с новым DOM-состоянием, иначе возникают утечки состояния между кейсами.


Управление временем и fake timers

Flatpickr активно использует setTimeout и текущую дату, поэтому фиксация времени — обязательный элемент автоматизации.

В Jest это реализуется через fake timers:

jest.useFakeTimers();
jest.setSystemTime(new Date(2026, 5, 1));

test("открытие календаря использует фиксированную дату", () => {
  document.body.innerHTML = `<input id="date" />`;

  const input = document.getElementById("date");
  const fp = flatpickr(input, {});

  fp.open();

  jest.runAllTimers();

  expect(fp.currentYear).toBe(2026);
});

Фиксация времени устраняет недетерминированность тестов и делает календарную сетку воспроизводимой.


Симуляция пользовательских событий

Flatpickr реагирует на события DOM, поэтому тестирование требует программной эмуляции взаимодействия.

Основные сценарии:

  • focus → открытие календаря
  • click → выбор даты
  • input → ручной ввод
  • blur → закрытие

Пример:

test("выбор даты через клик обновляет input", () => {
  document.body.innerHTML = `<input id="date" />`;

  const input = document.getElementById("date");
  const fp = flatpickr(input, {});

  fp.open();

  const day = document.querySelector(".flatpickr-day:not(.prevMonthDay)");
  day.click();

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

Важный аспект — ожидание отрисовки календаря. В некоторых случаях требуется requestAnimationFrame или setTimeout в тестах.


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

Состояние UI является одной из ключевых точек проверки:

test("календарь открывается и закрывается", () => {
  document.body.innerHTML = `<input id="date" />`;

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

  fp.open();
  expect(document.querySelector(".flatpickr-calendar")).not.toBeNull();

  fp.close();
  expect(document.querySelector(".flatpickr-calendar")).toBeNull();
});

Такие тесты проверяют корректность управления DOM-узлами и очистки состояния.


Интеграционные тесты и взаимодействие с приложением

При интеграционном тестировании Flatpickr проверяется уже в контексте реального UI-фреймворка или формы.

Типовые сценарии:

  • синхронизация значения с state (React/Vue/Vanilla)
  • валидация формы с датой
  • взаимодействие нескольких datepicker-ов
  • зависимость minDate/maxDate между полями

Пример логики зависимых дат:

const start = flatpickr("#start", {
  onChange: (_, dateStr, instance) => {
    end.set("minDate", dateStr);
  }
});

const end = flatpickr("#end", {});

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


E2E тестирование (Cypress / Playwright)

На уровне end-to-end Flatpickr тестируется как часть пользовательского потока.

Ключевые сценарии:

  • открытие календаря через UI
  • выбор даты в форме
  • отправка формы
  • проверка сохранённого значения на серверной стороне UI

Пример (Playwright):

import { test, expect } from "@playwright/test";

test("выбор даты в форме", async ({ page }) => {
  await page.goto("/form");

  await page.click("#date");
  await page.click(".flatpickr-day:not(.prevMonthDay)");

  const value = await page.inputValue("#date");
  expect(value).not.toBe("");
});

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


Стабилизация тестов и борьба с флаки-эффектами

Основные источники нестабильности:

  • анимации открытия календаря
  • задержки рендера DOM
  • различия часовых поясов
  • системное время CI-среды
  • перекрытие элементов в headless-режиме

Методы стабилизации:

  • фиксация системного времени
  • отключение анимаций (animate: false)
  • ожидание DOM через MutationObserver
  • использование явных ожиданий вместо sleep
  • очистка DOM после каждого теста

Тестирование плагинов и расширений

Flatpickr поддерживает плагины, которые добавляют поведение (например, диапазоны дат, альтернативные UI-режимы).

При тестировании плагинов важно:

  • изолировать плагин от ядра
  • проверять корректность хуков (onReady, onChange)
  • контролировать порядок выполнения событий
const fp = flatpickr(input, {
  plugins: [new SomePlugin()]
});

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


Поведение в CI и headless-окружении

В CI-средах часто отсутствует полноценный layout engine, что влияет на:

  • вычисление размеров календаря
  • позиционирование popup
  • обработку scroll container

Типовые решения:

  • использование jsdom-global с расширениями
  • запуск браузерных E2E в headless Chromium
  • отключение layout-зависимой логики
  • унификация viewport

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


Детеминированность тестов и управление состоянием

Flatpickr сохраняет внутреннее состояние экземпляра, поэтому критически важно:

  • не переиспользовать DOM-элементы между тестами
  • явно уничтожать инстансы (destroy)
  • избегать глобальных переменных
  • контролировать побочные эффекты и listeners
afterEach(() => {
  document.body.innerHTML = "";
});

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