webium

Webium – это клёвый фреймворк, разработанный силами автоматизаторов компании «Wargaming» для Python. Мне приходится каждый день иметь с ним дело на работе.

Что такое Logical Container? Это такая штука, позволяющая вам группировать элементы в блоки, при этом подразумевается, что на странице определение данного блока с помощью селектора не требуется. И, как заметил в своём докладе на «Selenium camp» Игорь Хрол, в самом «Варгейминге» использование этой фичи не особо прижилось. Но мой пытливый ум нашел таки способ его применения, правда, для написания костыля. =)

Итак, дано: на странице есть блок, в котором находится 3 элемента, и нам необходимо с этими элементами выполнять какие-то действия через методы, а также определять, видны ли они вообще.

  1. class NativeMenu(WebElement):
  2.     user_link = Find(Link, By.CSS_SELECTOR, '.js-auth-menu-authenticated > span > a')
  3.     """@type : Link"""
  4.     login_link = Find(Link, By.CSS_SELECTOR, 'li.b-global-nav_item__nologin>a.js-auth-openid-link')
  5.     """@type : Link"""
  6.     logout_link = Find(Link, By.CSS_SELECTOR, '.js-auth-logout-link')
  7.     """@type : Link"""
  8.  
  9.     def is_user_login(self, account):
  10.         return self.is_element_present('user_link') and self.user_link.text == account.name
  11.  
  12.     def is_user_logout(self):
  13.         return self.is_element_present('login_link')
  14.  
  15.     def click_login(self):
  16.         self.login_link.click()
  17.  
  18.     def click_logout(self):
  19.         self.user_link.click()
  20.         self.logout_link.click()

 

Как раз определение видимости элементов и привело к использованию логического контейнера.  Как известно, всему, что было найдено через Find, вебиум до кучи добавляет очень удобный метод is_element_present(). Его я и решил использовать внутри блока через self(self.is_element_present()), что привело, внезапно, к появлению старой и знакомой всем автоматизаторам ошибке StaleElementReferenceException.

Появление этой штуки в вебиуме вызвало недоумение! Как? Это же вебиум! При Сталине такой херни не было. Причину проблемы нашёл вышеупомянутый Игорь. Оказывается, вместе с элементами внутри блока AJAX вызывал также и изменение самого блока. Через self мы обращались уже к определённому ранее блоку, и пересчёт его не производился. Мы не обращались повторно к переменной блока, чтобы Find его пересчитал, поэтому метод is_element_present вызывался на уже устаревшем блоке. Выход был найден следующий: блок с элементами был обёрнут в логический контейнер, а методы взаимодействия уже были в нем описаны.

  1. class MenuElements(WebElement):
  2.     user_link = Find(Link, By.CSS_SELECTOR, '.js-auth-menu-authenticated > span > a')
  3.     """@type : Link"""
  4.     login_link = Find(Link, By.CSS_SELECTOR, 'li.b-global-nav_item__nologin>a.js-auth-openid-link')
  5.     """@type : Link"""
  6.     logout_link = Find(Link, By.CSS_SELECTOR, '.js-auth-logout-link')
  7.     """@type : Link"""
  8.  
  9.  
  10. class NativeMenu(object):
  11.     menu_elements = Find(MenuElements, By.CSS_SELECTOR, '#native-menu')
  12.     """@type : MenuElements"""
  13.  
  14.     def is_user_login(self, account):
  15.         return self.menu_elements.is_element_present('user_link') and self.menu_elements.user_link.text == account.name
  16.  
  17.     def is_user_logout(self):
  18.         return self.menu_elements.is_element_present('login_link')
  19.  
  20.     def click_login(self):
  21.         self.menu_elements.login_link.click()
  22.  
  23.     def click_logout(self):
  24.         self.menu_elements.user_link.click()
  25.         self.menu_elements.logout_link.click()

 

Просто и элегантно! Конечно, мы ввели ещё одну прослойку абстракции, но работает же! =)

P.S: Потом, от костыля было решено избавиться, и просто взять в DOM элемент который находится на уровень выше, но такое решение не всегда приемлемо, если лишнего div’а у вас нет.

Опубликовать в Google Plus
Опубликовать в LiveJournal
Опубликовать в Мой Мир
Опубликовать в Одноклассники
Опубликовать в Яндекс