
Один из распространённых сценариев работы с веб-приложениями заключается в открывании нового окна (или вкладки) браузера после выполнения пользователем определённого действия. Многие веб-разработчики используют HTML-тэг
__blank, приказывающий браузеру при нажатии на ссылку открыть новое окно (или вкладку, это зависит от выбранных пользователем настроек). Работа с окнами в Selenium при помощи PHP может использоваться для автоматизации взаимодействия с окнами, вкладками и даже всплывающими окнами браузера.
Всплывающие окна могут иногда раздражать посетителей веб-сайта, однако зачастую у разработчика нет иного выхода, кроме как использовать их. Как Selenium различает окна и вкладки? Как можно использовать автоматизацию для беспроблемного переключения между окнами или вкладками браузера? Как реализовать работу с окнами в Selenium?
В этой статье мы подробно рассмотрим применение Selenium для автоматизации взаимодействия с браузерами, вкладками и всплывающими окнами. Для демонстрации работы с окнами в Selenium PHP мы воспользуемся PHPUnit — фреймворком юнит-тестирования для PHP.
Что такое дескриптор окна?
Дескриптор окна (window handle) — это уникальный идентификатор, основная задача которого заключается в хранении адресов всех окон. При создании экземпляра Selenium WebDriver окну назначается алфавитно-цифровой ID. Этот уникальный ID называется дескриптором окна — указателем на окно, позволяющим идентифицировать окно браузера.
Для каждого окна/вкладки/всплывающего окна дескриптор окна (или ID) уникален. Для переключения между окнами (или вкладками) Selenium WebDriver использует функции дескрипторов окон в Selenium PHP.
Уникальный ID сохраняется до закрытия сессии Selenium WebDriver (выполняемого через API WebDriver.Quit или WebDriver.Close). Функции дескрипторов окон используются для получения подробной информации о дескрипторах всех окон. Фундаментальные основы работы с окнами в Selenium остаются неизменными, вне зависимости от того, используете ли вы Selenium с PHP или Selenium с другими языками программирования (например, Python, Java, и т. п.).
Вот некоторые из самых распространённых сценариев, в которых приходится иметь дело с множественными окнами (или вкладками):
- Формы, требующие выбора даты в новом открытом окне
- Нажатия кнопок, открывающие новую вкладку (или окно)
- Всплывающие окна, используемые для показа конечному пользователю каких-либо предложений; эту стратегию часто используют порталы с вакансиями
- Работа с окнами, отображающими рекламу

