Подтвердить что ты не робот

Обработка Select2 с помощью Selenium webdriver

Я ударился головой о стену, пытаясь выбрать опцию из списка выбора select2, выбранного ajax, с веб-селеном селена. Мне удалось заставить его работать с IE webdriver, но не с firefox. Вот мое хакерское решение для IE

 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 с похожими результатами.

Кто-нибудь сталкивался с подобной проблемой раньше?

4b9b3361

Ответ 1

Не могли бы вы показать нам и локаторы? Вот что я тестировал без каких-либо проблем.

Примечание

  • Чтобы открыть поле выбора, используйте css selector #s2id_e1 .select2-choice или эквивалентный XPath.
  • Убедитесь, что #select2-drop является видимым, с помощью селектора css #select2-drop:not([style*='display: none']) или эквивалентного XPath.
  • Обязательно выберите выбранный элемент с помощью 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();

Ответ 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 с идентификатором (атрибутом): s2id_autogen1:

List<WebElement> select2Results = getDataFromSelect2("//input[@id='s2id_autogen1']");

for(WebElement item: select2Results)
{
    System.out.println(item.getText());
}

Ответ 4

Здесь представлено твердое, многоразовое решение, которое обрабатывает дополнительную проблему взаимодействия с несколькими раскрывающимися списками select2 на одной странице.

По какой-то причине webdriver не рассматривал элемент для отправки значения поиска как видимого, даже если вы могли видеть его на экране, а курсор был в нем. Что проверяет проверка "если отображается". Затем он использует другой селектор.

Его функция, с которой вы можете отправить идентификатор поля, с которым хотите взаимодействовать (за исключением стандартного 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);
        }

    }

Ответ 5

Я использовал приведенный ниже код, чтобы выбрать нужный вариант, и он сработал. Это также должно быть быстрее, чем выполнение нескольких кликов.

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)

Ответ 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);
}