【问题标题】:Handling Select2 with Selenium webdriver使用 Selenium webdriver 处理 Select2
【发布时间】:2013-07-19 04:56:27
【问题描述】:

我一直在努力尝试使用 selenium webdriver 从启用 ajax 的 select2 选择列表中选择一个选项。我已经设法让它与 IE webdriver 但不是 Firefox 一起工作。这是我针对 IE 的 hacky 解决方案

 public static void SetSelect2Option(this IWebDriver driver, By locator, string subContainerClass, string searchTerm, TimeSpan? ajaxWaitTimeSpan = null)
    {
        var select2Product = driver.FindElement(locator);
        select2Product.Click();
        var searchBox = driver.FindElement(By.CssSelector(subContainerClass + " .select2-input"));
        searchBox.SendKeys(searchTerm);
        if (ajaxWaitTimeSpan != null)
        {
            driver.Manage().Timeouts().ImplicitlyWait(ajaxWaitTimeSpan.Value);
        }
        var selectedItem = driver.FindElements(By.CssSelector(subContainerClass + " .select2-results li")).First();
        selectedItem.Click();
        selectedItem.SendKeys(Keys.Enter);
    }

在 Firefox 中,此解决方案一直有效,直到 SendKeys 调用点挂起并继续执行下一步,而无需实际触发 select2 的事件来填充所选项目。

我也厌倦了使用http://code.google.com/p/selenium/wiki/AdvancedUserInteractions api 并获得类似的结果。

以前有没有人遇到过类似的问题?

