Тесты на Cypress могут быть довольно быстрыми. Иногда даже быстрее, чем тестируемое приложение. Если вы столкнулись с ситуацией, когда Cypress работает быстрее, чем загружается ваше приложение, то эта статья для вас.
Содержание:
Подпишитесь на наш ТЕЛЕГРАМ КАНАЛ ПО АВТОМАТИЗАЦИИ ТЕСТИРОВАНИЯ
Событие загрузки страницы
Если вы нашли эту статью через поиск в Google, то, возможно, столкнулись с проблемой, где выводится такое сообщение: “Timed out after waiting 60000ms for your remote page to load”.
![Timed out after waiting 60000ms for your remote page to load](https://qarocks.ru/wp-content/uploads/2023/10/pageloadtimeout_error_mxm3ft.png)
Это сообщение появляется, когда на странице не срабатывает load
событие. Но что же это такое на самом деле?
Согласно MDN docs, событие load
– это то, что выводит браузер после загрузки всех ассетов страницы.
Что же это означает?
Всякий раз, когда вы вводите в браузер URL и нажимаете клавишу Enter, браузер выполняет GET
API запрос по этому адресу. Аналогично происходит при тестировании API с помощью Postman или Cypress. Вместо того, чтобы получить JSON
-структурированный объект, вы получите HTML
файл.
Упрощенный вариант такого файла будет выглядеть следующим образом:
<html> <head> <title>My page</title> <link rel="stylesheet" href="style.css"> <script src="app.js" defer></script> </head> <body> Hello world! </body> </html>
Браузер заглянет в HTML-файл и запросит все остальные файлы, связанные с ним. Обратите внимание, что у нас есть style.css
и app.js
файлы. Браузер загрузит их и, как только закончит, вызовет load
событие, которое и ждет Cypress.
Это именно тот момент, когда можно сказать, что приложение готово. В реальности многие сайты имеют динамические .js
файлы, которые вызывают API, загружающие ресурсы с сервера, или анимируют какие-то элементы на странице. Это может привести к тому, что приложение все еще будет находиться в режиме “загрузки”. Неизвестно, сколько ресурсов загрузят эти .js
файлы, и сколько времени займет их загрузка. Хотя событие load
является хорошей контрольной точкой, в современных веб-приложениях оно редко бывает последним, что происходит на странице.
Если вы видите ошибку, что Cypress не смог загрузить вашу страницу, то, скорее всего, загрузка не происходит, потому что что-то ее блокирует.
Недавно я анализировал ошибку на демо-сайте от Sauce labs. Причина проблемы заключалась в неправильной конфигурации service worker, что привело к отсутствию
load
события. Для решения проблемы необходимо было заглушить вызов API service-worker, по сути, отключив его. Я добавил следующий код и перезагрузил браузер.cy.intercept('/service-worker.js', { body: undefined })
Ожидание сетевых запросов
Другим способом обеспечения загрузки страницы является ожидание сетевого запроса. Например, если у вас есть to-do приложение, которое будет загружать все таски, открыв приложение, вы можете использовать перехват сетевого запроса, который будет следить за выполнением этого запроса, и страница не будет считаться полностью загруженной до его завершения:
it('testing todos', () => { cy.intercept('/todos').as('todos') cy.visit('/') cy.wait('@todos') // page is loaded, continue with the test })
Поскольку cy.wait()
будет ждать не только выполнение запроса, но и получение ответа, это может быть надежным способом убедиться в том, что ваша страница загружена правильно.
Если у вас несколько вызовов API, вы можете перехватить их все и заставить ваш тест ждать их выполнения, передав массив псевдонимов команде cy.wait()
следующим образом:
it('testing todos', () => { cy.intercept('/todos').as('todos') cy.intercept('/profile').as('profile') cy.visit('/') cy.wait(['@todos', '@profile']) // page is loaded, continue with the test })
Другим способом ожидания нескольких запросов является использование cy.get('@alias.all')
синтаксиса. Таким образом, можно дождаться выполнения всех запросов.
it('testing todos', () => { cy.intercept('**').as('requests') cy.visit('/') cy.get('@requests.all') .should('have.length', 10) // all 10 requests have been sent })
Однако есть две небольшие загвоздки. Метод cy.get()
будет ожидать выполнения запроса только 4000 мс, так как он использует параметр defaultCommandTimeout
, а не responseTimeout
как в случае с cy.wait()
. Если ваши запросы загружаются дольше, необходимо изменить параметр timeout
в команде cy.get()
. Кроме того, метод cy.get()
будет ожидать только инициирование запроса, но не будет ожидать ответа.
Однако встроенная в Cypress возможность повторных запросов может нам помочь, потому что мы можем проверить статус-код последнего запроса:
it('testing todos', () => { cy.intercept('**').as('requests') cy.visit('/') // set longer timeout cy.get('@requests.all', { timeout: 30000 }) .should('have.length', 10) .its('9.response.statusCode') // check last request .should('eq', 200) })
Ожидание DOM
Другой способ убедиться в том, что приложение полностью загружено, – заглянуть в DOM (Document Object Model). Таким образом, мы можем убедиться, что не делаем того, чего не ожидаем от реального пользователя.
Например, в реальном мире вы, скорее всего, не будете взаимодействовать с приложением, пока на странице все еще присутствует анимация “загрузки”. Вы можете добавить в свой тест защитную функцию, чтобы убедиться, что загрузчик исчезнет до того, как вы начнете взаимодействовать со страницей.
it('testing todos', () => { cy.visit('/') // page loading, wait for loader to disappear cy.get('.loader') .should('not.exist') // continue with our test })
Использование отрицательных проверок (например, проверка отсутствия элемента на странице) может быть сложным, особенно если скорость загрузки страницы или анимация элемента .loader влияют на это. В таких случаях, перед проверкой отсутствия элемента, может быть полезно сначала удостовериться, что элемент видим на странице с помощью .should('be.visible')
.
Чтобы упростить этот процесс, мы можем просто использовать cy.get()
для первичного взаимодействия с элементом, с которым мы хотим работать. Если этот элемент занимает больше времени для появления на странице, вы можете добавить тайм-аут.
Тайм-аут по умолчанию
Иногда лучше всего придерживаться простого подхода. Метод cy.visit()
будет ждать 60 секунд, пока сработает load
событие. Это достаточно долгое время, поскольку реальные пользователи обычно не обладают таким терпением. Если команда cy.visit()
не срабатывает, то, скорее всего, следует исправить само приложение и использовать этот тайм-аут в качестве контрольной точки производительности. В качестве альтернативы можно уменьшить тайм-аут, изменив параметр pageLoadTimeout
в конфигурации. О различных тайм-аутах читайте в документации Cypress.
Перевод статьи «How to wait for page to load in Cypress».