【问题标题】:Wait for CSS property to change before asserting the change在断言更改之前等待 CSS 属性更改
【发布时间】:2017-12-05 09:07:45
【问题描述】:

我正在使用 python webdriver,我试图让系统等待,直到单击提交按钮后密码字段的边框颜色发生变化。颜色从一种渐变到另一种,我可以使用以下方法获得所需的结果:-

password_border_colour_after_click = ""
count = 0
while password_border_colour_after_click != "rgba(169, 68, 66, 1)":
    password_border_colour_after_click = self.driver.find_element_by_name("password").value_of_css_property('border-bottom-color')
    time.sleep(0.1)
    count += 1
    if password_border_colour_after_click == "rgba(169, 68, 66, 1)":
        break
    elif count > 50:
        break
assert password_border_colour_after_click == "rgba(169, 68, 66, 1)"

感觉有点笨拙,而且可能是糟糕的代码,所以我想必须有一种方法可以将它全部打包到等待命令中,但我无法正确使用语法。

有可能吗?

【问题讨论】:

    标签: python css google-chrome selenium-webdriver wait


    【解决方案1】:

    TL;DR;

    Selenium API 有一个“等待...” 功能:

    http://selenium-python.readthedocs.io/waits.html

    实现一个expected_condition,然后将其与wait结合

    element = WebDriverWait(driver, 10)
                 .until(custom_expected_condition((By.ID, 'search-input'), argA, argB))
    

    等待

    值得知道的是,“等待”是同步运行的(阻塞线程),并且可以与以下之一结合使用,开箱即用

    • title_is
    • title_contains
    • presence_of_element_located
    • visibility_of_element_located
    • visibility_of
    • presence_of_all_elements_located
    • text_to_be_present_in_element
    • text_to_be_present_in_element_value
    • frame_to_be_available_and_switch_to_it
    • invisibility_of_element_located
    • element_to_be_clickable
    • staleness_of
    • element_to_be_selected
    • element_located_to_be_selected
    • element_selection_state_to_be
    • element_located_selection_state_to_be
    • alert_is_present

    如您所见,不存在element_has_style_value 条件,但是始终可以使用自己的实现来扩展“等待”。

    在文档中,自定义的预期条件如下所示:

    class element_has_css_class(object):
      """An expectation for checking that an element has a particular css class.
    
      locator - used to find the element
      returns the WebElement once it has the particular css class
      """
      def __init__(self, locator, css_class):
        self.locator = locator
        self.css_class = css_class
    
      def __call__(self, driver):
        element = driver.find_element(*self.locator)   # Finding the referenced element
        if self.css_class in element.get_attribute("class"):
            return element
        else:
            return False
    

    它的用法是:

    # Wait until an element with id='myNewInput' has class 'myCSSClass'
    wait = WebDriverWait(driver, 10)
    element = wait.until(element_has_css_class((By.ID, 'myNewInput'), "myCSSClass"))
    

    可能的解决方案

    将所有内容放在一个资产页面中,如下所示:https://output.jsbin.com/xutipu

    可以实现这个:

    class element_has_css_value(object):
      """An expectation for checking that an element has a particular css property and value.
    
      locator - used to find the element
      returns the WebElement once it has the particular css property and value
      """
      def __init__(self, locator, css_property, css_value):
        self.locator = locator
        self.css_property = css_property
        self.css_value = css_value
    
      def matchPropertyAndValue(self, css_property, css_value):
    
          return css_property == self.css_property and css_value  == self.css_value;
    
      def extractPropertyAndValue(self, cssStatement):
        keyValue = cssStatement.split(':')
        if len(keyValue) == 2:
            key = keyValue[0].strip();
            value = keyValue[1].strip();
            return (key, value)
        return (None, None)
    
      def findProperty(self, entries):
        foundProperty = False
        for entry in entries:
          (css_property, css_value) = self.extractPropertyAndValue(entry)
          if css_value is None:
              continue
          foundProperty = self.matchPropertyAndValue(css_property, css_value);
          if foundProperty :
              break;
        return foundProperty
    
      def __call__(self, driver):
        element = driver.find_element(*self.locator)   # Finding the referenced element
        styles = element.get_attribute("style")
        entries = styles.split(';')
        foundProperty = self.findProperty(entries);
    
        if foundProperty :
            return element
        else:
            return False
    

    并像这样使用它:

    from selenium import webdriver
    from selenium.webdriver.common.keys import Keys
    from selenium.webdriver.common.by import By
    from selenium.webdriver.support.ui import WebDriverWait
    from selenium.webdriver.support import expected_conditions as EC
    driver = webdriver.Chrome()
    driver.get("https://output.jsbin.com/xutipu")
    button = None;
    try:
        button = WebDriverWait(driver, 10).until(
            EC.presence_of_element_located((By.ID, "search-button"))
        )
    except e:
        print(e);
        driver.quit()
    
    button.send_keys(Keys.RETURN)
    
    try :
        wait = WebDriverWait(driver, 10)
        element = wait.until(element_has_css_value((By.ID, 'search-input'), "border-color", "rgb(169, 68, 66)"))
        assert element;
        print('Success');
    finally:
        driver.quit()
    

    【讨论】:

      【解决方案2】:

      我不知道如何在 Python 中执行此操作,因为我不太熟悉该语言,但在 C# 中,您可以创建类似于自定义 ExpectedConditions 的委托函数,您可以将其与 WebDriverWait 类一起使用.

      WebDriverWait 类在抛出异常之前等待 n 秒。

      C# 中的示例(伪)代码:

      public static class CustomExpectedConditions
      {
          public static Func<IWebDriver, bool> ElementAttributeContains(By locator, string attributeName, string expectedValue)
          {
              return (driver) => driver.FindElement(locator).GetAttribute(attributeName).Contains(expectedValue);
          }
      }
      

      这使您可以像这样使用它:

      var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(5));
      wait.Until(CustomExpectedConditions.ElementAttributeContains(By.Name("password"), "style", "rgba(169, 68, 66, 1)"));
      

      我在 Python 中找到了用于自定义预期条件的示例代码:

      class element_has_css_class(object):
      """An expectation for checking that an element has a particular css class.
      
      locator - used to find the element
      returns the WebElement once it has the particular css class
      """
      def __init__(self, locator, css_class):
        self.locator = locator
        self.css_class = css_class
      
      def __call__(self, driver):
        element = driver.find_element(*self.locator)   # Finding the referenced element
        if self.css_class in element.get_attribute("class"):
            return element
        else:
            return False
      
      # Wait until an element with id='myNewInput' has class 'myCSSClass'
      wait = WebDriverWait(driver, 10)
      element = wait.until(element_has_css_class((By.ID, 'myNewInput'), "myCSSClass"))
      

      希望这会让你朝着正确的方向开始

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-02-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-07-22
        相关资源
        最近更新 更多