Как устроен Selenium: Эпизоды 1 — 2

Автор оригинала: David Burns
  • Перевод
Перевод статьи подготовлен в преддверии старта курса «Java QA Engineer».




Эпизод 1 — Транспортировка


В результате диалога, произошедшего в последние выходные января 2020 года, который был посвящен одной из проблем в Selenium, где кто-то сказал мне «почему ты просто не сделаешь так…» в ответ на объяснение проблемы, я решил написать серию статей, объясняющих команды в Selenium WebDriver и почему мы в итоге пришли к дизайну, который имеем сегодня.

Я буду повторять это в каждом эпизоде этой серии — много, иногда до безумия много размышлений и продумывания было вложено в работу каждой мельчайшей детали Selenium.

Почему?

По воле случая и благодаря тому, насколько хорошо он делает то, для чего предназначен, Selenium используется миллионами людей по всему миру. Именно так широчайший спектр компаний от небольших стартапов до Microsoft и Google следят за тем, чтобы их сайт работал в каждом браузере.

Как Selenium взаимодействует с браузером?


За годы работы Selenium мы в итоге остановились на использовании HTTP в качестве способа взаимодействия с браузером. Мы создали REST-ish API (REST-ish — в духе REST), который может использовать каждая клиентская привязка и получать, как мы надеемся, одинаковые результаты.

HTTP и REST-ish? Серьезно?

Дааа…

Начнем с HTTP-части. Когда мы только начинали, нам приходилось поддерживать разные способы взаимодействия с каждым браузером, основанные на лучшем подходе для каждого из них. Например, для Internet Explorer мы написали COM код. Он хорошо работал, но от него у нас до сих пор ночные кошмары. Для Firefox мы написали считывающего строку за строкой монстра, который, к счастью, благодаря подходу Mozilla «сделай браузер своим» был способен на многое. Opera позволяла нам войти через DevTools протокола.

Таким образом, это означало, что, особенно в первые годы существования WebDriver, нам нужно было поддерживать N:M привязок, где N — привязки языка, а M — браузеры, которые мы поддерживаем. Этот путь не ведет к хорошему продукту. Мы решили, что нам нужно что-то, что будет понимать каждый язык. Нам также нужно было что-то довольно надежное. Так выбор пал на HTTP, и мы приступили к созданию JSONWireProtocol.

В рамках JSONWireProtocol мы построили REST-ish интерфейс, который общается на JSON. Я говорю REST-ish, потому что он не следует абсолютно всем принципам REST, а скорее воплощает их в степени достаточной для того, чтобы сделать его мощным инструментом для наших задач.

Что по отношению к текущему положению вещей?

Web, Интернет и мир двигаются дальше. Так почему же Selenium нет?

Это хороший вопрос, но дело в том, что мы пытаемся модернизироваться. К сожалению, для сети характерно состояние, когда она не работает, если она не запущена. HTTP довольно надежен в качестве протокола. Он также позволяет людям создавать кластеры для тестирования, не беспокоясь о том, как будет работать мультиплексирование. Это причина, по которой была создана Selenium Grid, которая до сих пор остается хорошим выбором, когда речь заходит об организации тестирования несколькими устройствами и компьютерами.

Но это больше похоже на сеть.

Итак… Существуют инструменты, которые используют для управления Chrome его протокол отладки (Chrome Debug Protocol). Некоторые вещи они делают лучше чем Selenium, что является следствием их выбора способа общения с браузером. К сожалению, это проприетарный протокол Chrome, и делать его доступным для других браузеров не в интересах Google.

Кроме того, игнорируя интересные дизайнерские решения от команды Google, есть такая проблема, что у нас должно быть постоянно открытое соединение. В данном случае он использует WebSockets, но вам следует вспомнить мой комментарий выше о том, что интернет недоступен, пока он не работает. WebSockets будет постоянно восстанавливать соединение. Существует также проблема того, сколько трафика будет идти вверх и вниз по этому каналу.

Это не проблема для кукловода, когда вы взаимодействуете с чем-то только на своем локальном компьютере, но если вы объединяете CI службу, такую ​​как Circle CI или TravisCI и что-то вроде AWS Device Farm, Sauce Labs или BrowserStack, между вами и вашем раннером внезапно встает интернет, а эти данные должны доходить до адресатов.

Рабочая группа W3C Browser Testing and Tools, состоящая из поставщиков браузеров и ребят из Selenium, пытается спроектировать, как все должно выглядеть, чтобы быть уверенными в том, что мы можем обеспечивать кроссбраузерность с самого начала, не прибегая к странным хакерским патчам и личной поставке этих браузеров.

Хотите узнать больше?




Эпизод 2 — Навигация


В этом эпизоде ​​мы рассмотрим огромное количество работы, связанной с навигацией.

from selenium import webdriver

driver = webdriver.Firefox()
driver.get("https://www.theautomatedtester.co.uk")


