zoukankan      html  css  js  c++  java
  • Selenium 高阶应用之WebDriverWait 和 expected_conditions

      Seleniium 是相当不错的一个第三方测试框架,可惜目前国内已经无法访问其官网(翻墙可以)。

          不知道大家是否有认真查看过selenium 的api,我是有认真学习过的。不得不说,selenium模块的文档组织是非常优秀的,事后多年回想起,我python编码能力的提升主要是得益于认真拜读过selenium的源码。

          selenium 的api中包含有WebDriverWait  和 expected_conditions这两个高级应用。

      下面先看WebDriverWait :

     1 import time
     2 from selenium.common.exceptions import NoSuchElementException
     3 from selenium.common.exceptions import TimeoutException
     4 
     5 POLL_FREQUENCY = 0.5  # How long to sleep inbetween calls to the method
     6 IGNORED_EXCEPTIONS = (NoSuchElementException,)  # exceptions ignored during calls to the method
     7 
     8 
     9 class WebDriverWait(object):
    10     def __init__(self, driver, timeout, poll_frequency=POLL_FREQUENCY, ignored_exceptions=None):
    11         """Constructor, takes a WebDriver instance and timeout in seconds.
    12 
    13            :Args:
    14             - driver - Instance of WebDriver (Ie, Firefox, Chrome or Remote)
    15             - timeout - Number of seconds before timing out
    16             - poll_frequency - sleep interval between calls
    17               By default, it is 0.5 second.
    18             - ignored_exceptions - iterable structure of exception classes ignored during calls.
    19               By default, it contains NoSuchElementException only.
    20 
    21            Example:
    22             from selenium.webdriver.support.ui import WebDriverWait 
    
    23             element = WebDriverWait(driver, 10).until(lambda x: x.find_element_by_id("someId")) 
    
    24             is_disappeared = WebDriverWait(driver, 30, 1, (ElementNotVisibleException)). 
    
    25                         until_not(lambda x: x.find_element_by_id("someId").is_displayed())
    26         """
    27         self._driver = driver
    28         self._timeout = timeout
    29         self._poll = poll_frequency
    30         # avoid the divide by zero
    31         if self._poll == 0:
    32             self._poll = POLL_FREQUENCY
    33         exceptions = list(IGNORED_EXCEPTIONS)
    34         if ignored_exceptions is not None:
    35             try:
    36                 exceptions.extend(iter(ignored_exceptions))
    37             except TypeError:  # ignored_exceptions is not iterable
    38                 exceptions.append(ignored_exceptions)
    39         self._ignored_exceptions = tuple(exceptions)
    40 
    41     def until(self, method, message=''):
    42         """Calls the method provided with the driver as an argument until the 
    43         return value is not False."""
    44         screen = None
    45         stacktrace = None
    46 
    47         end_time = time.time() + self._timeout
    48         while True:
    49             try:
    50                 value = method(self._driver)
    51                 if value:
    52                     return value
    53             except self._ignored_exceptions as exc:
    54                 screen = getattr(exc, 'screen', None)
    55                 stacktrace = getattr(exc, 'stacktrace', None)
    56             time.sleep(self._poll)
    57             if time.time() > end_time:
    58                 break
    59         raise TimeoutException(message, screen, stacktrace)
    60 
    61     def until_not(self, method, message=''):
    62         """Calls the method provided with the driver as an argument until the 
    63         return value is False."""
    64         end_time = time.time() + self._timeout
    65         while True:
    66             try:
    67                 value = method(self._driver)
    68                 if not value:
    69                     return value
    70             except self._ignored_exceptions:
    71                 return True
    72             time.sleep(self._poll)
    73             if time.time() > end_time:
    74                 break
    75         raise TimeoutException(message)

     哈哈,我始终相信贴出来总会有人看。WebDriverWait 类位于selenium.webdriver.support.ui下面的例子很简单,

    Example:
    1 from selenium.webdriver.support.ui import WebDriverWait
    2 element = WebDriverWait(driver, 10).until(lambda x: x.find_element_by_id("someId")) 
    3 is_disappeared = WebDriverWait(driver, 30, 1, (ElementNotVisibleException)).
    4                  until_not(lambda x: x.find_element_by_id("someId").is_displayed())
    WebDriverWait 里面主要有两个方法,一个是until和until_not

    那么我们可以这样用:
    WebDriverWait(driver, 10).until(lambda x: x.find_element_by_id("某个按钮")).click()

      意思就是在10秒内等待某个按钮被定位到,咱们再去点击。就是每隔0.5秒内调用一下until里面的表达式或者方法函数,要么10秒内表达式执行成功,要么10秒后抛出超时异常。

    然后我们再看expected_conditions:
      1 from selenium.common.exceptions import NoSuchElementException
      2 from selenium.common.exceptions import NoSuchFrameException
      3 from selenium.common.exceptions import StaleElementReferenceException
      4 from selenium.common.exceptions import WebDriverException
      5 from selenium.common.exceptions import NoAlertPresentException
      6 
      7 """
      8  * Canned "Expected Conditions" which are generally useful within webdriver
      9  * tests.
     10 """
     11 class title_is(object):
     12     """An expectation for checking the title of a page.
     13     title is the expected title, which must be an exact match
     14     returns True if the title matches, false otherwise."""
     15     def __init__(self, title):
     16         self.title = title
     17 
     18     def __call__(self, driver):
     19         return self.title == driver.title
     20 
     21 class title_contains(object):
     22     """ An expectation for checking that the title contains a case-sensitive
     23     substring. title is the fragment of title expected
     24     returns True when the title matches, False otherwise
     25     """
     26     def __init__(self, title):
     27         self.title = title
     28 
     29     def __call__(self, driver):
     30         return self.title in driver.title
     31 
     32 class presence_of_element_located(object):
     33     """ An expectation for checking that an element is present on the DOM
     34     of a page. This does not necessarily mean that the element is visible.
     35     locator - used to find the element
     36     returns the WebElement once it is located
     37     """
     38     def __init__(self, locator):
     39         self.locator = locator
     40 
     41     def __call__(self, driver):
     42         return _find_element(driver, self.locator)
     43 
     44 class visibility_of_element_located(object):
     45     """ An expectation for checking that an element is present on the DOM of a
     46     page and visible. Visibility means that the element is not only displayed
     47     but also has a height and width that is greater than 0.
     48     locator - used to find the element
     49     returns the WebElement once it is located and visible
     50     """
     51     def __init__(self, locator):
     52         self.locator = locator
     53 
     54     def __call__(self, driver):
     55         try:
     56             return _element_if_visible(_find_element(driver, self.locator))
     57         except StaleElementReferenceException:
     58             return False
     59 
     60 class visibility_of(object):
     61     """ An expectation for checking that an element, known to be present on the
     62     DOM of a page, is visible. Visibility means that the element is not only
     63     displayed but also has a height and width that is greater than 0.
     64     element is the WebElement
     65     returns the (same) WebElement once it is visible
     66     """
     67     def __init__(self, element):
     68         self.element = element
     69 
     70     def __call__(self, ignored):
     71         return _element_if_visible(self.element)
     72 
     73 def _element_if_visible(element, visibility=True):
     74     return element if element.is_displayed() == visibility else False
     75 
     76 class presence_of_all_elements_located(object):
     77     """ An expectation for checking that there is at least one element present
     78     on a web page.
     79     locator is used to find the element
     80     returns the list of WebElements once they are located
     81     """
     82     def __init__(self, locator):
     83         self.locator = locator
     84 
     85     def __call__(self, driver):
     86         return _find_elements(driver, self.locator)
     87 
     88 class text_to_be_present_in_element(object):
     89     """ An expectation for checking if the given text is present in the
     90     specified element.
     91     locator, text
     92     """
     93     def __init__(self, locator, text_):
     94         self.locator = locator
     95         self.text = text_
     96 
     97     def __call__(self, driver):
     98         try :
     99             element_text = _find_element(driver, self.locator).text
    100             return self.text in element_text
    101         except StaleElementReferenceException:
    102             return False
    103 
    104 class text_to_be_present_in_element_value(object):
    105     """
    106     An expectation for checking if the given text is present in the element's
    107     locator, text
    108     """
    109     def __init__(self, locator, text_):
    110         self.locator = locator
    111         self.text = text_
    112 
    113     def __call__(self, driver):
    114         try:
    115             element_text = _find_element(driver,
    116                                          self.locator).get_attribute("value")
    117             if element_text:
    118                 return self.text in element_text
    119             else:
    120                 return False
    121         except StaleElementReferenceException:
    122                 return False
    123 
    124 class frame_to_be_available_and_switch_to_it(object):
    125     """ An expectation for checking whether the given frame is available to
    126     switch to.  If the frame is available it switches the given driver to the
    127     specified frame.
    128     """
    129     def __init__(self, locator):
    130         self.frame_locator = locator
    131 
    132     def __call__(self, driver):
    133         try:
    134             if isinstance(self.frame_locator, tuple):
    135                 driver.switch_to.frame(_find_element(driver,
    136                                                      self.frame_locator))
    137             else:
    138                 driver.switch_to.frame(self.frame_locator)
    139             return True
    140         except NoSuchFrameException:
    141             return False
    142 
    143 class invisibility_of_element_located(object):
    144     """ An Expectation for checking that an element is either invisible or not
    145     present on the DOM.
    146 
    147     locator used to find the element
    148     """
    149     def __init__(self, locator):
    150         self.locator = locator
    151 
    152     def __call__(self, driver):
    153         try:
    154             return _element_if_visible(_find_element(driver, self.locator), False)
    155         except (NoSuchElementException, StaleElementReferenceException):
    156             # In the case of NoSuchElement, returns true because the element is
    157             # not present in DOM. The try block checks if the element is present
    158             # but is invisible.
    159             # In the case of StaleElementReference, returns true because stale
    160             # element reference implies that element is no longer visible.
    161             return True
    162 
    163 class element_to_be_clickable(object):
    164     """ An Expectation for checking an element is visible and enabled such that
    165     you can click it."""
    166     def __init__(self, locator):
    167         self.locator = locator
    168 
    169     def __call__(self, driver):
    170         element = visibility_of_element_located(self.locator)(driver)
    171         if element and element.is_enabled():
    172             return element
    173         else:
    174             return False
    175 
    176 class staleness_of(object):
    177     """ Wait until an element is no longer attached to the DOM.
    178     element is the element to wait for.
    179     returns False if the element is still attached to the DOM, true otherwise.
    180     """
    181     def __init__(self, element):
    182         self.element = element
    183 
    184     def __call__(self, ignored):
    185         try:
    186             # Calling any method forces a staleness check
    187             self.element.is_enabled()
    188             return False
    189         except StaleElementReferenceException as expected:
    190             return True
    191 
    192 class element_to_be_selected(object):
    193     """ An expectation for checking the selection is selected.
    194     element is WebElement object
    195     """
    196     def __init__(self, element):
    197         self.element = element
    198 
    199     def __call__(self, ignored):
    200         return self.element.is_selected()
    201 
    202 class element_located_to_be_selected(object):
    203     """An expectation for the element to be located is selected.
    204     locator is a tuple of (by, path)"""
    205     def __init__(self, locator):
    206         self.locator = locator
    207 
    208     def __call__(self, driver):
    209         return _find_element(driver, self.locator).is_selected()
    210 
    211 class element_selection_state_to_be(object):
    212     """ An expectation for checking if the given element is selected.
    213     element is WebElement object
    214     is_selected is a Boolean."
    215     """
    216     def __init__(self, element, is_selected):
    217         self.element = element
    218         self.is_selected = is_selected
    219 
    220     def __call__(self, ignored):
    221         return self.element.is_selected() == self.is_selected
    222 
    223 class element_located_selection_state_to_be(object):
    224     """ An expectation to locate an element and check if the selection state
    225     specified is in that state.
    226     locator is a tuple of (by, path)
    227     is_selected is a boolean
    228     """
    229     def __init__(self, locator, is_selected):
    230         self.locator = locator
    231         self.is_selected = is_selected
    232 
    233     def __call__(self, driver):
    234         try:
    235             element = _find_element(driver, self.locator)
    236             return element.is_selected() == self.is_selected
    237         except StaleElementReferenceException:
    238             return False
    239 
    240 class alert_is_present(object):
    241     """ Expect an alert to be present."""
    242     def __init__(self):
    243         pass
    244 
    245     def __call__(self, driver):
    246         try:
    247             alert = driver.switch_to.alert
    248             alert.text
    249             return alert
    250         except NoAlertPresentException:
    251             return False
    252 
    253 def _find_element(driver, by):
    254     """Looks up an element. Logs and re-raises ``WebDriverException``
    255     if thrown."""
    256     try :
    257         return driver.find_element(*by)
    258     except NoSuchElementException as e:
    259         raise e
    260     except WebDriverException as e:
    261         raise e
    262 
    263 def _find_elements(driver, by):
    264     try :
    265         return driver.find_elements(*by)
    266     except WebDriverException as e:
    267         raise e

    哈哈,我相信这个py文件大家一看就能懂。这无非就是一些预期条件。

    结合上面的WebDriverWait,我们可以这么用:

    from selenium.webdriver.support.wait import WebDriverWait
    from selenium.webdriver.support import expected_conditions as EC
    
    '''
    10秒钟等待浏览器弹出的对话框,如果出现,就点击确定按钮
    '''
    WebDriverWait(chromedriver,10).until(EC.alert_is_present()).accept()
    我们的自动化脚本跑得快慢或者出现异常,很大程度上取决于我们设定的等待时间,如果你还是习惯于time.sleep(5)这种方式的话,这将会浪费很多时间。
    根据expected_conditions.py文件的写法,我们也可以定义一些自己的期待类,例如:
    from selenium.webdriver.support.wait import WebDriverWait
    from selenium.webdriver.support import expected_conditions as EC
    
    
    class must_get_url(object):
        '''
        必须到达的URL
           参数:
           url    - 必须到达的地址
        '''
        def __init__(self, url):
            self.url = url
    
        def __call__(self, driver):
            driver.get(self.url)
            return self.url == driver.current_url
    
    options = webdriver.ChromeOptions()
    options.add_argument("--test-type")
    chromedriver =     webdriver.Chrome(r"E:MyProjectWebDriverchromedriver.exe",chrome_options=options)
    WebDriverWait(chromedriver,10).until(must_get_url("https://www.baidu.com"))




  • 相关阅读:
    设计模式-中介者模式
    设计模式-中介者模式
    设计模式-职责链模式
    设计模式-职责链模式
    设计模式-命令模式
    设计模式-命令模式
    设计模式-桥接模式
    模乘逆元与孙子定理
    网贷野蛮生长加速 超百亿平台频频涌现
    获乐视千万投资 电桩“傍上大款”
  • 原文地址:https://www.cnblogs.com/yicaifeitian/p/4749149.html
Copyright © 2011-2022 走看看