Пример сценария, в котором нажатие на родительское (или базовое) окно открывает два «дочерних окна». Каждое из них имеет уникальный дескриптор окна, и этот дескриптор хранится, пока окна не будут уничтожены (т. е. закрыты). Общее количество окон становится равным трём (parent + child-1 + child-2). При нажатии кнопки/ссылки в «Child-1» и «Child-2», соответственно, откроется окно «Grand Child-1» и «Grand Child-2». После этого суммарно будет открыто пять окон, и каждое из них будет иметь уникальный дескриптор окна, который можно использовать для автоматизации операций с окном.
Команды для работы с окнами в Selenium с PHP
Selenium предоставляет различные методы для работы с несколькими окнами. Вы можете также изучить наше руководство по работе с несколькими окнами при помощи Selenium и Protractor. Ниже представлены самые часто используемые при тестировании Selenium PHP команды для переключения окон браузера и работы со всплывающими окнами.
Если вы специалист по PHP, то вы можете получить сертификат специализации в программировании на базовом PHP и расширить свои возможности для развития своей карьеры в сфере автоматического тестирования PHP.
▍ SwitchTo Window
Команда SwitchTo используется для переключения фокуса на новое окно или вкладку браузера. Для переключения фокуса на новое окно в качестве аргумента команде передаётся дескриптор окна соответствующего окна браузера.
/* $wHandle - это дескриптор окна (или ID), на которое нужно выполнить переключение */ $this->webDriver->switchTo()->window($wHandle); /* Переключение также можно выполнять получением количества окон при помощи getWindowHandles или getWindowHandle */ $this->webDriver->switchTo()->window($HandleCount[win-number]);
▍ getWindowHandle
Метод getWindowHandle в Selenium PHP возвращает Window ID (уникальный алфавитно-цифровой идентификатор окна) для текущего активного (или находящегося в фокусе) окна.
$wHandle = $this->webDriver->getWindowHandle();
В показанном выше примере $wHandle — это ID окна, полученный при помощи метода getWindowHandle.
▍ getWindowHandles
Это важный метод для работы с окнами в Selenium с PHP. Метод getWindowHandles возвращает множество дескрипторов окон (и вкладок), открытых одним экземпляром драйвера, в том числе родительских и дочерних окон. Например, если операция «щелчок на кнопке» в родительском окне открывает новую вкладку, то метод getWindowHandles вернёт дескрипторы родительского и дочернего окна (например, вкладки). Если затем к множеству, возвращённому методом getWindowHandles, применить оператор sizeof, то он вернёт размер множества (в данном случае 2).
Аналогично, если открытая в родительском окне веб-страница открывает 8 всплывающих окон, то количество дескрипторов, полученных применением оператора sizeof для множества, возвращённого getWindowHandles, будет 9.
Каждое из окон будет иметь уникальный дескриптор окна (или идентификатор) для удобства идентификации окна.
/* В случае веб-страницы, открывающей новую вкладку, getWindowHandles возвращает массив, состоящий из двух дескрипторов окон (т. е. дескрипторов родительского и дочернего окон) */ $HandleCount = $this->webDriver->getWindowHandles(); /* Возвращает размер массива дескрипторов окон. В данном примере он будет равен 2 */ echo ("\n Total number of window handles are " . sizeof($HandleCount)); /* Печать дескриптора окна в родительском окне */ echo ("\n Window 0: " . $HandleCount[0]); /* Печать дескриптора окна в дочернем окне */ echo ("\n Window 0: " . $HandleCount[1]);
Как работать с несколькими окнами, вкладками и всплывающими окнами в Selenium PHP
Мы продемонстрируем сценарии тестов работы с окнами в Selenium PHP при помощи PHPUnit в облачном Selenium Grid сервиса LambdaTest. Кросс-браузерное тестирование при помощи PHPUnit в облачном Selenium Grid помогает в тестировании на различных сочетаниях браузеров, платформ и эмуляторов устройств.
Для начала создадим аккаунт LambdaTest и обратим внимание, что user-name и access-key доступны на странице профиля. Тесты выполняются на сочетании Chrome 85.0 + Windows 10. Возможности браузера сгенерированы при помощи генератора возможностей LambdaTest.

Для установки фреймворка PHPUnit мы создаём для этого проекта файл composer.json:
{ "require":{ "php":">=7.1", "phpunit/phpunit":"^9", "phpunit/phpunit-selenium": "*", "php-webdriver/webdriver":"1.8.0", "symfony/symfony":"4.4", "brianium/paratest": "dev-master" } }
Введём команду composer require и дважды нажмём на кнопку «Enter», чтобы приступить к установке фреймворка PHPUnit. После завершения фреймворк PHPUnit (версии 9.3) будет установлен.
Файл composer.lock содержит информацию о зависимостях, а в папке vendor содержатся все зависимости.

