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

Принципы тестирования ввода числовых значений

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

Ключевые аспекты:

  • корректность парсинга строкового ввода в числовое значение
  • устойчивость к локалям (разделители тысяч и десятичные знаки)
  • реакция на некорректные символы
  • поведение при частичном вводе (например, «-», «.»)
  • синхронизация DOM и внутреннего состояния
  • обработка вставки (paste) и drag-and-drop

Тестирование инициализации и базового ввода

При тестировании инициализации важно проверить, что экземпляр корректно форматирует начальное значение и сохраняет согласованность состояния.

import AutoNumeric from 'autonumeric';

test('инициализация форматирует число согласно настройкам', () => {
  document.body.innerHTML = `<input id="price" value="1000">`;

  const input = document.getElementById('price');

  new AutoNumeric(input, {
    digitGroupSeparator: ' ',
    decimalCharacter: ','
  });

  expect(input.value).toBe('1 000');
});

Проверка должна учитывать:

  • форматирование при загрузке
  • соответствие локали
  • отсутствие потери значимых цифр

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

Клавиатурный ввод является основным сценарием и требует симуляции событий keydown, keypress, input.

test('ввод цифр с клавиатуры форматируется корректно', () => {
  document.body.innerHTML = `<input id="amount">`;
  const input = document.getElementById('amount');

  new AutoNumeric(input, {
    digitGroupSeparator: ','
  });

  input.value = '';
  input.dispatchEvent(new Event('focus'));

  input.value = '1234';
  input.dispatchEvent(new Event('input'));

  expect(input.value).toBe('1,234');
});

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

  • поэтапному вводу (1 → 12 → 123 → 1234)
  • сохранению каретки (cursor position)
  • обработке backspace/delete

Тестирование вставки из буфера обмена

Вставка данных часто нарушает форматирование, особенно если источник содержит пробелы, символы валют или нестандартные разделители.

test('вставка очищает некорректные символы', () => {
  document.body.innerHTML = `<input id="amount">`;
  const input = document.getElementById('amount');

  const an = new AutoNumeric(input, {
    decimalCharacter: '.',
    digitGroupSeparator: ','
  });

  const pasteEvent = new Event('paste');
  pasteEvent.clipboardData = {
    getData: () => '$1 234.56'
  };

  input.dispatchEvent(pasteEvent);

  expect(input.value).toBe('1,234.56');
});

При тестировании вставки важно учитывать:

  • валютные символы ($, €, ₸)
  • неразрывные пробелы
  • переносы строк
  • смешанные форматы (1.234,56 vs 1,234.56)

Тестирование частичного ввода и промежуточных состояний

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

Примеры допустимых промежуточных значений:

  • - (начало отрицательного числа)
  • . (начало дробной части)
  • 1. (ожидание дробных цифр)
