Есть отличная удаленная работа для php+codeception+jenkins+allure+docker спецов. 100% remote! Присоединиться к проекту

Проблема с window handles и закрытием окон в IE driver


(Дмитрий Безручко) #1

Есть тесты на Python + Selenium:

self.driver.get(ua_url)
    base_handle = self.driver.current_window_handle
    self.TryAndWait(By.XPATH,pdf_link)
    self.driver.find_element_by_xpath(pdf_link).click()
    time.sleep(2)
    self.driver.switch_to_window(self.driver.window_handles[-1])
    self.TryAssertAndWait(pdf_url)
    self.driver.close()
    self.driver.switch_to_window(base_handle)

Все, что они делают - открывается страница в текущем окне, считывается ее handle, затем в новом окне открывается пдф документ, драйвер переходит на открывшуюся ссылку по ее handle, проверяет ее, затем окно закрывается и драйвер возвращается к первому окну. Таких тестов штук 10 выполняется подряд. Все прекрасно работает на FF и Chrome, но на IE, постоянно в какой-то момент вместо открывшегося окна закрывается главное, и все падает ! При чем случайно, а не в определенном месте. Уже промучался кучу времени с этим, мб кто-то также сталкивался ?


(Sergey Korol) #2

Что такое TryAndWait / TryAssertAndWait? Какие-то кастомные методы? Что внутри? И откуда берется pdf_link?
Думаю, что @polusok сможет лучше подсказать. Он тут спец по питону.


(Sergey Korol) #3

Да, еще не совсем понятна запись: driver.window_handles[-1]. Это в питоне нормальное явление - отрицательные индексы в массиве?


(Дмитрий Безручко) #4

Это методы, что писал, с ними проблем нету, дело именно в окнах. Насчет driver.window_handles[-1] - это последний элемент в массиве, то есть последнее открытое окно.


(Sergey Korol) #5

С каких пор последние элементы в массиве стали нумероваться -1? Неужели питон настолько отличается от других языков программирования, где принята нумерация от 0 до N-1. Ну да ладно, не суть.
Смею предположить, что если self.driver.window_handles[-1] выдаст хэндл главного окна, то self.driver.close() как раз его и закроет. А хэндл главного окна возможен в случае, когда 2х секунд не хватило на открытие пдф. Вообще говоря, слипы - зло. Если у вас возникнет проблема с сетью и пакеты задержаться на 1 сек, то ваш сценарий как раз таки и зафейлится.


(Дмитрий Безручко) #6

Да, в python можно отрицательными значениями отсчитывать значения с конца строки.
Я знаю что зло, но мне нужно уже чтобы просто хоть как-то заработало, т.к. кучу времени уже убил. Поставил 5 секунд ожидания, все равно главное окно закрывается в случайный момент. Может все-таки проблема в handles ? Функция switch_to_window принимает еще также кроме handle еще name window - не знаете как я его могу получать у текущего окна ? Гугл не помог.


(Sergey Korol) #7

В Java можно еще получить handle по name:

import com.sun.jna.platform.win32.WinDef.HWND;
import static com.sun.jna.platform.win32.User32.INSTANCE;

// ...

HWND hwnd = INSTANCE.FindWindow(null, "Name");
INSTANCE.SetFocus(hwnd);

В питоне как, не подскажу.


(Mykhailo Poliarush) #8

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

Вот набросал небольшой скрипт, чтобы проверить ваш код и у меня все работает как часы:

from selenium import webdriver
from selenium.webdriver.common.keys import Keys
ie = webdriver.Ie()
ie.get('http://the-internet.herokuapp.com/windows')
ie.find_element_by_link_text('Click Here').click()
for window_id in ie.window_handles:
    print 'switching to {}'.format(window_id)
    ie.switch_to_window(window_id)
    ie.get('http://lessons2.ru')

for window_id in ie.window_handles[::-1]:
    ie.switch_to_window(window_id)
    ie.close()
    print 'close handle {} successfully'.format(window_id)

