Обработка 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 с похожими результатами.
Кто-нибудь сталкивался с подобной проблемой раньше?
Ответы
Ответ 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);
}