C# 如何使用Selenium中的CSS选择器查找非根元素的直接后代?
我正在尝试为下面的C# 如何使用Selenium中的CSS选择器查找非根元素的直接后代?,c#,css,selenium,C#,Css,Selenium,我正在尝试为下面的重用找到的WebElement,以搜索其子代和直接子代: ... 福 ... ... 这个表可能包含嵌套的表,也可能不包含嵌套的表,我只是不想涉猎整个过程,我宁愿使用一个更具体的选择器,它可以保证做我想做的事情。我需要的一些元素没有合理的ID,我想使用选择器查找它们: #tbl1>tbody>tr:first child>td:first child>div #tbl1>tbody>tr>td>button.btnDefault 为了减少代码的重复性,甚至更快,我想缓存元
重用找到的WebElement,以搜索其子代和直接子代:
...
福
...
...
这个表可能包含嵌套的表,也可能不包含嵌套的表,我只是不想涉猎整个过程,我宁愿使用一个更具体的选择器,它可以保证做我想做的事情。我需要的一些元素没有合理的ID,我想使用选择器查找它们:
#tbl1>tbody>tr:first child>td:first child>div
#tbl1>tbody>tr>td>button.btnDefault
为了减少代码的重复性,甚至更快,我想缓存
元素:
var table=driver.FindElement(By.Id(“tbl”);
var div=table.FindElement(By.CssSelector(“>tbody>tr:first-child>td:first-child>div”);
var button=table.FindElement(由.CssSelector(“>tbody>tr>td>button.btnDefault”);
在第二个和第三个查询中,这会导致CSS选择器无效。这是正确的,但同样,标准CSS语法并不意味着要从特定的范围进行搜索。这里是否有某种构造可以用作查询的根?定义页面类时,为什么不使用:
public IWebDriver WebDriver { get; set; }
[FindsBy(How = How.ClassName, Using = "btnDefault")]
private IWebElement button { get; set; }
实例化该类时,您将获得作为WebElement的按钮。因为您是从table元素调用FindElement,那么这应该可以工作:
var div = table.FindElement(By.CssSelector("tbody > tr:first-child > td:first-child > div"));
var button = table.FindElement(By.CssSelector("tbody > tr > td > button.btnDefault"));
这删除了开头的“>”。如果有多个按钮具有相同的类名。当我建议识别按钮所在的单元格时。可能是以下代码将起作用:
public IWebDriver WebDriver { get; set; }
IWebElement tableElement = WebDriver.FindElement(By.Id(tableName));
IWebElement tbodyElement = tableElement.FindElement(By.TagName("tbody"));
List<IWebElement> rows = new List<IWebElement>(tbodyElement.FindElements(By.TagName("tr")));
foreach (var row in rows)
{
if (row.GetAttribute("row") != "-1" && (!string.IsNullOrWhiteSpace(row.GetAttribute("row"))))
{
List<IWebElement> cells = new List<IWebElement>(row.FindElements(By.TagName("td")));
if (cells.Count != 0)
{
if (cells[0].Text == columnName) //Identify the cell, may use other attribute
{
IWebElement btn = cells[0].FindElement(By.ClassName("btnDefault")) as IWebElement;
return btn;
}
}
}
}
public-IWebDriver-WebDriver{get;set;}
IWebElement tableElement=WebDriver.FindElement(By.Id(tableName));
IWebElement tbodyElement=tableElement.FindElement(按.TagName(“tbody”));
列表行=新列表(tbodyElement.FindElements(按.TagName(“tr”));
foreach(行中的变量行)
{
if(row.GetAttribute(“row”)!=“-1”&(!string.IsNullOrWhiteSpace(row.GetAttribute(“row”)))
{
列表单元格=新列表(row.FindElements(按.TagName(“td”));
如果(cells.Count!=0)
{
如果(单元格[0].Text==columnName)//标识该单元格,则可以使用其他属性
{
IWebElement btn=单元格[0]。将FindElement(By.ClassName(“btnDefault”))作为IWebElement;
返回btn;
}
}
}
}
一个选项是使用伪类:scope
引用当前元素
此伪类存在于中,并且当前受Firefox和Chrome支持。但是一些浏览器可能不支持它
var table = driver.FindElement(By.Id("tbl"));
var div = table.FindElement(By.CssSelector(":scope > tbody > tr:first-child > td:first-child > div"));
var button = table.FindElement(By.CssSelector(":scope > tbody > tr > td > button.btnDefault"));
请注意,使用像“直接子对象”这样的强依赖性通常会导致脆弱的选择器,这将增加测试维护成本。我不确定这是如何解决我的问题的,除了可能是一个轻微的清晰度改进。(可能不是因为有不止一个这样的按钮,我正在测试一个多步骤工作流,其中包括一个AJAX弹出窗口,也是多步骤的。)这只是解决了语法问题,但不能保证匹配的
tbody
将是表的直接后代。也就是说,我没有意识到这是毫无意义的,因为findelelement
无论如何都应该抓取第一个找到的元素,当从表中搜索时,
将是它对应的tbody
。啊,我看到了问题。我摆弄着缓存“table#tbl>tbody”,对“div”稍作修改就可以了,但这并没有让我在“button”上走得更远。这无助于改变性能,但为了减少重复,您可以在页面上创建一个方法来与这些元素进行交互(假设您使用的是页面对象模型),这似乎相当于查询表tbody tr td
,因此,比我已经拥有的更不具体。这是我一直在寻找的,谢谢!不幸的是,代码库是一个遗留的怪物,我将接受带有误报的脆弱测试,而不是完全没有。