Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save yashaka/dd5ed32ae6c776059b619179f204457a to your computer and use it in GitHub Desktop.
Save yashaka/dd5ed32ae6c776059b619179f204457a to your computer and use it in GitHub Desktop.
selene-custom-conditions-to-wait-for-several-elements.py
"""
можно передавать лямбды вместо кондишенов в Selene
но в лямбдах-кондишенах для Selene
нужно возвращать не тру/фолс, а просто кидать еррор если было фолс
например
"""
if browser.wait_until(lambda browser: raise Exception if not (
browser.element('#page1-header').matching(be.visible)
or browser.element('#page2-header').matching(be.visible)
) else None):
# your next code goes here
"""
конечно строка сильно длинная и лучше так:
"""
# вот этот браузер в параметре у функции-кондишена
# – это как драйвер в селениумских родных функциях-экспектед-кондишенах
# то есть его надо полюбому принимать в кондишене
# соответственно внутри - мы можем находить элемет
# от этого принятого браузера...
def page1_or_page2_loaded(browser):
if not (
browser.element('#page1-header').matching(be.visible)
or browser.element('#page2-header').matching(be.visible)
):
raise Exception
if browser.wait_until(page1_or_page2_loaded):
if browser.element('#page1-header').matching(be.visible):
# the scenario for page1
else: # on page2...
# the scenario for page2
"""
вот только я надеюсь ты уверен хотя бы в том
что может быть только два варианта
поэтому лучше
"""
def have_page1_or_page2_loaded(browser):
if not (
browser.element('#page1-header').matching(be.visible)
or browser.element('#page2-header').matching(be.visible)
):
raise Exception
browser.should(have_page1_or_page2_loaded):
if browser.element('#page1-header').matching(be.visible):
# the scenario for page1
else: # on page2...
# the scenario for page2
"""
или DRY версия,
при этом «самая точная в контексте управления браузером»
(но не самая удобная)
"""
page1_header = lambda browser: browser.element('#page1-header')
page2_header = lambda browser: browser.element('#page2-header')
def have_page1_or_page2_loaded(browser):
if not (
page1_header(browser).matching(be.visible)
or page2_header(browser).matching(be.visible)
):
raise Exception
browser.should(have_page1_or_page2_loaded):
if page1_header(browser).matching(be.visible) :
# the scenario for page1
else: # on page2...
# the scenario for page2
"""
Заметь, можно было бы и так:
"""
is_page1_header_visible = (
lambda browser: browser.element('#page1-header').matching(be.visible)
)
...
"""
но эта версия менее гибкая, если потенциально нам нужны
эти элементы и для других задач (не только проверки на видимость)
"""
"""
Теперь, если не задроствовать по браузеру,
если у нас всегда "один браузер",
нет каких то там мультибраузерных тестов
то достаточно и так
"""
page1_header = browser.element('#page1-header')
page2_header = browser.element('#page2-header')
def have_page1_or_page2_loaded(_):
if not (
page1_header.matching(be.visible)
or page2_header.matching(be.visible)
):
raise Exception
browser.should(have_page1_or_page2_loaded):
if page1_header.matching(be.visible) :
# the scenario for page1
else: # on page2...
# the scenario for page2
"""
Еще одна версия чуток более оптимальная по скорости,
но реально, оно того не стоит,
врядли где-то будет существенный прирост
(эти тесты и так медленные сами по себе),
показываю просто на всякий случай...
Идея - вызвать селен элемент как функцию
– это вернет чистый вебэлемент
и мы напрямую вызовем метод вебдрайвера
is_displayed()
Таким образом убирая всю магию селена
которая могла бы как то это замедлить
(она там все равно убирается самим методом matching
но потенциально гдето когда то
может таки где то быть медленней)
"""
page1_header = browser.element('#page1-header')
page2_header = browser.element('#page2-header')
def have_page1_or_page2_loaded(_):
if not (
page1_header().is_displayed()
or page2_header().is_displayed()
):
raise Exception
browser.should(have_page1_or_page2_loaded)
if page1_header.matching(be.visible) :
# the scenario for page1
else: # on page2...
# the scenario for page2
"""
Ну и версия которую можно использовать с какими угодно элементами:
"""
# my_project/helpers/match.py
def any_to(condition, *elements):
def fn(browser):
if not any(map(lambda it: it.matching(condition), elements)):
raise Exception
return fn
# test_weird_scenario.py
from my_project.helpers import match
...
page1_header = browser.element('#page1-header')
page2_header = browser.element('#page2-header')
browser.should(match.any_to(be.visible, page1_header, page2_header))
if page1_header.matching(be.visible) :
# the scenario for page1
else: # on page2...
# the scenario for page2
"""
Если важно чтобы кастомные кондишены
лучше логировались
то стоит использовать либо callable объекты
либо заюзать дополнительные селеновские классы типа BrowserCondition
"""
# my_project/helpers/match.py
from selene.core.conditions import BrowserCondition
def element(condition, *elements):
def fn(browser):
if not any(map(lambda it: it.matching(condition), elements)):
raise Exception
return BrowserCondition.raise_if_not(
f'any {condition} among {elements}', # < вот это будет видно при ошибке
fn,
)
# test_weird_scenario.py
from my_project.helpers import match
...
"""
Другой плюс этих штук типа BrowserCondition
(там еще есть ElementCondition и CollectionCondition)
Что у них есть встроенные методы or_, and_, not_
Что позволить например переписать вот так:
"""
# my_project/helpers/browser_conditions.py
from selene.core.conditions import BrowserCondition
def have_visible(element):
return BrowserCondition.raise_if_not(
f'any {condition} among {elements}', # < вот это будет видно при ошибке
lambda browser: element().is_displayed(),
)
# test_weird_scenario.py
from my_project.helpers.browser_conditions import have_visible
...
page1_header = browser.element('#page1-header')
page2_header = browser.element('#page2-header')
browser.should(have_visible(page1_header).or_(have_visible(page2_header)))
if page1_header.matching(be.visible) :
# the scenario for page1
else: # on page2...
# the scenario for page2
"""
КСТАТИ!!!
А еще должно наверное работать такое:
"""
page1_header = browser.element('#page1-header')
page2_header = browser.element('#page2-header')
page1_header.should(be.visible.or_(lambda _: be.visible(page2_header)))
if page1_header.matching(be.visible) :
# the scenario for page1
else: # on page2...
# the scenario for page2
"""
P.S. все примеры кода выше написал "от руки"
на ошибки не проверял :D
"""
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment