Это вторая статья из цикла статей "WebDriver features", в которых рассматриваться примеры нестандартных ситуаций, которые могут возникнуть при автоматизации на Selenium WebDriver.
WebDriver features: Робота с несколькими окнами (вкладками) одновременно при помощи Selenium Web Driver
Почти вся автоматизация веб-приложений привязана к одной активной вкладке. То есть при вызове driver.get(“some url”); откроется вкладка браузера с адресом “some url”. Но что делать, если, например, у нас web приложение, которое состоит из 2-х взаимно зависимых “view-шок”, либо же нам нужно по-быстрому поменять что-то в web интерфейсе сервера или админчасти сайта и проверить эти изменения в одном тесте. Другими словами, конструкция манипуляций выглядит следующим образом:
Start from “some url” in first browser tab
Make some changes (automation test steps)
Open new tab in the same browser with new url (server url, site administration part, etc)
Make some changes in new tab (automation test steps)
Return to first tab
Repeat steps from 2 to 6 till the end of test.
По ходу действий вышеописанного алгоритма нас интересуют такие структурные этапы:
создание новой вкладки браузера и открытие в ней новой ссылки тем же webdriver-ом, что используется в тестах
навигация между вкладками (туда и обратно) и фокусировка на необходимой вкладке
Итак, разберем по пунктам, что нам нужно знать и реализовать.
Для первого этапа:
-
Объект данного класса WebWindow эмулирует создание новой вкладки браузера. (Для детального изучения данной реализации присутствуют комментарии в коде.
package Core; import org.openqa.selenium.By; import org.openqa.selenium.JavascriptExecutor; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebDriverException; import java.util.Set; /** * Creates and Handles a New window * */ public class WebWindow { private WebDriver driver = PageLoader.GetInstance(); // сюда передаем тот же веб драйвер который вызываеться в самих тестах private String handle; private String name; private String parentHandle; private static int instanceCount = 0; /** * Creates a new window for given web driver * @param parent WebDriver instance * @param url Initial url to load * @return new WebWindow */ public WebWindow(WebDriver parent, String url) { this.driver = parent; parentHandle = parent.getWindowHandle(); name = createUniqueName(); handle = createWindow(url); //Switch to that window and load the url to wait switchToWindow().get(url); } public String getWindowHandle() { return handle; } public String getParentHandle() { return parentHandle; } public void close() { switchToWindow().close(); handle = ""; //Switch back to the parent window driver.switchTo().window(parentHandle); } private static String createUniqueName() { return "a_Web_Window_" + instanceCount++; } public WebDriver switchToWindow() { checkForClosed(); return driver.switchTo().window(handle); } public WebDriver switchToParent() { checkForClosed(); return driver.switchTo().window(parentHandle); } private String createWindow(String url) { //Record old handles Set < string > oldHandles = driver.getWindowHandles(); parentHandle = driver.getWindowHandle(); //Inject an anchor element ((JavascriptExecutor) driver). executeScript( injectAnchorTag(name, url) ); //Click on the anchor element driver.findElement(By.id(name)).click(); handle = getNewHandle(oldHandles); return handle; } private String getNewHandle(Set < string > oldHandles) { Set < string > newHandles = driver.getWindowHandles(); newHandles.removeAll(oldHandles); //Find the new window for (String handle: newHandles) return handle; return null; } private void checkForClosed() { if (handle == null || handle.equals("")) throw new WebDriverException("Web Window closed or not initialized"); } private String injectAnchorTag(String id, String url) { return String.format("var anchorTag = document.createElement('a'); " + "anchorTag.appendChild(document.createTextNode('nwh'));" + "anchorTag.setAttribute('id', '%s');" + "anchorTag.setAttribute('href', '%s');" + "anchorTag.setAttribute('target', '_blank');" + "anchorTag.setAttribute('style', 'display:block;');" + "document.getElementsByTagName('body')[0].appendChild(anchorTag);", id, url ); } }
Данному подходу есть имя - Script Injection technique. Использование инъекции anchor tag (with target = _blank …) дает возможность открытия новой вкладки (окна) после клика на этот элемент.
Для второго этапа:
Создадим переменную public String handleHost; В аннотации `@Before` к нашим тестам укажем следующее:
@Before
public void setup() {
…
handleHost = driver.getWindowHandle(); //handle first Window
…
}
Другими словами, в нее запишем первую вкладку (окно) с которой стартуют тесты.
Напишем методы: создание новой вкладки, переключение со стартовой вкладки(окна) на созданную и обратно.
protected void SwitchFromSecondTabToFirst() {
try {
driver.switchTo().window(handleHost);
driver.switchTo().activeElement();
} catch (Exception e) {
System.err.println(“Couldn’t get back to first page”);
}
}
protected void SwitchFromFirstPageToSecond() {
try {
for (String handle: driver.getWindowHandles()) {
if (handle != handleHost) {
driver.switchTo().window(handle);
driver.switchTo().activeElement();
} // смотрим все вкладки (а их две всего); если і-тая вкладка не равна первой handleHost (инициализированой в пункте (а), тогда переключаемся на нее).
}
} catch (Exception e) {
System.err.println(“Couldn’t get to second page”);
}
}