Selenium DeselectAll不适用于具有多个属性的HTML SELECT

时间:2018-11-22 09:38:44

标签: selenium select selenium-webdriver webdriver multi-select

我正在使用this HTML code

<select name="cars" multiple>
  <option value="volvo">Volvo</option>
  <option value="saab">Saab</option>
  <option value="opel">Opel</option>
  <option value="audi">Audi</option>
</select>

手动选择一些项目。然后我想取消所有选择(我正在使用C#,但这没关系):

var carsElement = BrowserDriver.FindElementByName("cars");
var carsSelect = new SelectElement(carsElement);
carsSelect.DeselectAll();

会发生什么:首先选择的选项保持选中状态,其他选项未被选中。

请看代码,这是必须发生的事情,因为DeselectAll()会为所有选定选项调用Click()。您可以在浏览器中尝试。这将永远不会取消选择所有选项(除非您在单击时按住CTRL键,但Selenium代码无法做到)。因此正确的方法是将DeselectAll更改为按How to perform Control key down in selenium webdriver?演示的同时单击CTRL

最重要的是,我知道如何解决这个问题;我的问题是:我错过了什么吗?有更容易的方法吗?是不是SelectElement不能用于HTML SELECT多个?

4 个答案:

答案 0 :(得分:2)

您可以肯定通过以下方式取消选择这些

browser.execute_script("[...document.querySelectorAll('[name=cars] option')].map(o => o.selected = false)")

答案 1 :(得分:0)

Select类可以处理多项选择下拉菜单。使用DeselectAll()时,它甚至检查下拉列表是否为多项选择。来自github

public void DeselectAll()
{
    if (!this.IsMultiple)
    {
        throw new InvalidOperationException("You may only deselect all options if multi-select is supported");
    }

    foreach (IWebElement option in this.Options)
    {
        SetSelected(option, false);
    }
}

private static void SetSelected(IWebElement option, bool select)
{
    bool isSelected = option.Selected;
    if ((!isSelected && select) || (isSelected && !select))
    {
         option.Click();
    }
}

当您在不按下控制键的情况下单击第一个选择选项时,此选项将保持选中状态,但所有其他选项均被取消选择,因此实际上isSelectedselectfalse中的SetSelected

解决方案是按照问题中的建议实施自己的DeselectAll(),或者从下拉列表中选择第一个选项(这将自动取消选择所有其他选项),然后使用控件取消选择此选项。

答案 2 :(得分:0)

尽管我没有要求代码如何设置选择状态,但无论如何我都会将其发布给遇到相同问题的任何人。这是C#代码。您将需要NuGet软件包Selenium.WebDriverSelenium.SupportBrowserDriver是我的助手类的成员变量,其中包含此方法。

/// <summary>
/// Sets the selection state of <paramref name="selectElement"/>. All options specified  by <paramref name="selectedOptions"/>
/// are select, all others are unselected.
/// </summary>
/// <param name="selectElement">HTML select element</param>
/// <param name="selectedOptions">options to be selected</param>
internal void SelectStateByText(OpenQA.Selenium.Support.UI.SelectElement selectElement, params string[] selectedOptions)
{
    Assert.IsNotNull(selectElement);
    Assert.IsNotNull(selectedOptions);
    CollectionAssert.IsSubsetOf(selectedOptions, selectElement.Options.Select(o => o.Text).ToArray());
    if (!selectElement.IsMultiple)
    {
        Assert.AreEqual(1, selectedOptions.Length);
        selectElement.SelectByText(selectedOptions[0]);
    }
    else
    {
        var actions = new OpenQA.Selenium.Interactions.Actions(BrowserDriver);
        actions.KeyDown(Keys.LeftControl);
        foreach (var option in selectElement.Options)
        {
            if (selectedOptions.Contains(option.Text) && !option.Selected)
            {
                actions.Click(option);
            }
            else if (option.Selected)
            {
                actions.Click(option);
            }
        }
        actions.KeyUp(Keys.LeftControl).Build().Perform();
    }
}

答案 3 :(得分:-1)

我已经通过 Selenium Python客户端使用deselect_all()方法验证了您的用例,并且看来 perfecto 可行。

deselect_all()

deselect_all()方法清除所有选定的条目。仅在SELECT支持多个选择时有效。如果SELECT不支持多个选择,则抛出NotImplementedError。


插图

注意:正如您在问题中提到的,我还模拟了手动

所有项目的选择
  • 代码块:

    from selenium import webdriver
    from selenium.webdriver.common.by import By
    from selenium.webdriver.support.ui import WebDriverWait 
    from selenium.webdriver.support import expected_conditions as EC
    from selenium.webdriver.support.ui import Select
    import time
    
    options = webdriver.ChromeOptions() 
    options.add_argument("start-maximized")
    options.add_argument('disable-infobars')
    driver=webdriver.Chrome(chrome_options=options, executable_path=r'C:\Utility\BrowserDrivers\chromedriver.exe')
    driver.get('https://www.w3schools.com/tags/tryit.asp?filename=tryhtml_select_multiple')
    WebDriverWait(driver, 10).until(EC.frame_to_be_available_and_switch_to_it((By.ID,"iframeResult")))
    select_cars = Select(driver.find_element_by_css_selector("select[name='cars']"))
    time.sleep(5) # Timeframe to Manually select all the items
    select_cars.deselect_all()
    
  • 浏览器快照:

deselect_all.gif