Поток выполнения в автоматизации браузера селена - PullRequest
0 голосов
/ 24 января 2019

Я не уверен насчет выполнения скрипта (автоматического теста) в селене. Я полагаю, что процесс, как показано ниже:

  • выполнение начинается.
  • Команда selenese преобразуется в запрос HTTP.
  • HTTP-сервер драйвера браузера получает HTTP-запрос.
  • Драйвер браузера определяет шаги, необходимые для реализации
    команда.
  • Драйвер браузера выполняет их в браузере.
  • Статус выполнения отправляется обратно на HTTP-сервер браузера. драйвер, а затем в сценарий (IDE).

Полагаю, это процесс. Пожалуйста, поправьте меня, где я не прав.

1 Ответ

0 голосов
/ 25 января 2019

Да, это так, широкими мазками.

Теория

webdriver calls flow

В полужирный & в полях указаны действующие стороны, в курсив и стрелки - используемые протоколы.

Если вы хотите взаимодействовать с браузером,

  1. ваш код использует клиент веб-драйвера (обычно это библиотека, например, selenium) на языке , который вы используете (Java, Python, Ruby и т. Д.) ).
  2. Этот клиент связывается с сервером веб-драйвера , отправляя и получая данные в соответствии с протоколом веб-драйвера ; этот протокол инкапсулирован в http для упрощения транспортировки и управления.
  3. Сервер вебдрайвера преобразует его в фактические команды для браузера - таким образом, он (браузер) взаимодействует со страницей или получает с нее данные.

Поток всегда сквозной (например, браузер никогда не связывается напрямую с вашим кодом:)) и двунаправленный. Отказ / исключение обычно передается только по вашему коду .


Некоторые детали

« веб-браузер браузера » на этом графике представляет собой двоичный файл (программа) - «geckodriver» для Firefox (с «.exe» в Windows) , "chromedriver", "safaridriver", "edgedriver.exe" (всегда с ".exe":)) . Он действует как прокси - с одной стороны, принимая и понимая команды в протоколе веб-драйвера, с другой - зная, как общаться с браузером.

Веб-драйвер всегда является сервером HTTP - все команды инкапсулированы в HTTP с обычными методами get / post / delete / put (закрыть, если не совпадает с обычным REST) ​​. Он реализует протокол веб-драйвера , поэтому клиенты (selenium & co) имеют четко определенный API для взаимодействия с ним. Таким образом, его также можно назвать «сервером веб-драйвера» - он слушает команды, передает их в браузер и возвращает ответы клиенту. (никто не называет это так :), но это облегчает различие между "исполняемым файлом webdriver" и "протоколом webdriver")

Будучи сервером, он связывает и прослушивает случайный сетевой порт - на вашем локальном компьютере или на удаленном. Если вы работаете локально, по этой причине его двоичный файл должен быть в вашей переменной path - при инициализации Selenium запускает его (поэтому он должен быть в состоянии найти его) и получает сетевой порт, который прослушивает (для дальнейшее общение) . Если вы используете удаленное соединение, вы должны либо: а) знать IP: порт удаленного сервера веб-драйвера, либо б) использовать «Selenium Hub», который отслеживает эту информацию в своем домене и делится ею с вами.


Связь между сервером веб-драйвера и браузером обычно выполняется в двоичном формате и зависит от браузера - он использует внутренние API, веб-драйвер знает, как лучше всего управлять этим конкретным браузером. Таким образом, драйверы предоставляются поставщиками браузеров. Это всегда локальная (на одной машине / ОС) связь (по крайней мере, насколько мне известно).


Если вы используете инфраструктуру более высокого уровня, такую ​​как Robot Framework, Cucumber, JBehave и т. Д., Она стоит перед «вашим кодом» на этой диаграмме, пытаясь оградить вас от некоторых вызовов селена.


На практике

«Картинка стоит тысячи слов», поэтому код должен быть чем-то вроде 740? :) Достаточно теории, вот практический пример:

from selenium import webdriver       # importing selenium bindings

wd = webdriver.Firefox()      # connect to the "webdriver server", a local one
element = wd.find_element_by_css_selector('#my-id')  # locate an element
the_text = element.text        # get is text

assert(text == 'My awesome text!')   # verify it's the expected one

Весь этот список ваш код в первой части - различные инструкции, управление потоком и проверки, которые выполняются для выполнения работы. В строке 1 библиотека Python selenium импортируется для дальнейшего использования.

