Как вы боретесь с модальными окнами в Selenium?


(Mykhailo Poliarush) #1

Сегодня снова обсуждал этот вопрос.

Есть несколько способов, например через Robot java class или AutoIT, но это не универсальные способы.

А как вы решаете подобные задачи?

Вот пример страницы, которую хочется автоматизировать https://developer.mozilla.org/samples/domref/showModalDialog.html


(Taras) #2

Сегодня как раз делал через AutoIT - работает нормально.

Если нужен пример скрипта, то могу скинуть.


(Mykhailo Poliarush) #3

скинь, пожалуйста, для коллекции не помешает


(barancev) #4

Надо ли говорить о том, что лучше бы такими "окнами" вообще не пользоваться? В Chrome они совсем не модальные. В IE... попробуйте сами, увидите, как он его откроет. Ну а Opera не открывает вообще никакого окна. Вместо того, чтобы автоматизировать __это__, надо пойти и накатить разрабочикам как следует.


(Mykhailo Poliarush) #5

подход "накатить разработчикам как следует" мне лично нравиться, только не всегда, к сожалению, применим :)

legacy системы меняют очень даже неохотно, даже если накатить разработчикам

 


(Mykhailo Poliarush) #6

Леша, я понимаю почему ты так пишешь

Пресловутая 284 проблема висит с декабря 2009 года

Мне кажется, с модальными окнами ничего так и не сделают


(barancev) #7

Вообще-то работа над 284 ведётся. В браузере IE модальные окна отлично обрабатываются, с ними можно работать как с обычными:

    final WebDriver driver = new InternetExplorerDriver();
    driver.manage().timeouts().implicitlyWait(60, TimeUnit.SECONDS);
    driver.get("http://developer.mozilla.org/samples/domref/showModalDialog.html");
    
    String mainWindowHandle = driver.getWindowHandle();
    Set<String> oldWindowHandles = driver.getWindowHandles();
    
    driver.findElement(By.tagName("input")).click();
 
    driver.switchTo().window(newWindowOpened(driver, oldWindowHandles, 5));
    Assert.assertEquals(2, driver.getWindowHandles().size());
    
    driver.findElement(By.id("foo")).clear();
    driver.findElement(By.id("foo")).sendKeys("footest");
    driver.findElement(By.cssSelector("input[type=button]")).click();
 
    driver.switchTo().window(mainWindowHandle);
 
Так что если есть возможность -- просто выполняйте в IE те тесты, где используются такие "окна". В других браузерах этот код, действительно, не срабатывает, тест блокируется.

(Mykhailo Poliarush) #8

вот именно, что только с ИЕ, хотя я тоже бы отрезал руки тем разработчикам, которые в проектных масштабах используют модальные окна + это уже давно не феншуй

з.ы. добавить, пожалуйста, еще реализацию newWindowOpened(driver, oldWindowHandles, 5)


(barancev) #9

 

 public String newWindowOpened(WebDriver driver, final Set<String> oldWindowHandles, long timeOutInSeconds) {
    return new WebDriverWait(driver, timeOutInSeconds).until(new ExpectedCondition<String>() {
      @Override
      public String apply(WebDriver d) {
        Set<String> handles = d.getWindowHandles();
        handles.removeAll(oldWindowHandles);
        if (handles.size() > 0) {
          return handles.iterator().next();
        } else {
          return null;
        }
      }
    });

(rpwheeler) #10

А допускается только средствами Selenium? Попадись такая задача мне, попытался бы вкрутить туда поддержку Sikuli (http://sikuli.org/), его функционал можно вызывать через подключение его модулей на Java или Python.

Работал с Sikuli для тестирования на эмуляторе iPad, - с помощью его визуального поиска прописывал выход из модальных поп-апов приложения без какой-либо поддержки со стороны эмулятора вообще, и даже обнаружение перехода в браузер iPad - сворачивание браузера - возврата в тестируемое приложение. "Все, что можно найти на экране как изображение и кликнуть - все ваше".


(barancev) #11

Допускается всё что угодно. Но окна и кнопки в разных браузерах и даже в разных версиях одного и того же браузера выглядят по разному. Так что использование Sikuli потребует снятия кучи скриншотов, а потом ещё надо будет угадать, какой именно использовать в конкретном случае.


(rpwheeler) #12

@barancev

а потом ещё надо будет угадать, какой именно использовать в конкретном случае.

Снятие скриншотов и нарезание из них кусков делается Sikuli IDE довольно просто.

"Угадывать" будет сам скрипт - что визуально найдет, то и угадает.
Можно задать поиск более чем менее конкретной графики + оценку ее приблизительного расположения.
Можно менять точность распознавания, можно проводить поиск только в определенном регионе экрана.
Можно делать поиск даже по тексту.
Если примерно совпадает шрифт надписей, можно опознавать поп-ап по нему, а кликать по относительной позиции, - много вариантов, в общем.

Не такая уж и куча.

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

Мое дело - предложить вариант :)


(barancev) #13

Это уж пусть Миша выбирает :) У меня в тестах тоже есть места, где используется Sikuli, но там уж действительно сложно без него -- флешовый видеоплеер на страничке, флешовый же "слайд-проектор". Но они хотя бы одинаково выглядят и работают во всех браузерах.

Мой тезис был, собственно, в другом -- проблемные места в приложении надо не автоматизировать, а устранять.


(barancev) #14

Ну а теперь -- полусекретная информация о том, как можно работать с этими модальными окнами в Firefox :) Надо просто клик выполнять в отдельном потоке. Но! Не пробуйте выполнить это в IE -- упадёт.

 

String mainWindowHandle = driver.getWindowHandle();
Set<String> oldWindowHandles = driver.getWindowHandles();
 
new Thread() {
  @Override
    public void run() {
      driver.findElement(By.tagName("input")).click();
    }
  }.start();
 
driver.switchTo().window(newWindowOpened(driver, oldWindowHandles, 5));
 
driver.findElement(By.id("foo")).clear();
driver.findElement(By.id("foo")).sendKeys("footest");
driver.findElement(By.cssSelector("input[type=button]")).click();
 
driver.switchTo().window(mainWindowHandle);

(Taras) #15

 

try {
         String[] commands = new String[]{};
         commands = new String[]{"D:\AutoIT-commands\chooseVideo.exe"}; //location of the autoit executable
         Runtime.getRuntime().exec(commands);
      } catch (IOException e) {}
 
 

(Taras) #16

Я так понимаю, что driver.switchTo().window(newWindowOpened(driver, oldWindowHandles, 5)); начинает свое действие только когда new Thread() заканчивает свою роботу, правильно ????


(barancev) #17

Неправильно. Этот поток, в котором выполняется click, работает параллельно с основным, то есть ожидание появления нового окна начинается одновременно с выполнением этого дополнительного потока.


(Taras) #18

как сделать так, чтоб вебдрайвер ждал пока модальное окно не закроется ???

Откривание и перехват кликов модального окна я делаю через AutoIT


(barbos) #19

рискну показаться снобом, но, товарищи, в данном случае "боретесь". глаз режет просто)