Selenium C# Webdriver 下拉菜单不会触发 Javascript

问题描述 投票:0回答:4

我正在使用 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");

在选择/单击下拉选项方面我缺少什么?

谢谢

c# ajax selenium webdriver
4个回答
1
投票

我最近使用 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");

好处

  • 无 JavaScript hack
  • 使用 Selenium 中的本机事件

缺点

  • 执行需要更长的时间

0
投票

我使用 FirefoxDriver 而不是 InternetExplorer 驱动程序,现在一切看起来都很好。


0
投票

我发现使用 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 %>')

0
投票

我尝试了所有我能想到的解决方案来处理 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();
© www.soinside.com 2019 - 2024. All rights reserved.