使用 Selenium webdriver 处理 Select2

Posted

技术标签:

【中文标题】使用 Selenium webdriver 处理 Select2【英文标题】:Handling Select2 with Selenium webdriver 【发布时间】: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 并获得类似的结果。

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

【问题讨论】:

【参考方案1】:

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

注意

    要打开选择框,请使用 css 选择器 #s2id_e1 .select2-choice 或等效的 XPath。 通过 css 选择器 #select2-drop:not([style*='display: none']) 或等效的 XPath 确保 #select2-drop 是可见的。 确保使用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 中运行。

    点击下拉箭头 点击需要的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);

【讨论】:

以上是关于使用 Selenium webdriver 处理 Select2的主要内容,如果未能解决你的问题,请参考以下文章

使用 selenium webdriver chrome 处理“选择数字证书”

如何使用 Selenium WebDriver 处理登录弹出窗口?

在 Python 中使用 Selenium WebDriver 时处理 Firefox 无响应?

如何使用 selenium 或 webdriver 在测试自动化中处理文件上传

selenium+webdriver+python 中警告框的处理方法

如何使用 Selenium WebDriver 处理 Windows 文件上传?