Механизмы тестирования пользовательского ввода в Inputmask опираются на симуляцию событий DOM, проверку состояния маски после каждого изменения значения поля и анализ внутреннего буфера символов. Основная сложность заключается в том, что библиотека перехватывает ввод на уровне событий клавиатуры, вставки и изменения значения, трансформируя сырые данные в структурированный формат.
Ключевой объект тестирования — HTMLInputElement, к которому применена
маска через Inputmask().mask(element). Любое изменение
value проходит через цепочку обработки, включающую нормализацию,
проверку по паттерну и перерасчёт отображаемого значения.
Тестирование Inputmask условно разделяется на три уровня:
Модульное тестирование логики маски
Интеграционное тестирование DOM
E2E тестирование пользовательского сценария
Простейший сценарий проверяет, что маска корректно инициализируется и форматирует ввод.
import Inputmask from "inputmask";
test("инициализация маски для телефона", () => {
document.body.innerHTML = `<input id="phone" />`;
const input = document.querySelector("#phone");
Inputmask("+7 (999) 999-99-99").mask(input);
input.value = "9123456789";
input.dispatchEvent(new Event("input", { bubbles: true }));
expect(input.value).toBe("+7 (912) 345-67-89");
});
Основной аспект проверки — реакция на событие input,
поскольку именно оно запускает перерасчёт маски.
Inputmask активно использует keydown и
keypress для контроля допустимых символов. Тестирование
требует ручной генерации событий:
function triggerKeyDown(el, key) {
const event = new KeyboardEvent("keydown", {
key,
bubbles: true
});
el.dispatchEvent(event);
}
test("разрешение только цифр", () => {
document.body.innerHTML = `<input id="num" />`;
const input = document.querySelector("#num");
Inputmask("9999").mask(input);
triggerKeyDown(input, "A");
input.value = "A";
input.dispatchEvent(new Event("input", { bubbles: true }));
expect(input.value).toBe("");
});
Здесь проверяется фильтрация недопустимых символов до их попадания в буфер маски.
Вставка данных является отдельным каналом ввода, который часто
обходит клавиатурную фильтрацию. Inputmask обрабатывает
paste через перехват clipboardData.
test("обработка вставки номера", () => {
document.body.innerHTML = `<input id="phone" />`;
const input = document.querySelector("#phone");
Inputmask("(999) 999-9999").mask(input);
const pasteEvent = new ClipboardEvent("paste", {
clipboardData: new DataTransfer()
});
pasteEvent.clipboardData.setData("text", "8005551234");
input.dispatchEvent(pasteEvent);
input.dispatchEvent(new Event("input", { bubbles: true }));
expect(input.value).toBe("(800) 555-1234");
});
Особенность тестирования paste заключается в необходимости эмуляции
ClipboardEvent, который в разных тестовых окружениях может
иметь ограничения.
Маска должна корректно реагировать на удаление символов, сохраняя структуру.
test("удаление символов сохраняет формат", () => {
document.body.innerHTML = `<input id="date" />`;
const input = document.querySelector("#date");
Inputmask("99.99.9999").mask(input);
input.value = "12.03.2024";
input.dispatchEvent(new Event("input", { bubbles: true }));
input.value = "12.03.202";
input.dispatchEvent(new Event("input", { bubbles: true }));
expect(input.value).toBe("12.03.202");
});
В реальной среде также учитывается позиция каретки, которая влияет на поведение удаления.
Одним из наиболее сложных аспектов является контроль caret position после каждого ввода.
test("позиция каретки после ввода", () => {
document.body.innerHTML = `<input id="phone" />`;
const input = document.querySelector("#phone");
Inputmask("999-999").mask(input);
input.value = "123";
input.setSelectionRange(3, 3);
input.dispatchEvent(new Event("input", { bubbles: true }));
expect(input.selectionStart).toBeGreaterThanOrEqual(3);
});
Caret тестирование требует учёта браузерных различий, особенно в Chromium и WebKit.
В unit-тестах чаще всего используется связка Jest + JSDOM. Однако JSDOM не полностью эмулирует поведение input-событий, поэтому часть тестов требует дополнительных утилит.
Типичная конфигурация тестового окружения:
import "jest-environment-jsdom";
import Inputmask from "inputmask";
Проблемные зоны JSDOM:
InputEventselectionStartДля обхода используются ручные триггеры событий и фикстуры DOM.
Inputmask позволяет менять конфигурацию на лету, что требует проверки реактивности.
test("смена маски динамически", () => {
document.body.innerHTML = `<input id="field" />`;
const input = document.querySelector("#field");
const im = Inputmask("9999");
im.mask(input);
input.value = "1234";
input.dispatchEvent(new Event("input", { bubbles: true }));
im.setOptions({ mask: "999-9999" });
input.value = "1234567";
input.dispatchEvent(new Event("input", { bubbles: true }));
expect(input.value).toBe("123-4567");
});
Ключевой момент — корректная переинициализация внутренних буферов без разрушения DOM-состояния.
Alias-режимы (phone, email, numeric) требуют отдельного слоя тестирования, так как включают предустановленные правила.
test("alias numeric", () => {
document.body.innerHTML = `<input id="num" />`;
const input = document.querySelector("#num");
Inputmask({
alias: "numeric",
rightAlign: false
}).mask(input);
input.value = "123abc456";
input.dispatchEvent(new Event("input", { bubbles: true }));
expect(input.value).toBe("123456");
});
Здесь проверяется фильтрация нечисловых символов и нормализация строки.
Для полного контроля пользовательского сценария используется Cypress, который корректно эмулирует реальные браузерные события.
describe("Inputmask E2E", () => {
it("ввод телефона", () => {
cy.visit("/form");
cy.get("input#phone")
.type("9123456789")
.should("have.value", "+7 (912) 345-67-89");
});
});
E2E тесты фиксируют поведение, близкое к реальному пользовательскому вводу, включая задержки и порядок событий.
Особое внимание требуется нестандартным ситуациям:
Пример:
test("unicode ввод игнорируется", () => {
document.body.innerHTML = `<input id="field" />`;
const input = document.querySelector("#field");
Inputmask("9999").mask(input);
input.value = "12?34";
input.dispatchEvent(new Event("input", { bubbles: true }));
expect(input.value).toBe("1234");
});
При нестабильных тестах анализируется:
isCompleteДополнительно используются console-hooks внутри Inputmask для логирования промежуточных состояний.
Стабильность достигается через:
value setter, а не user typing
simulationТакая модель позволяет минимизировать влияние браузерных особенностей и получать детерминированные результаты поведения маски.