Файл vendor/autoload.php будет использоваться в коде тестов, чтобы классы (и их методы), предоставленные этими библиотеками, можно было использовать в реализации.
Теперь настало время продемонстрировать различные сценарии работы с окнами в Selenium с PHP.
▍ Работа с несколькими окнами браузера в Selenium PHP
Для демонстрации работы с несколькими окнами в Selenium PHP мы используем следующий тестовый сценарий:
- Открываем страницу LambdaTest в браузере Chrome.
- Получаем дескриптор текущего окна в фокусе.
- Открываем страницу блога LambdaTest в новом окне при помощи HTML-атрибута __blank.
- Печатаем соответствующие дескрипторы окон.
- Переключаемся на окно, где открыт второй URL.
- Добавляем утверждение на случай, если заголовок окна не соответствует ожидаемому заголовку.
- Закрываем окно в фокусе.
- Переключаемся на первое окно и добавляем утверждение на случай, если заголовок окна не соответствует ожидаемому заголовку.
- Закрываем окно браузера.
❒ Реализация
<?php require 'vendor/autoload.php'; use PHPUnit\Framework\TestCase; use Facebook\WebDriver\Remote\DesiredCapabilities; use Facebook\WebDriver\Remote\RemoteWebDriver; $GLOBALS['LT_USERNAME'] = "user-name"; # accessKey: AccessKey можно сгенерировать в панели автоматизации или в разделе профиля $GLOBALS['LT_APPKEY'] = "access-key"; class WindowSwitchTest extends TestCase { protected $webDriver; public function build_browser_capabilities(){ /* $capabilities = DesiredCapabilities::chrome(); */ $capabilities = array( "build" => "[PHP] Window Switching with Chrome on Windows 10", "name" => "[PHP] Window Switching with Chrome on Windows 10", "platform" => "Windows 10", "browserName" => "Chrome", "version" => "85.0" ); return $capabilities; } public function setUp(): void { $url = "https://". $GLOBALS['LT_USERNAME'] .":" . $GLOBALS['LT_APPKEY'] ."@hub.lambdatest.com/wd/hub"; $capabilities = $this->build_browser_capabilities(); /* Скачать Selenium Server 3.141.59 с https://selenium-release.storage.googleapis.com/3.141/selenium-server-standalone-3.141.59.jar */ /* $this->webDriver = RemoteWebDriver::create('http://localhost:4444/wd/hub', $capabilities); */ $this->webDriver = RemoteWebDriver::create($url, $capabilities); } public function tearDown(): void { $this->webDriver->quit(); } /* * @test */ public function test_SwitchToNewWindow() { $test_url_1 = "https://www.lambdatest.com"; $title_1 = "Most Powerful Cross Browser Testing Tool Online | LambdaTest"; $test_url_2 = "https://www.lambdatest.com/blog/"; $title_2 = "LambdaTest | A Cross Browser Testing Blog"; $this->webDriver->get($test_url_1); $this->webDriver->manage()->window()->maximize(); $wHandle = $this->webDriver->getWindowHandle(); /* echo ("\n Primary Window Handle is " . $wHandle ); */ sleep(5); /* Открываем второе окно */ /* $link = "window.open('https://www.lambdatest.com/blog/', '_blank', 'toolbar=yes,scrollbars=yes,resizable=yes,width=800,height=800')"; */ $link = "window.open('". $test_url_2 ."', '_blank', 'toolbar=yes,scrollbars=yes,resizable=yes,width=1200,height=1200')"; $this->webDriver->executeScript($link); /* $this->webDriver->manage()->window()->maximize(); */ /* Фокус теперь на втором окне */ /* Количество дескрипторов будет равным двум */ $HandleCount = $this->webDriver->getWindowHandles(); echo ("\n Total number of window handles are " . sizeof($HandleCount)); echo ("\n Window 0: " . $HandleCount[0]); echo ("\n Window 1: " . $HandleCount[1]); sleep(10); /* Создаём утверждение на случай, если количество окон не равно 2 */ $this->assertEquals(2, sizeof($HandleCount)); /* Проверяем соответствие заголовков окон */ $this->webDriver->switchTo()->window($HandleCount[1]); $win_title_2 = $this->webDriver->getTitle(); echo ("\n Title of the window 1 is " . $win_title_2); sleep(10); $this->assertEquals($win_title_2, $title_2); /* Закрываем новое открытое окно и возвращаемся к старому окну */ $this->webDriver->close(); sleep(10); /* Возвращаемся к окну с дескриптором = 0 */ $this->webDriver->switchTo()->window($wHandle); /* Проверяем, совпадают ли заголовки окон */ $win_title_1 = $this->webDriver->getTitle(); echo ("\n Title of the window 0 is " . $win_title_1); $this->assertEquals($win_title_1, $title_1); sleep(10); } } ?>
❒ Разбор кода
Существенная часть реализации в этой части туториала по Selenium PHP остаётся той же, которая была использована для работы с окнами в Selenium с PHP.
1. При открытиитестового URL для получения дескрипторов открытых окон браузера используется метод getWindowHandles WebDriver.
public function test_SwitchToNewTab() { $test_url = "http://automationpractice.com/index.php"; $title_1 = "My Store"; $title_2 = "Selenium Framework - YouTube"; ...................................... ...................................... $this->webDriver->get($test_url); $this->webDriver->manage()->window()->maximize(); ...................................... ...................................... $HandleCount = $this->webDriver->getWindowHandles();
2. В конце страницы размещается веб-элемент с гиперссылкой на YouTube-канал сайта. При помощи метода executeScript, предоставленного JavaScriptExecutor, исполняется метод window.scrollTo JavaScript. Он выполняет переход к концу страницы.
$link = "window.scrollTo(0, document.body.scrollHeight)"; $this->webDriver->executeScript($link);
3. Для получения информации о требуемом веб-элементе мы используем расширение POM Builder для Chrome, чтобы получить информацию локатора (т. е. XPath).

Для получения информации о веб-элементе [with XPath – //a[contains(.,’Youtube’)] используется метод findElement класса WebDriverBy.
$browser_button = $this->webDriver->findElement(WebDriverBy::XPath("//a[contains(.,'Youtube')]"));
4. Для найденного веб-элемента вызывается метод click.
$browser_button->click();
5. Метод getWindowHandles возвращает алфавитно-цифровой массив (или множество), содержащий дескрипторы (или ID) текущих открытых окон (или вкладок) браузера. В нашем случае количество открытых окон будет равным 2.
Следовательно, после применения оператора sizeof к массиву (или множеству), возвращённому getWindowHandles, вернёт 2.
$HandleCount = $this->webDriver->getWindowHandles(); echo ("\n Total number of window handles are " . sizeof($HandleCount)); echo ("\n Window 0: " . $HandleCount[0]); echo ("\n Window 1: " . $HandleCount[1]);
6. Для переключения на второе окно (т. е. $HandleCount[1]) используется метод switchTo Selenium WebDriver. Если заголовок окна не соответствует ожидаемому заголовку, срабатывает утверждение.
$this->webDriver->switchTo()->window($HandleCount[1]); $win_title_2 = $this->webDriver->getTitle(); $this->assertEquals($win_title_2, $title_2);
7. Метод close закрывает окно в фокусе (т. е. вкладку, где открыт YouTube-канал).
$this->webDriver->close();
8. Выполняется переключение на родительское окно (т. е. $HandleCount[0]). Если заголовки не совпадают, срабатывает утверждение.
$this->webDriver->switchTo()->window($HandleCount[0]); $win_title_1 = $this->webDriver->getTitle(); $this->assertEquals($win_title_1, $title_1);
❒ Исполнение
Вот дескрипторы двух окон браузера, созданных при тестировании.
Ниже показан снэпшот исполнения автоматизированного теста Selenium:

Как видно из снэпшота, дескрипторы родительского окна и вкладки уникальны. Когда окно и вкладка открыты, размер массива дескрипторов окон равен 2.

Теперь, когда мы увидели реализацию и исполнение работы с окнами и несколькими вкладками в Selenium с PHP, давайте подробнее узнаем о работе с несколькими всплывающими окнами браузера.
▍ Работа с несколькими всплывающими окнами браузера в Selenium с PHP
Для демонстрации работы со всплывающими окнами браузера в Selenium PHP мы используем следующий тестовый сценарий:
- Откроем www.popuptest.com/popuptest1.html в браузере Chrome.
- Закроем все всплывающие окна в обратном хронологическом порядке.
- Проверим, соответствует ли заголовок родительского окна ожидаемому заголовку.
Если тот же тест выполняется в локальном Selenium Grid, то нужно убедиться, что для Google Chrome включены всплывающие окна. Для включения всплывающих окон для Chrome на локальной машине перейдите по адресу chrome://settings/ -> Privacy and security -> Site Settings -> Pop-ups and redirects. Отключите опцию Block для www.popuptest.com:80.


❒ Реализация
<?php require 'vendor/autoload.php'; use PHPUnit\Framework\TestCase; use Facebook\WebDriver\Remote\DesiredCapabilities; use Facebook\WebDriver\Remote\RemoteWebDriver; use Facebook\WebDriver\WebDriverBy; $GLOBALS['LT_USERNAME'] = "user-name"; # accessKey: AccessKey можно сгенерировать в панели автоматизации или в разделе профиля $GLOBALS['LT_APPKEY'] = "access-key"; class PopUpTest extends TestCase { protected $webDriver; public function build_browser_capabilities(){ /* $capabilities = DesiredCapabilities::chrome(); */ $capabilities = array( "build" => "[PHP] Pop Up Testing with Chrome on Windows 10", "name" => "[PHP] Pop Up Testing with Chrome on Windows 10", "platform" => "Windows 10", "browserName" => "Chrome", "version" => "85.0" ); return $capabilities; } public function setUp(): void { $url = "https://". $GLOBALS['LT_USERNAME'] .":" . $GLOBALS['LT_APPKEY'] ."@hub.lambdatest.com/wd/hub"; $capabilities = $this->build_browser_capabilities(); /* Скачать Selenium Server 3.141.59 с https://selenium-release.storage.googleapis.com/3.141/selenium-server-standalone-3.141.59.jar */ /* $this->webDriver = RemoteWebDriver::create('http://localhost:4444/wd/hub', $capabilities); */ $this->webDriver = RemoteWebDriver::create($url, $capabilities); } public function tearDown(): void { $this->webDriver->quit(); } /* * @test */ public function test_SwitchToNewWindow() { $test_url = "http://www.popuptest.com/popuptest1.html"; $title = "PopupTest 1 - test your popup killer software"; $this->webDriver->get($test_url); sleep(5); /* Это откроет основное окно и шесть всплывающих окон */ /* После загрузки страницы общее количество страниц будет равным 7 */ $HandleCount = $this->webDriver->getWindowHandles(); /* Это ID родительского окна */ $mainHandle = $HandleCount[0]; echo ("\n Total number of window handles are " . sizeof($HandleCount)); echo ("\n Window 0: " . $HandleCount[0]); $win_title = $this->webDriver->getTitle(); echo ("\n Title of the parent window is " . $win_title); foreach( $HandleCount as $handle) { if($handle != $mainHandle) { echo ("\n Window handle of the current window: " . $handle); $this->webDriver->switchTo()->window($handle); echo ("\n Title of the current window: " . $this->webDriver->getTitle()); /* Закрываем всплывающее окно и возвращаемся к старому окну */ $this->webDriver->close(); sleep(2); } } $this->webDriver->switchTo()->window($mainHandle); $this->webDriver->manage()->window()->maximize(); sleep(5); $curr_window_title = $this->webDriver->getTitle(); echo ("\n\n Title of the only left window: " . $curr_window_title); $this->assertEquals($curr_window_title, $title); sleep(5); } } ?>
❒ Разбор кода
1. Так как для тестирования используется Selenium Grid на LambdaTest, user-name и access key хранятся в глобальных переменных. Того же результата можно получить, перейдя на страницу профиля на LambdaTest.
$GLOBALS['LT_USERNAME'] = "user-name"; # accessKey: AccessKey можно сгенерировать в панели автоматизации или в разделе профиля $GLOBALS['LT_APPKEY'] = "access-key";
2. При помощи LambdaTest Capabilities Generator генерируются возможности браузера.
$capabilities = array( "build" => "[PHP] Window Switching with Chrome on Windows 10", "name" => "[PHP] Window Switching with Chrome on Windows 10", "platform" => "Windows 10", "browserName" => "Chrome", "version" => "85.0" );
3. Для доступа к Selenium Grid on LambdaTest (@hub.lambdatest.com/wd/hub) используется сочетание глобальных переменных, в которых хранятся user-name и access-key. Метод create в классе RemoteWebDriver получает в качестве первого параметра URL Selenium Grid, а в качестве второго — возможности браузера.
$url = "https://". $GLOBALS['LT_USERNAME'] .":" . $GLOBALS['LT_APPKEY'] ."@hub.lambdatest.com/wd/hub"; $capabilities = $this->build_browser_capabilities(); $this->webDriver = RemoteWebDriver::create($url, $capabilities);
4. В тестовом методе test_SwitchToNewWindow открывается тестовый URL https://www.lambdatest.com и используется предоставляемый Selenium WebDriver метод getWindowHandle для получения дескриптора текущего окна.
public function test_SwitchToNewWindow() { $test_url_1 = "https://www.lambdatest.com"; $title_1 = "Most Powerful Cross Browser Testing Tool Online | LambdaTest"; ............................................... ............................................... $this->webDriver->get($test_url_1); $wHandle = $this->webDriver->getWindowHandle(); ............................................... }
5. Для открытия нового вторичного окна браузера используется метод JavaScript window.open. Методу также передаются ширина и высота окна. Для исполнения сформированного кода JavaScript в контексте текущего открытого окна используется метод executeScript, предоставляемый JavaScriptExecutor в Selenium PHP.
$link = "window.open('". $test_url_2 ."', '_blank', 'toolbar=yes,scrollbars=yes,resizable=yes,width=1200,height=1200')"; $this->webDriver->executeScript($link);
6. Метод getWindowHandles возвращает алфавитно-цифровой массив, содержащий ID (или дескриптор) текущих открытых окон. Оператор sizeof, применяемый к массиву, возвращённому getWindowHandles, возвращает количество открытых окон (т. е. в нашем случае 2).
$HandleCount = $this->webDriver->getWindowHandles(); echo ("\n Total number of window handles are " . sizeof($HandleCount));
7. При помощи утверждения проверяем, не меньше ли двух общее количество дескрипторов окон.
$this->assertEquals(2, sizeof($HandleCount));
8. Для переключения на второе окно (которое было открыто при помощи метода window.open) используется метод switchTo Selenium WebDriver. Если заголовок окна не соответствует ожидаемому заголовку, срабатывает утверждение.
$this->webDriver->switchTo()->window($HandleCount[1]); $win_title_2 = $this->webDriver->getTitle(); $this->assertEquals($win_title_2, $title_2);
9. Текущее окно закрывается при помощи метода Close().
$this->webDriver->close();
10. Теперь количество дескрипторов окон будет равно одному (так как открыто только родительское окно). Для переключения на родительское окно используется метод switchTo, которому в качестве параметра передаётся дескриптор этого окна (т. е. $wHandle). Если заголовок окна не соответствует ожидаемому заголовку, срабатывает утверждение.
$test_url_1 = "https://www.lambdatest.com"; $title_1 = "Most Powerful Cross Browser Testing Tool Online | LambdaTest"; ........................................... $this->webDriver->get($test_url_1); ........................................... ........................................... $wHandle = $this->webDriver->getWindowHandle(); /* Возвращаемся к окну с дескриптором = 0 */ $this->webDriver->switchTo()->window($wHandle); /* Проверяем, совпадают ли заголовки окон */ $win_title_1 = $this->webDriver->getTitle(); $this->assertEquals($win_title_1, $title_1);
11. Как часть tearDown вызывается метод quit Selenium WebDriver на PHP.
public function tearDown(): void { $this->webDriver->quit(); }
❒ Исполнение
На скриншоте ниже отмечены дескрипторы всплывающих окон:

После закрытия всех всплывающих окон остаётся только родительское окно, которое закрывается после исполнения теста.

Как показано на снэпшоте исполнения, сделанном на вкладке автоматизации платформы LambdaTest, всплывающие окна открываются, а затем закрываются в обратном хронологическом порядке.


Заключение
Окна браузера, в том числе вкладки и всплывающие окна, идентифицируются по дескрипторам окон. Эти дескрипторы используются в качестве ID окон, они уникальны для каждого окна браузера. В этом туториале по Selenium WebDriver PHP мы узнали, как происходит работа с окнами в Selenium с PHP при помощи таких методов, как switchTo, getWindowHandle и getWindowHandles. Эти методы играют важную роль в работе с окнами для автоматизации тестов Selenium с PHP.
ссылка на оригинал статьи https://habr.com/ru/company/ruvds/blog/679048/

Добавить комментарий