Unpoly — это JavaScript-библиотека, упрощающая работу с асинхронными запросами и динамическими обновлениями страниц без перезагрузки. В контексте тестирования асинхронных операций важно учитывать специфику работы Unpoly: действия, инициированные библиотекой, не происходят мгновенно, а требуют времени на выполнение HTTP-запросов, рендеринг и обновление DOM.
Все основные методы Unpoly, такие как up.navigate,
up.replace или up.append, выполняют сетевые
запросы и обновляют страницу асинхронно. Это означает, что результат
операции может быть недоступен сразу после вызова функции. Для
корректного тестирования необходимо синхронизироваться с завершением
этих действий.
Unpoly предоставляет встроенные события, которые позволяют отслеживать жизненный цикл асинхронных операций:
up:request — вызывается перед
отправкой HTTP-запроса.up:response — вызывается после
получения ответа, но до обновления DOM.up:fragment:inserted — вызывается
после вставки обновлённого фрагмента в DOM.up:complete — вызывается после
завершения всех операций, связанных с запросом.Для тестов наибольшее значение имеют события
up:fragment:inserted и up:complete, так как
они гарантируют, что изменения DOM уже произошли.
Unpoly позволяет работать с промисами для асинхронного контроля.
Например, метод up.request возвращает объект
Promise, который разрешается после завершения всех
действий:
up.request('/users/42', { target: '#user-details' })
.then(() => {
// DOM обновлён, можно проверять содержимое
const content = document.querySelector('#user-details').textContent;
console.assert(content.includes('John Doe'));
})
.catch(error => {
console.error('Ошибка при запросе:', error);
});
Такой подход облегчает интеграцию с современными фреймворками
тестирования, такими как Jest или Mocha, где асинхронные тесты
определяются с использованием async/await или возвращаемых
промисов:
test('Детали пользователя отображаются после запроса', async () => {
await up.request('/users/42', { target: '#user-details' });
const content = document.querySelector('#user-details').textContent;
expect(content).toContain('John Doe');
});
up.onВ некоторых случаях удобнее отслеживать события напрямую, особенно если нужно протестировать пользовательские действия, такие как клик по ссылке, вызывающий обновление фрагмента:
up.on('up:fragment:inserted', '#user-details', () => {
const content = document.querySelector('#user-details').textContent;
expect(content).toContain('John Doe');
});
document.querySelector('#load-user-btn').click();
В этом примере проверка выполняется только после того, как фрагмент с деталями пользователя вставлен в DOM.
Тестирование асинхронного поведения может потребовать дополнительных
механизмов ожидания. В Unpoly для тестов можно использовать короткие
задержки или функции вроде up.macro.wait (если
интегрирована соответствующая утилита), чтобы убедиться, что все
промежуточные анимации и отложенные изменения завершены:
await up.request('/notifications', { target: '#notifications' });
await new Promise(resolve => setTimeout(resolve, 100)); // ожидание анимации
const notifications = document.querySelectorAll('#notifications .notification');
expect(notifications.length).toBeGreaterThan(0);
up.navigate или up.replace без ожидания
события или промиса приведёт к тому, что DOM ещё не обновлён.up:fragment:inserted, чтобы тест ждал именно
нужного элемента.up.motion(false), либо учитывать
задержку.async/await и промисами.cy.get с опцией
.should('contain', ...), что автоматически ждет появления
элементов, заменяя необходимость явного ожидания событий.cy.get('#load-user-btn').click();
cy.get('#user-details').should('contain', 'John Doe');
Такой подход позволяет скрыть внутренние асинхронные детали Unpoly за абстракцией фреймворка тестирования.
Асинхронность в тестах с Unpoly требует внимательного контроля за моментом, когда DOM уже обновлён и все запросы завершены. Использование событий, промисов и правильное ожидание гарантирует стабильность тестов и корректное отслеживание динамических изменений интерфейса.