test('поддержка промежуточного ввода', () => {
  document.body.innerHTML = `<input id="amount">`;
  const input = document.getElementById('amount');

  new AutoNumeric(input, {
    decimalCharacter: '.',
    allowDecimalPadding: false
  });

  input.value = '-';
  input.dispatchEvent(new Event('input'));

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

Такие сценарии критичны для проверки:

  • отсутствие преждевременной нормализации
  • сохранение UX при наборе
  • отсутствие сбоев парсера

Тестирование локалей и форматов

AutoNumeric активно используется в интернациональных приложениях, где различаются:

  • разделитель тысяч
  • десятичный символ
  • порядок группировки
test('локаль с пробелами как разделитель тысяч', () => {
  document.body.innerHTML = `<input id="amount">`;
  const input = document.getElementById('amount');

  new AutoNumeric(input, {
    digitGroupSeparator: ' ',
    decimalCharacter: ','
  });

  input.value = '1000000';
  input.dispatchEvent(new Event('input'));

  expect(input.value).toBe('1 000 000');
});

Также проверяются:

  • французский формат 1 234,56
  • английский формат 1,234.56
  • арабские и восточноазиатские локали (при расширенной конфигурации)

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

Важная часть поведения — корректная генерация событий input, change, blur.

test('событие change вызывается при потере фокуса', () => {
  document.body.innerHTML = `<input id="amount">`;
  const input = document.getElementById('amount');

  const handler = jest.fn();
  input.addEventListener('change', handler);

  const an = new AutoNumeric(input, {});

  input.value = '1000';
  input.dispatchEvent(new Event('input'));
  input.dispatchEvent(new Event('blur'));

  expect(handler).toHaveBeenCalled();
});

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

  • отсутствие лишних событий
  • корректный порядок вызова
  • синхронизация значения и DOM

Тестирование работы с кареткой (cursor position)

Сложность возрастает при форматировании числа «на лету». Каретка должна оставаться в логически ожидаемой позиции.

test('каретка сохраняется после форматирования', () => {
  document.body.innerHTML = `<input id="amount">`;
  const input = document.getElementById('amount');

  new AutoNumeric(input, {
    digitGroupSeparator: ','
  });

  input.value = '1234';
  input.setSelectionRange(2, 2);

  input.dispatchEvent(new Event('input'));

  const position = input.selectionStart;
  expect(position).toBeGreaterThan(0);
});

Проблемные случаи:

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

Тестирование обработки ошибок и некорректного ввода

Ввод может содержать:

  • буквы
  • спецсимволы
  • смешанные форматы
  • пустые строки
test('игнорирование нечисловых символов', () => {
  document.body.innerHTML = `<input id="amount">`;
  const input = document.getElementById('amount');

  new AutoNumeric(input, {});

  input.value = '12ab34';
  input.dispatchEvent(new Event('input'));

  expect(input.value).toBe('1,234');
});

Дополнительно проверяется:

  • защита от NaN
  • обработка null/undefined
  • устойчивость к HTML-вставкам

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

Фаззинг позволяет выявить редкие ошибки в парсере чисел и форматировании.

function randomInput() {
  const chars = '0123456789.,-$€  ';
  let str = '';
  for (let i = 0; i < 50; i++) {
    str += chars[Math.floor(Math.random() * chars.length)];
  }
  return str;
}

test('фаззинг ввод не ломает форматирование', () => {
  document.body.innerHTML = `<input id="amount">`;
  const input = document.getElementById('amount');

  new AutoNumeric(input, {});

  for (let i = 0; i < 100; i++) {
    input.value = randomInput();
    input.dispatchEvent(new Event('input'));

    expect(Number.isNaN(Number(input.value))).toBe(false);
  }
});

Фаззинг выявляет:

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

Тестирование мобильного ввода и IME

Мобильные клавиатуры и IME (Input Method Editor) создают промежуточные состояния ввода.

Критично учитывать:

  • compositionstart / compositionend
  • задержку применения форматирования
  • неполные символы
test('IME ввод не ломает значение', () => {
  document.body.innerHTML = `<input id="amount">`;
  const input = document.getElementById('amount');

  new AutoNumeric(input, {});

  input.dispatchEvent(new Event('compositionstart'));

  input.value = '12';
  input.dispatchEvent(new Event('input'));

  input.dispatchEvent(new Event('compositionend'));

  expect(input.value).toBeDefined();
});

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

При частых обновлениях (например, 60 FPS ввод) важно измерять время обработки событий.

test('обработка массового ввода не деградирует', () => {
  document.body.innerHTML = `<input id="amount">`;
  const input = document.getElementById('amount');

  const an = new AutoNumeric(input, {});

  const start = performance.now();

  for (let i = 0; i < 1000; i++) {
    input.value = String(i);
    input.dispatchEvent(new Event('input'));
  }

  const duration = performance.now() - start;

  expect(duration).toBeLessThan(200);
});

Интеграционное тестирование с DOM-формами

В реальных приложениях числовые поля часто связаны с формами и валидацией.

test('интеграция с формой', () => {
  document.body.innerHTML = `
    <form id="form">
      <input id="amount" name="amount">
    </form>
  `;

  const input = document.getElementById('amount');
  const form = document.getElementById('form');

  new AutoNumeric(input, {});

  input.value = '5000';
  input.dispatchEvent(new Event('input'));

  const formData = new FormData(form);

  expect(formData.get('amount')).toBeTruthy();
});

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

Тестирование пользовательского ввода в AutoNumeric строится вокруг многослойной модели:

  • unit-тесты для парсинга и форматирования
  • integration-тесты для DOM и событий
  • e2e-тесты для реального браузерного поведения
  • стресс-тесты для больших объёмов ввода

Критические зоны покрытия:

  • input event pipeline
  • cursor management
  • locale formatting
  • paste handling
  • IME composition
  • edge-case parsing
  • performance under rapid updates