Тестирование интеграции с формами

Интеграция AutoNumeric с формами требует проверки не только корректного форматирования чисел, но и устойчивости поведения при вводе данных, отправке форм, программном изменении значений и взаимодействии с DOM-событиями. Основная сложность тестирования заключается в том, что библиотека изменяет отображаемое значение поля ввода, сохраняя при этом внутреннее числовое представление, что создаёт двойственность состояния: пользовательский ввод и логическая модель значения.

При интеграционном тестировании форм с AutoNumeric важно воспроизводить реальные условия браузера. Обычно используются среды:

  • Jest + JSDOM для быстрых модульных и интеграционных тестов
  • Testing Library (DOM Testing Library) для проверки поведения интерфейса
  • Cypress или Playwright для end-to-end сценариев

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

document.body.innerHTML = `
  <form id="testForm">
    <input id="price" name="price" />
    <button type="submit">Send</button>
  </form>
`;

const priceInput = document.querySelector('#price');

Инициализация AutoNumeric:

const anElement = new AutoNumeric(priceInput, {
  digitGroupSeparator: ' ',
  decimalCharacter: ',',
  decimalPlaces: 2
});

Проверка корректности отображения значения

Первый уровень тестирования связан с форматированием.

anElement.set(12345.67);
expect(priceInput.value).toBe('12 345,67');

Важно проверять именно DOM-значение, а не внутреннее значение экземпляра. При необходимости можно проверять и его:

expect(anElement.getNumber()).toBe(12345.67);

Разделение get() и getNumber() является критическим, поскольку первый возвращает строку с форматированием, а второй — числовое значение.

Тестирование пользовательского ввода

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

priceInput.value = '10000.5';
priceInput.dispatchEvent(new Event('input', { bubbles: true }));

expect(priceInput.value).toBe('10 000,50');

Особое внимание уделяется:

  • вставке значений через paste
  • вводу десятичного разделителя
  • удалению символов форматирования
  • работе backspace и delete

Пример теста вставки:

priceInput.focus();
document.execCommand('insertText', false, '99999.9');

expect(priceInput.value).toMatch(/99 999/);

Интеграция с отправкой формы

Ключевой аспект — корректная сериализация данных при submit. AutoNumeric изменяет отображение, но форма должна отправлять нормализованное значение.

let submittedData = null;

document.querySelector('#testForm').addEventListener('submit', (e) => {
  e.preventDefault();
  submittedData = Object.fromEntries(new FormData(e.target));
});

anElement.set(2500.75);
document.querySelector('button').click();

expect(submittedData.price).toBe('2500.75');

Если используется режим с форматированием в input, важно явно вызывать unformat перед отправкой:

anElement.unformat();

или использовать конфигурацию, при которой AutoNumeric автоматически возвращает числовое значение через hidden field.

Проверка синхронизации состояния

В сложных формах часто возникает проблема рассинхронизации между:

  • DOM значением input
  • внутренним состоянием AutoNumeric
  • состоянием фреймворка (React, Vue, Angular)

Для тестирования важно проверять двустороннюю синхронизацию:

anElement.set(1000);
expect(anElement.getNumber()).toBe(1000);

priceInput.value = '2000';
priceInput.dispatchEvent(new Event('input', { bubbles: true }));

expect(anElement.getNumber()).toBe(2000);

При этом некоторые конфигурации блокируют прямую запись в value, поэтому тесты должны учитывать режим управления (watchExternalChanges, modifyValueOnWheel, и аналогичные опции).

Обработка edge cases

Интеграция с формами требует проверки нестандартных сценариев:

Пустые значения

anElement.set(null);
expect(priceInput.value).toBe('');

Нулевое значение

anElement.set(0);
expect(priceInput.value).toBe('0,00');

Некорректный ввод

priceInput.value = 'abc123';
priceInput.dispatchEvent(new Event('input', { bubbles: true }));

expect(anElement.getNumber()).toBe(123);

Очень большие числа

anElement.set(999999999999.99);
expect(priceInput.value).toContain('999');

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

AutoNumeric генерирует события, которые часто используются для бизнес-логики:

  • autoNumeric:initialized
  • autoNumeric:formatted
  • autoNumeric:rawValueModified

Проверка событий:

let triggered = false;

priceInput.addEventListener('autoNumeric:formatted', () => {
  triggered = true;
});

anElement.set(123);

expect(triggered).toBe(true);

Важно проверять, что события не вызываются избыточно при массовых обновлениях значений.

Интеграция с динамическими формами

В формах, где поля добавляются динамически, AutoNumeric должен корректно инициализироваться после вставки DOM-элемента.

const newInput = document.createElement('input');
newInput.id = 'dynamic';
document.body.appendChild(newInput);

const dyn = new AutoNumeric(newInput, { decimalPlaces: 2 });
dyn.set(500);

expect(newInput.value).toBe('500,00');

Тестирование должно учитывать повторную инициализацию и предотвращение двойного биндинга.

Проверка уничтожения инстанса

Корректное освобождение ресурсов важно для форм с динамическим lifecycle.

anElement.clear();
anElement.remove();

expect(priceInput.value).toBe('');

Также важно убедиться, что после remove() события больше не обрабатываются:

priceInput.value = '1000';
priceInput.dispatchEvent(new Event('input', { bubbles: true }));

expect(anElement.getNumber()).toBe(null);

End-to-end тестирование форм

В Cypress или Playwright проверяется полный пользовательский сценарий:

  • ввод значения
  • проверка форматирования
  • отправка формы
  • проверка payload

Пример логики:

  • пользователь вводит 12345
  • поле отображает 12 345,00
  • при submit отправляется 12345

Критически важно тестировать поведение при реальном DOM-рендере, так как JSDOM не всегда корректно воспроизводит input-события.

Проверка совместимости с фреймворками

При использовании React/Vue важно тестировать:

  • controlled vs uncontrolled inputs
  • обновление через props
  • предотвращение конфликтов между state и AutoNumeric

Типичный тестовый конфликт:

setState({ value: 1000 });
anElement.set(2000);
expect(state.value).not.toBe(2000);

Такие сценарии требуют проверки приоритетов источника истины.

Стресс-тестирование массовых обновлений

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

for (let i = 0; i < 1000; i++) {
  anElement.set(i);
}

Проверяется:

  • отсутствие утечек памяти
  • стабильность форматирования
  • отсутствие зависаний UI

Проверка локализации в формах

Формы часто используют разные локали:

  • разделитель тысяч
  • десятичный символ
  • валютные форматы
const an = new AutoNumeric(priceInput, {
  digitGroupSeparator: '.',
  decimalCharacter: ','
});

an.set(1234.56);

expect(priceInput.value).toBe('1.234,56');

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