ie.window_handles[::-1] вот эта строка говорит, что начать закрывать окна с конца списка.

ууу в питоне даже больше можно делать driver.window_handles[::-1] надеюсь тебе уже страшно стало :slight_smile: Это называется backward indexing или reverse indexing. Я бы сказал очень удобно и часто используется.

С того момента как их начали там использовать, и это не только фишка python. Это конечно не так сложно как в джаве https://commons.apache.org/proper/commons-collections/javadocs/api-3.2.1/org/apache/commons/collections/iterators/ReverseListIterator.html :smile: а просто указываешь минусовый индекс и работаешь с элементом списка без проблем

Как раз нет, -1 указывает на последний открытое окно, так что все верно.

А вот с этим поспорить тяжело, лучше сделать try/except блок с определенным количесвом попыток а потом уже фейлить тесты.


(Дмитрий Безручко) #9

Вообщем , таки разобрался что к чему. Дело в том, что именно в IE массив с хендлами создается в случайном порядке, т.е. главное окно может быть как первым так и вторым элементом массива window_handles. Переделал так (знаю что тоже криво, но потратив на поиск решения полтора дня, уже лень даже переменные именовать нормально

self.driver.get(ua_url)
base_handle = self.driver.current_window_handle
self.TryAndWait(By.XPATH,pdf_link)
self.driver.find_element_by_xpath(pdf_link).click()
time.sleep(1)
handles = self.driver.window_handles
handles.remove(base_handle)
self.driver.switch_to_window(handles[0])
self.TryAssertAndWait(pdf_url)
self.driver.close()
self.driver.switch_to_window(base_handle)

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


(Mykhailo Poliarush) #10

Ну хорошо, что разобрался. Единственное что добавлю, научись плиз правильно вставлять код, чтобы он нормально отображался. Детали тут http://automated-testing.info/faq


(Sergey Korol) #11

Ну как написали выше, вовсе и не последнее. Плюс к всему, если физически окно только одно открыто, то -1 разве не его вернет? :blush:

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

Зачем использовать какие-то итераторы, если можно обратиться к любому элементу ровно так же, зная всего лишь lengt: windowHandles[len-1]? Ну или если это список, то windowHandles.get(len-1). Все так же просто, но по крайней мере понятно, что -1 - не просто индекс, а результат арифметической операции над длиной для получения нужного элемента.


(Mykhailo Poliarush) #12

Ну я уже убедился, но должно было быть попорядку. Это походу бажина IE драйвера.
А если окно только одно, то по индексу 0 или -1 вернется один и тот же элемент из списка.

Ну как там говорят забугром, change you mindset :smile:

В питоне когда-то давно тоже всегда писали window_handles[len(window_handles)-1] и window_handles[len(window_handles)-2] но потом поняли, зачем постоянно повторять len(window_handles) в каждом обращении. Вот и избавились от него. В питоне и сейчас можно написать window_handles[len(window_handles)-1] только это выглядит громоздко в сравнении с window_handles[-1]


(Sergey Korol) #13

Так ну брось. Не зря ведь серьезные задачи и по сей день решаются на плюсах. А все почему? Потому что на плюсах все under human control. Я не говорю, что подобные упрощения - это плохо. Это очень даже хорошо, когда особо не надо заморачиваться над тем, что происходит внутри. Так что на свой домен / задачу всегда найдется свой язык. Но это не значит, что всем нужно менять свое сознание ради каких-то упрощений.


(vmaximv) #14

http://www.w3.org/TR/webdriver/#window-handles

Нет никакого бага - все по спеке.


(Mykhailo Poliarush) #15

Я имел ввиду change mindset для того чтобы понять python. Это холивар, лучше дальше не продолжать.

Значит уже поменяли, или у меня они располагались в правильной последовательности и у меня не было из-за этого проблем. Ну если уже в спеке написано, так оно и должно быть :smile:


(vmaximv) #16

Всегда так было. Это “классические” грабли IEDriverServer. Хром и огнелис более щепетильны в этом вопросе.