Selenium - самая популярная платформа, реализующая протокол webdriver; он имеет реализации (т.е. привязки) для разных языков - python здесь, java , ruby ​​, javascript и так далее. Он стремится создать единый интерфейс для всех них - getText() в Java также доступен в Python как .text, и снова - и так далее. С помощью этого интерфейса он изолирует клиента от действующего протокола веб-драйвера - пользователь вводит .text, и ему все равно, как это выполняется на самом деле, и не должен менять свой код, если протокол изменяется.


В строке 3 объект webdriver создается; так как этот здесь - локальный сервер, процесс создания экземпляра проходит через локальные шаги, описанные ранее - «сервер веб-драйвера» запущен, его порт теперь известен (и хранится в объекте) , и связь может начаться .


В строке 4 в коде используется метод selenium для поиска определенного элемента на странице. Изнутри библиотека отправляет HTTP-запрос POST на сервер веб-драйвера, чтобы найти элемент.
Почему ПОСТ? Поскольку после успешного поиска сервер назначает ему внутренний идентификатор, который будет использоваться с этого момента; и возвращает идентификатор клиенту, который сохраняет его как свойство объекта element (* см. сноску) .
Как сервер веб-драйвера обнаруживает этот элемент? Нет как - он связывается с браузером через собственный протокол, говоря: «Эй, используя ваш механизм рендеринга и оценки, найдите элемент в DOM, который соответствует этому селектору CSS, и дайте мне ссылку, которую мы оба можем использовать в будущем. " (т. Е. "Магия":) . Так что это браузер, который делает работу, сервер веб-драйвера просто прокси-сервер связи.


Давайте разберемся со спецификой - строка 5 выполняет команду .text, которая, очевидно, возвращает текст элемента (если вы не знаете Python, не пугайтесь, как да, это команда, но в конце нет () - это странная странность, методы сглаживания в качестве свойств объекта, довольно удобная функция) .
Что происходит в этот момент: привязка к селену Python соответствует этой команде getElementText в ее общем интерфейсе; затем это сопоставляется с командой протокола webdriver (откройте ссылку, это интересно, обещаю) - это тип GET, и параметры для него - это то и это.
Он открывает сетевое соединение с "localhost: the_know_port", для этой конечной точки:

GET /session/2cce72b7-c748-48bc-b350-6dd6730b5a69/element/5/text

Первая «случайная» строка - это идентификатор сеанса - сервер веб-драйвера может использоваться многими клиентами, ваш устанавливается и хранится в строке 3. Второй параметр («5») - это идентификатор элемента, установленный в строке 4. Затем следует «текст» - запрашиваемый подресурс, один из поддерживаемых элементов.
И это печально известный протокол / API веб-драйвера - знание конкретных схем доступа (вы можете получить «текст» установленного элемента в сеансе) и поток (сначала необходимо установить общий сеанс, затем ссылка на элемент, поэтому, наконец, получим «текст») .

После этого сервер вебдрайвера заставляет браузер получать информацию из своего DOM («магия») и отправляет ее клиенту (экземпляр selenium) по сети:

{"sessionId":"2cce72b7-c748-48bc-b350-6dd6730b5a69","status":0,"value":"My awesome text!"}

Ваш экземпляр selenium ожидал ответа, получает и анализирует информацию из полезной нагрузки и возвращает значение в ваш код - переменная the_text теперь имеет значение «Мой потрясающий текст!».


И - сделано , цикл code -> webdriver client -> webdriver server -> browser -> webdriver server -> webdriver client -> code завершен.


Сноска:

(*) - это фактическая причина для страшного StaleElementReferenceException: все три - клиент, сервер веб-драйвера и браузер, содержат ссылку на элемент в DOM.
Но в определенный момент времени третья сторона - код javascript, работающий в браузере, изменяет / удаляет элемент, блаженно не подозревая, что что-то имеет ссылку, теперь она аннулирует (если подумать, довольно злой поступок: D) .
В следующий раз, когда клиент пытается взаимодействовать со ссылкой через сервер веб-драйвера в браузере - элемент больше не существует. Естественно, взаимодействие терпит неудачу, сбой возвращается обратно к клиенту и появляется за исключением; его текстовое сообщение «Элемент больше не привязан к DOM», что, как мы надеемся, немного загадочно, теперь имеет смысл.

...