Интеграционное тестирование в контексте использования Choices.js направлено на проверку корректного взаимодействия библиотеки с окружающей системой: DOM-структурой, пользовательскими событиями, серверными API, формами, валидацией и сторонними JavaScript-модулями. В отличие от модульных тестов, здесь проверяется не изолированная функция, а цепочка поведения компонента в реальной среде браузера или её эмуляции.
Choices.js представляет собой компонент для кастомизации
<select> и <input> элементов с
поддержкой поиска, мультиселекта, тегов и динамических источников
данных. При интеграционном тестировании ключевое значение имеют
следующие аспекты:
input, change,
search, addItem, removeItemЭти особенности требуют тестирования не только логики, но и поведения интерфейса в реальном времени.
Для интеграционного тестирования Choices.js чаще всего применяются:
Базовая конфигурация с jsdom позволяет симулировать DOM:
import Choices from 'choices.js';
document.body.innerHTML = `
<sel ect id="city">
<option value="1">London</option>
<option value="2">Paris</option>
</select>
`;
Инициализация компонента:
const element = document.getElementById('city');
const choices = new Choices(element, {
searchEnabled: true,
removeItemButton: true
});
Интеграционный тест должен подтверждать, что:
test('инициализация Choices.js создаёт кастомный UI', () => {
expect(document.querySelector('.choices')).not.toBeNull();
expect(document.querySelectorAll('.choices__item').length).toBeGreaterThan(0);
});
Важным моментом является проверка синхронизации между DOM и внутренним состоянием экземпляра.
Интеграционные сценарии включают симуляцию действий пользователя:
Пример с Testing Library:
import { fireEvent } fr om '@testing-library/dom';
const input = document.querySelector('.choices__input--cloned');
fireEvent.focus(input);
fireEvent.input(input, { target: { value: 'Pa' } });
Ожидается фильтрация списка:
expect(document.querySelectorAll('.choices__item--choice').length).toBe(1);
Choices.js активно используется для мультивыбора, что требует проверки сложных состояний.
Ключевые сценарии:
<select>choices.setChoiceByValue('1');
choices.setChoiceByValue('2');
expect(element.selectedOptions.length).toBe(2);
Удаление элемента:
choices.removeActiveItemsByValue('1');
expect(element.selectedOptions[0].value).toBe('2');
Особое внимание уделяется синхронизации состояния между UI и DOM.
Одним из критичных сценариев является работа внутри
<form>.
Проверяется:
const form = document.querySelector('form');
form.dispatchEvent(new Event('submit'));
const data = new FormData(form);
expect(data.getAll('city')).toContain('2');
Сброс формы должен очищать внутреннее состояние Choices:
form.reset();
expect(element.selectedOptions.length).toBe(0);
Choices.js поддерживает динамическую загрузку через
fetch или пользовательские источники данных. Интеграционное
тестирование в этом случае требует мокирования сетевых запросов.
Пример с Jest:
global.fetch = jest.fn(() =>
Promise.resolve({
json: () => Promise.resolve([
{ value: '1', label: 'London' },
{ value: '2', label: 'Paris' }
])
})
);
Проверка подгрузки:
await choices.setChoices(async () => {
const response = await fetch('/api/cities');
return response.json();
});
Ожидается, что элементы появятся в DOM:
expect(document.querySelectorAll('.choices__item--choice').length).toBe(2);
Choices.js генерирует набор событий, которые часто используются для интеграции с бизнес-логикой:
addItemremoveItemhighlightItemsearchПроверка событий:
const handler = jest.fn();
element.addEventListener('addItem', handler);
choices.setChoiceByValue('1');
expect(handler).toHaveBeenCalled();
Важно проверять не только факт вызова, но и передаваемые данные события:
const event = handler.mock.calls[0][0];
expect(event.detail.value).toBe('1');
Choices.js часто используется совместно с системами валидации:
Проверяется синхронизация состояния ошибки:
element.setCustomValidity('Required');
expect(element.checkValidity()).toBe(false);
Интеграционный сценарий включает проверку, что UI отражает состояние ошибки.
В реальных приложениях на одной странице может быть несколько экземпляров Choices.js. Тестирование должно исключать перекрёстное влияние:
const first = new Choices(document.getElementById('first'));
const second = new Choices(document.getElementById('second'));
first.setChoiceByValue('1');
expect(second.getValue()).toEqual([]);
Это проверяет изоляцию состояний.
Корректное освобождение ресурсов важно при SPA:
choices.destroy();
Проверяется:
expect(document.querySelector('.choices')).toBeNull();
При использовании Cypress или Playwright проверяются реальные браузерные сценарии:
Пример Cypress:
cy.get('.choices__input').type('Pa');
cy.get('.choices__item--choice').first().click();
cy.get('select').should('have.value', '2');
Choices.js должен корректно взаимодействовать с ARIA-атрибутами:
aria-expandedaria-selectedrole="listbox"Тестируется:
expect(document.querySelector('.choices__list')).toHaveAttribute('role', 'listbox');
Также проверяется навигация с клавиатуры:
В процессе тестирования Choices.js часто выявляются следующие проблемы:
Эти проблемы требуют повторного запуска тестов в различных условиях и строгого контроля асинхронных операций.
Для повышения надёжности интеграционных тестов применяются:
waitForjest.useFakeTimers)Особенно важно учитывать задержки при рендере и поисковой фильтрации, так как Choices.js может обновлять UI асинхронно.