То, что мы видим выше… выглядит достаточно просто, верно… а вот и нет!

На самом деле, это подводит меня к натертой на интервью мозоли. Если кто-то когда-нибудь попросит вас описать, что происходит в браузере, когда вы набираете URL и нажимаете ввод, существует высокая вероятность того, что он не имеет реального представления о том, что происходит в навигации. Во всяком случае… возвращаясь к Selenium и его навигации.

driver.get

Как только мы отправим запрос через транспортный слой, начинается настоящее веселье. Нам нужно выяснить, куда мы хотим попасть, и сказать браузеру, чтобы он отправился туда для нас. К сожалению, это приведет к первой из многих проблем для автоматизаторов.

Сертификаты


Если вы когда-либо работали в крупных корпоративных компаниях, где технологии не является основной, вы понимаете, с какой болью может сталкиваться команда разработчиков. Теперь удвойте эту боль, и вы сможете представить боль, с которой приходится сталкиваться тестерам и автоматизаторам.

Одна из этих болей — сертификаты. Компании скупы и будут делать самозаверяющие сертификаты и прочие уродства. Особенно в ранние дни Selenium, когда не было таких сервисов, как Let's Encrypt. И даже сейчас большинство разработчиков и QA-групп редко имеют доступ к изменению конфигурации в своих тестовых средах или на своих CI-серверах. Нам нужно было найти способ обойти сертификаты. (Это одна из первых причин, по которой Selenium рассматривается как угроза безопасности).

Таким образом, каждый из браузеров пропускает плохо настроенные сертификаты при автоматизации. Если бы не реализовали это, то многие тестировщики/разработчики не имели возможности протестировать их сайты.

Теперь… когда мы обошли первую проблему, нам нужно перейти к загрузке страницы.

Загрузка


Как только мы получим сертификаты, мы получаем для загрузки страницу. К счастью, нам не нужно делать ничего сложнее, чем эквивалент

location = "https://www.theautomatedtester.co.uk"; 
// или
window.location.href = "https://www.theautomatedtester.co.uk";


Готово…


Когда Selenium «закончит» команду, мы получим возврат. Итак, нам просто нужно дождаться окончания загрузки страницы. Если быть до конца откровенным, то что вообще означает «законченная загрузка»?

В браузере будет запущено несколько разных событий. Мы узнаем, когда страница будет показана, а затем каков ее readyState. Selenium проверит все это и также будет ожидать DOMContentLoaded.

А затем возникает проблема, если вы находитесь на странице и пытаетесь перейти к якорю на этой странице. Давайте посмотрим на следующий пример.

from selenium import webdriver

driver = webdriver.Firefox()
driver.get("https://www.theautomatedtester.co.uk")
driver.get("https://www.theautomatedtester.co.uk#someAnchor")


О, только посмотрите, ни одно из событий загрузки страницы не будет запущено! Класс? Глупый браузер сработает эффективно и просто прокрутит до якоря. Это означает, что мы не можем зависеть исключительно от событий, исходящих со страницы.

Нет, поэтому нам нужен специальный код для этого случая и понимание того, что означает «готово» в этом случае. Если мы ошибемся, это создаст много нестабильных тестов. Нестабильные тесты делают людей сварливыми, и мы не хотим сварливых разработчиков, их достаточно в мире и без нестабильных тестов.

После того, как мы выполнили эти проверки, и вы можете манипулировать тем, как мы смотрим на эти события, если вы хотите, чтобы они загружались быстрее, используя Page Load Strategies. Это больше павер юзер фича, по этому я бы не стал о них заморачиваться сейчас, но они влияют на скорость команд навигации.

Что насчет JavaScript Frameworks и навигации


Это то место, где сосредоточено все «веселье». Многие фреймворки будут еще много догружать после первоначальной загрузки на страницу. Если вы когда-либо работали над одностраничным приложением или просто использовали его, вы видели много элементов, отображаемых по мере их загрузки. К сожалению, это означает, что вы не можете просто полагаться на возврат команды навигации. Вам нужно будет добавить команду WebDriverWait в ваш код, как показано ниже, чтобы убедиться, что ваш тест находится в правильном состоянии, прежде чем отправиться делать то, что ему нужно.

from selenium import webdriver
from selenium.webdriver.support.wait import WebDriverWait

driver = webdriver.Firefox()
driver.get("https://www.theautomatedtester.co.uk")
element = WebDriverWait(driver, 10).until(lambda x: x.find_element_by_id(“someId”))


Заключение


При загрузке страницы не всегда полагайтесь на возврат Selenium по завершении загрузки страницы. Если вам нужно посмотреть на элемент на странице, то сделайте это. Просто знайте, как JavaScript на странице может изменить ее после первоначальной загрузки.

Для дальнейшего чтения






Узнать подробнее о курсе.


OTUS. Онлайн-образование
Цифровые навыки от ведущих экспертов

Комментарии 0

Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

Самое читаемое