我正在使用 Seleniunm 来测试我的网页。
我有一个下拉框,我想为其选择一个选项。这会触发一些 Ajax,获取相关单元的一些数据。
当我正常查看页面时,这工作正常,但使用 selenium,它会更改文本框中的选项,但不会触发 Ajax。
页面上的标记:
<select id="measure" name="measure">
<option selected="selected" value="1">Metric</option>
<option value="2">US Imperial</option>
<option value="3">UK Imperial</option>
</select>
C#代码:
var dropDown = WebDriver.FindElementById("measure");
var selectElement = new SelectElement(dropDown);
selectElement.SelectByValue("3");
在选择/单击下拉选项方面我缺少什么?
谢谢
我最近使用 FirefoxDriver 时遇到了同样的问题。在我的特定设置中,我在
<html>
标签上有一个冒泡委托的“更改”事件处理程序,但未触发:
document.documentElement.addEventListener("change", handleChange, false);
function handleChange(event) {
// do stuff
}
以下代码即使在下拉列表中也不会触发 onchange:
SelectElement select = new SelectElement(element);
select.SelectByText("Foo");
该选项将被选中,但即使将焦点设置到另一个表单字段,也不会触发任何更改。在触发更改事件之前,我使用自己的鼠标在下拉列表中选择一个新值。
我通过单击下拉菜单,然后单击其中的选项解决了此问题:
IWebElement element = // ...
element.Click();
element.FindElements(By.TagName("option"))
.Single(opt => opt.Text == Value)
.Click();
这里有一个方便的扩展方法,可以实现相同的功能:
public static class IWebElementExtensions
/// <summary>
/// Selects an option in a dropdown list by visible option text.
/// </summary>
/// <param name="element"></param>
/// <param name="optionText"></param>
public static void SelectOptionByText(this IWebElement element, string optionText)
{
if (element == null)
throw new ArgumentNullException("element");
if (element.TagName != "select")
throw new ArgumentException("The element must be a <select> tag");
if (optionText == null)
throw new ArgumentNullException("optionText");
var options = element.FindElements(By.TagName("option"))
.Where(opt => opt.Text == optionText);
if (options.Count() == 0)
throw new NoSuchElementException("Could not find <option>" + optionText + "</option> inside <select id=\"" + element.GetAttribute("id") + "\">");
if (options.Count() > 1)
throw new WebDriverException("Too many <option>" + optionText + "</option> tags inside <select id=\"" + element.GetAttribute("id") + "\">");
element.Click();
options.Single().Click();
element.Click();
}
}
并使用:
element.SelectOptionByText("Foo");
好处
缺点
我使用 FirefoxDriver 而不是 InternetExplorer 驱动程序,现在一切看起来都很好。
我发现使用 jQuery 比 WebDriver 的 SelectElement 类效果更好。
试试这个。请注意我如何调用 jQuery .change 事件(JavaScript onchange 事件)。我有另一个取决于此下拉列表的下拉列表,因此为了填充依赖的下拉列表,我必须调用该事件。为了使其正常工作,我还必须为我的 Firefox 驱动程序启用本机事件。我看到您是按值选择,而不是按选项文本。您应该能够使用适用于按值选择的代码来修改我的 jQuery 代码。另外,如果您正在使用 ASP.NET 控件,则使用 WebDriver 的代码将无法正常工作,因为 id 是基于浏览器的动态。因此,您必须使用客户端 id 通过 jQuery 获取 id。如果您是这种情况,我也将该代码粘贴在下面。
public static void SetDropdownSelectedOptionValue(IWebDriver driver, string tagId, string newValue)
{
//new SelectElement(driver.FindElement(By.Id("book-country_id"))).SelectByText(newValue);
IJavaScriptExecutor js = driver as IJavaScriptExecutor;
js.ExecuteScript("$('#" + tagId + " option:contains(" + newValue + ")').attr('selected', 'selected')");
js.ExecuteScript("$('#" + tagId + "').change()");
//driver.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(Config.WAIT_TIME));
System.Threading.Thread.Sleep(1000);
}
如果调用 onchange 本机事件,则为必需。
FirefoxProfile firefoxProfile = new FirefoxProfile();
firefoxProfile.EnableNativeEvents = true;
如果使用 ASP.NET 控件,请使用此 jQuery 代码而不是显式 id。当然修改此代码以将 tagId 放在中间以获得 jQuery 选择器。
$('#<%=dropdownid.ClientID %>')
我尝试了所有我能想到的解决方案来处理 Formkit 选择,该选择在选择选项时不会触发表单更改。以下是我能想到的唯一解决方案。它不是防弹的,但它有作用。
此解决方案使用操作。检查此链接以获取更多信息: https://www.browserstack.com/guide/action-class-in-selenium
注意:在实施此解决方案之前,请尝试使用向下箭头和 Enter 键操作表单。如果它不能手动工作,它就不能以编程方式工作。
var selectorBy = sharedStepSupport.GetSelectorBy(selector, selectorType); //A custom method that builds the selector By.
var selectPreScroll = webDriver.FindElement(selectorBy);
webDriver.ScrollToElement(selectPreScroll); //A custom scroll method
var select = webDriver.FindElement(selectorBy);
Thread.Sleep(250);
select.Click();
var options = select.FindElements(By.TagName("option")).Where(opt => opt.Enabled == true); //Gets all interactable options as some are disabled and aren't presented.
var optionIndex = options.TakeWhile(opt => opt.Text == optionText).Count(); //This gets the index of the option that you are looking for (optionText is passed to this method as the text of the desired option)
//Commented below is the long way you would do it. The TakeWhile can be unreliable.
//for (int i = 0; i < options.Count(); i++)
//{
// var text = options.ElementAt(i).Text;
// if (text == optionText)
// {
// desiredOptionIndex = i;
// i = options.Count();
// }
//}
Actions actions = new Actions(webDriver); //Actions allows a series of actions to be built and performed. This can be a really useful tool for those doing automation.
for (int i = 0;i <= optionIndex; i++)
{
actions.SendKeys(Keys.Down);
}
actions.SendKeys(Keys.Enter);
actions.Build();
actions.Perform();