Вопрос или проблема
У меня настроены Jest и JSDOM для запуска тестов для приложения на JQuery. У меня есть этот тест на то, что происходит, когда вы обновляете родительский вопрос, что должно добавить класс к измененному вопросу.
const updatedValue="Да";
// Родительский вопрос
$('[data-qid="217ec445"]').find('select').val(updatedValue);
$('[data-qid="217ec445"]').find('select')[0].dispatchEvent(new Event('change')); // вручную вызываем событие change
// Дочерний вопрос
const isHidden = $('[data-qid="1ff03b89"]').hasClass('isHidden');
expect(isHidden).toBeFalsy();
Этот тест не проходит, когда код написан с делегированным слушателем, как это:
$('[data-qid="217ec445"]').on('change', 'select', _parentsChangeHandler);
Однако тест проходит, когда код написан с обычным слушателем, как это:
$('[data-qid="217ec445"]').find('select').on('change', _parentsChangeHandler);
Из-за динамического HTML приложения нужен делегированный слушатель. Как заставить делегированные слушатели работать в Jest и JSDOM?
Ответ или решение
Чтобы протестировать делегированные слушатели событий с использованием jQuery, JSDOM и Jest, необходимо учитывать некоторые особенности работы делегированных слушателей. В вашем случае, когда слушатель прикрепляется с помощью делегирования, важно убедиться, что события корректно обрабатываются, даже если элементы добавляются динамически.
Вот подход, который поможет вам успешно протестировать сценарий с делегированными слушателями:
-
Проверка структуры HTML: Убедитесь, что HTML-структура вашего DOM корректно имитируется в тестах. Если элемент, который вы хотите протестировать, не существует в момент, когда вызывается событие, слушатель не сработает.
-
Использование jQuery для установки слушателей: Убедитесь, что вы добавляете прослушиватель событий после того, как ваш компонент был добавлен в DOM. В идеале ваш код для установки слушателя должен быть выполнен в блоке
beforeEach
, чтобы гарантировать, что все слушатели установлены перед каждым тестом. - Правильный порядок обработки событий: Когда вы вызываете метод
dispatchEvent
, убедитесь, что целевой селектор ('select'
) находится внутри родительского элемента, к которому прикреплен ваш делегированный слушатель.
Ниже представлена примерная реализация теста с учетом указанных выше моментов:
import $ from 'jquery';
describe('Тестирование делегированного слушателя событий', () => {
beforeEach(() => {
// Создание тестовой структуры HTML
document.body.innerHTML = `
<div data-qid="217ec445">
<select>
<option value="No">No</option>
<option value="Yes">Yes</option>
</select>
</div>
<div data-qid="1ff03b89" class="isHidden"></div>
`;
// Установка делегированного слушателя
$('[data-qid="217ec445"]').on('change', 'select', _parentsChangeHandler);
});
it('должен обновить класс у дочернего вопроса при изменении значения', () => {
const updatedValue = "Yes";
// Обновление значения и вызов события изменения
$('[data-qid="217ec445"]').find('select').val(updatedValue);
$('[data-qid="217ec445"]').find('select')[0].dispatchEvent(new Event('change'));
// Проверка, изменился ли класс у дочернего элемента
const isHidden = $('[data-qid="1ff03b89"]').hasClass('isHidden');
expect(isHidden).toBeFalsy();
});
});
// Пример обработчика события
function _parentsChangeHandler(event) {
const selectedValue = $(event.target).val();
if (selectedValue === "Yes") {
$('[data-qid="1ff03b89"]').removeClass('isHidden');
} else {
$('[data-qid="1ff03b89"]').addClass('isHidden');
}
}
Объяснение решения:
- Создание HTML: Мы создаем необходимую структуру HTML перед каждым тестом.
- Установка делегированного слушателя: Слушатель на событие
change
добавляется в корневой элемент перед выполнением теста, обеспечивая его доступность при любом изменении. - Тестирование: Мы обновляем значение в
<select>
и инициируем событиеchange
, ожидая, что соответствующий класс у дочернего элемента будет изменен.
Таким образом, с помощью этого подхода вы можете эффективно тестировать делегированные слушатели в вашей jQuery-приложении, используя Jest и JSDOM. Если у вас возникнут дополнительные вопросы или потребуются разъяснения, не стесняйтесь обращаться.