【问题讨论】:

    标签: c# selenium selenium-webdriver jquery-select2


    【解决方案1】:

    能否请您也向我们展示定位器?这是我测试的没有任何问题。

    注意

    1. 要打开选择框,请使用 css 选择器 #s2id_e1 .select2-choice 或等效的 XPath。
    2. 通过 css 选择器 #select2-drop:not([style*='display: none']) 或等效的 XPath 确保 #select2-drop 是可见的。
    3. 确保使用subContainerClass + .select2-results li.select2-result-selectable 或等效的XPath 单击可选项。
    var driver = new FirefoxDriver();
    driver.Url = "http://ivaynberg.github.io/select2/";
    
    var select2Product = driver.FindElement(By.CssSelector("#s2id_e1 .select2-choice"));
    select2Product.Click();
    
    string subContainerClass = "#select2-drop:not([style*='display: none'])";
    var searchBox = driver.FindElement(By.CssSelector(subContainerClass + " .select2-input"));
    searchBox.SendKeys("Ohio");
    
    var selectedItem = driver.FindElements(By.CssSelector(subContainerClass + " .select2-results li.select2-result-selectable")).First();
    selectedItem.Click();
    

    【讨论】:

    • FWIW,我不得不使用 'ClickAt' 5,5 而不是点击来让它工作。
    • @Daniel:你更有可能有其他元素重叠。什么版本?哪个浏览器?
    • 这是在 FF 的 Selenium 2.4.0 中。我正在使用 IDE,但希望行为相似。我是 Selenium 的新手,但是当 clickAt 发生时,我无法想象是什么导致点击不起作用。单击的行为是不出现 select2 下拉菜单。不过,您的回答有助于我找到正确的元素......
    • 我还必须等待与select2Product 相对应的元素显示出来。否则,测试会随机失败并返回 Elementnotvisibleexception
    【解决方案2】:

    我花了一些时间让它在 FF、Chrome 和 IE8-11 中运行。

    1. 点击下拉箭头
    2. 点击需要的li

    这是我的简化代码:

    [FindsBy(How = How.ClassName, Using = "select2-arrow")]
    private IWebElement Selector { get; set; }
    
    private void selectItem(string itemText)
    {
        Selector.Click();  // open the drop
        var drop = Driver.FindElement(By.Id("select2-drop"));    // exists when open only
        var item = drop.FindElement(By.XPath(String.Format("//li[contains(translate(., '{0}', '{1}'), '{1}')]", itemText.ToUpper(), itemText.ToLower())));
        item.Click();
    }
    

    【讨论】:

      【解决方案3】:

      这是我的代码(获取/显示):

      获取select2 可用元素(结果):

      public List<WebElement> getDataFromSelect2(String elementXpath)
      {       
          WebElement select2Element = driver.findElement(By.xpath(elementXpath));
          select2Element.click();     
      
          WebDriverWait webDriverWait = new WebDriverWait(driver, 90);
          webDriverWait.until(ExpectedConditions.presenceOfElementLocated(By.xpath("//ul[@class='select2-results']//div")));
      
          WebElement select2ElementResults=driver.findElement(By.xpath("//div[@id='select2-drop']/ul[@class='select2-results']"));
          List<WebElement> selectResultsAsListCollection = select2ElementResults.findElements(By.tagName("div"));
      
          return selectResultsAsListCollection; 
      }
      

      显示select2 可用元素(结果)

      使用select2,id(属性)为:s2id_autogen1

      List<WebElement> select2Results = getDataFromSelect2("//input[@id='s2id_autogen1']");
      
      for(WebElement item: select2Results)
      {
          System.out.println(item.getText());
      }
      

      【讨论】:

        【解决方案4】:

        我使用下面的代码来选择所需的选项并且它有效。这也必须比执行多次点击更快。

        String script = "$('select#yearSelector').trigger($.Event('change',{val:'" + year + "'}))";
        ((JavascriptExecutor) driver).executeScript(script);
        

        而且,在 Python 中,如果这个单行代码不起作用,请尝试将其拆分为组件:

         value = ['a', 'b', 'c']
         script = "var elem = $('select#tradingMarketSelect'); "
         script += "elem.val(%s); " % value
         script += "elem.change();"
         self.driver.execute_script(script)
        

        【讨论】:

          【解决方案5】:

          这是一个可靠的、可重复使用的解决方案,可以处理与一个页面上的多个 select2 下拉菜单交互的额外问题。

          由于某种原因,webdriver 没有考虑将搜索值发送到的元素是可见的,即使您可以在屏幕上看到它并且光标在其中。这就是“如果显示”测试检查的内容。然后它使用不同的选择器。

          它是一个函数,您可以发送要与之交互的字段的 ID(减去标准 s2id_)和要选择的值(或至少足以进行选择。)

          额外的 thread.sleep()s 只是为了帮助我观看它。我认为它们不会影响结果。

          public void SelectDropDownOption(string dropDownID, string option)
              {
                  for (int second = 0; ; second++)
                  {
                      if (second >= 60) Assert.Fail("timeout");
                      try
                      {
                          if (driver.FindElement(By.CssSelector("div[ID^=s2id_" + dropDownID + "]>a.select2-choice")).Displayed) break;
                      }
                      catch (Exception)
                      { }
                      Thread.Sleep(1000);
                  }
          
                  driver.FindElement(By.CssSelector("div[ID^=s2id_" + dropDownID + "]>a.select2-choice")).Click();
                  Thread.Sleep(1000);
          
                  if (driver.FindElement(By.CssSelector("input.select2-input.select2-focused")).Displayed == true)
                  {
                      driver.FindElement(By.CssSelector("input.select2-input.select2-focused")).SendKeys(option);
                      Thread.Sleep(500);
                      driver.FindElement(By.CssSelector("input.select2-input.select2-focused")).SendKeys(Keys.Enter);
                      Thread.Sleep(500);
                  }
                  else
                  {
                      driver.FindElement(By.CssSelector("input.select2-focusser.select2-offscreen")).SendKeys(option);
                      Thread.Sleep(500);
                      driver.FindElement(By.CssSelector("input.select2-focusser.select2-offscreen")).SendKeys(Keys.Enter);
                      Thread.Sleep(500);
                  }
          
              }
          

          【讨论】:

          • @HappyBird,我们都在这里学习。你能提出改进建议吗?我的解决方案可能并不完美,但我觉得它提供了很多有用的信息。
          • 对不起,我不需要粗鲁。我的意思是应该尽量避免Thread.Sleep()
          • 啊,感谢您的回复。我同意。如原始帖子中所述,这些只是故障排除的剩余部分,而不是实际解决方案的一部分。我想我应该删除它们并保持简单。再次感谢并祝您编码愉快。
          【解决方案6】:
          protected void SelectOptionForSelect2(IWebDriver driver, string id, string text)
          {
            var element = driver.FindElement(By.Id(id)).FindElement(By.XPath("following-sibling::*[1]"));
            element.Click();
          
            element = driver.FindElement(By.CssSelector("input[type=search]"));
            element.SendKeys(text);
          
            Thread.Sleep(1000);
            element.SendKeys(Keys.Enter);
          }
          

          【讨论】:

            【解决方案7】:

            尝试选择 webdriver javascript 执行。下面是一个方便的 C# 方法。

            // usings
            using System;
            using OpenQA.Selenium;
            using OpenQA.Selenium.Chrome;
            
            
            // method
            public static void SetSelect2Option_JSExample(this IWebDriver driver, string select2Id, string value)
            {       
                IJavaScriptExecutor jsExecutor = (IJavaScriptExecutor)driver;
                string js = "$('#" + select2Id + "').val('" + value + "').trigger('change');";
                string jsOutput = (string)jsExecutor.ExecuteScript(js);
            }
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2016-03-23
              • 2014-06-27
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多