Selenium DeselectAll 不适用于具有多个属性的 HTML SELECT
Selenium DeselectAll not working for HTML SELECT with multiple attribute
我正在使用 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>
我手动 select 一些项目。然后我想 deselect 所有这些(我正在使用 C# 但那没关系):
var carsElement = BrowserDriver.FindElementByName("cars");
var carsSelect = new SelectElement(carsElement);
carsSelect.DeselectAll();
会发生什么:第一个 selected 选项保留 selected,其他未selected。
查看代码,这是 必须 发生的,因为 DeselectAll()
为所有 selected 选项调用 Click()
。您可以在浏览器中尝试。这永远不会取消 select all 选项(除非您在单击时按住 CTRL,但 Selenium 代码不会这样做)。因此,正确的方法是更改 DeselectAll
以在单击时按 CTRL,如
所示
最重要的是,我知道如何解决这个问题;我的问题是:我错过了什么吗?有没有更简单的方法? SelectElement
不是 HTML SELECT 多个吗?
您肯定可以通过
取消选择这些
browser.execute_script("[...document.querySelectorAll('[name=cars] option')].map(o => o.selected = false)")
Select
class 可以处理多选下拉。它甚至在使用 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();
}
}
当您单击第一个 select 选项而不按控制键时,此选项仍然 selected 但所有其他选项都被取消 selected,因此单击是实际上没有对其余选项执行,因为 isSelected
和 select
都是 SetSelected
.
中的 false
解决方案是按照您的问题中的建议实施您自己的 DeselectAll()
,或者 select 下拉列表中的第一个选项(这将自动取消 select 所有其他选项)然后 deselect 使用 control.
这个选项
即使我没有询问如何设置选择状态的代码,我还是会 post 为遇到同样问题的任何人提供代码。这是 C# 代码。您将需要 NuGet 包 Selenium.WebDriver and Selenium.Support。 BrowserDriver
是我的助手 class 的成员变量,其中包含此方法。
/// <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();
}
}
我已经通过 Selenium Python Client 验证了您使用 deselect_all()
方法的 usecase 并且它似乎工作 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()
浏览器快照:
我正在使用 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>
我手动 select 一些项目。然后我想 deselect 所有这些(我正在使用 C# 但那没关系):
var carsElement = BrowserDriver.FindElementByName("cars");
var carsSelect = new SelectElement(carsElement);
carsSelect.DeselectAll();
会发生什么:第一个 selected 选项保留 selected,其他未selected。
查看代码,这是 必须 发生的,因为 DeselectAll()
为所有 selected 选项调用 Click()
。您可以在浏览器中尝试。这永远不会取消 select all 选项(除非您在单击时按住 CTRL,但 Selenium 代码不会这样做)。因此,正确的方法是更改 DeselectAll
以在单击时按 CTRL,如
最重要的是,我知道如何解决这个问题;我的问题是:我错过了什么吗?有没有更简单的方法? SelectElement
不是 HTML SELECT 多个吗?
您肯定可以通过
取消选择这些browser.execute_script("[...document.querySelectorAll('[name=cars] option')].map(o => o.selected = false)")
Select
class 可以处理多选下拉。它甚至在使用 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();
}
}
当您单击第一个 select 选项而不按控制键时,此选项仍然 selected 但所有其他选项都被取消 selected,因此单击是实际上没有对其余选项执行,因为 isSelected
和 select
都是 SetSelected
.
false
解决方案是按照您的问题中的建议实施您自己的 DeselectAll()
,或者 select 下拉列表中的第一个选项(这将自动取消 select 所有其他选项)然后 deselect 使用 control.
即使我没有询问如何设置选择状态的代码,我还是会 post 为遇到同样问题的任何人提供代码。这是 C# 代码。您将需要 NuGet 包 Selenium.WebDriver and Selenium.Support。 BrowserDriver
是我的助手 class 的成员变量,其中包含此方法。
/// <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();
}
}
我已经通过 Selenium Python Client 验证了您使用 deselect_all()
方法的 usecase 并且它似乎工作 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()
浏览器快照: