高效操作 WebDriver 元素





5.00/5 (2投票s)
本技巧总结了如何高效地使用 WebDriver 读取/写入网页元素。
引言
最近,我使用 WebDriver 对一个单页应用程序进行了一些自动化测试,并开发了自己的框架以避免重复代码。 即使尝试将字符串输入到 AJAX 自动建议文本输入框、从使用 'optiongrp
' 的下拉列表中选择一个选项,或访问表格中的单元格,都具有相当大的挑战性。
作为我过去工作的总结,也是展示我的框架的第一步,我想介绍一些常见 HTML 元素的基本操作。
向文本框输入文本
当大家都知道 "SendKey(string text)
" 应该有效时,这可能看起来过于简单。 然而,在大多数情况下,如果文本框 (input
, textArea
) 未清除,SendKey
会将文本附加到现有文本上。
因此,常用的做法是在调用 SendKey()
之前先清除它。
IWebElement element = theWebDriver.findElement(By.Id("textId"));
...
element.Clear();
element.SendKey("text to be input");
另一种选择是,首先使用 "Ctrl+A" 选择现有的文本,然后再进行实际输入。
public static readonly string Control = Convert.ToString
(Convert.ToChar(0xE009, CultureInfo.InvariantCulture), CultureInfo.InvariantCulture);
public static readonly string Tab = Convert.ToString(Convert.ToChar
(0xE004, CultureInfo.InvariantCulture), CultureInfo.InvariantCulture);
public static readonly string Control_a = Control + "a";
IWebElement element = theWebDriver.findElement(By.Id("textId"));
...
element.SendKey(Control_a);
element.SendKey("text to be input");
然而,这对于由 Angular 等技术支持的自动完成文本框来说是不够的,当我执行以下操作时,会弹出一个警告对话框。 再次考虑在这种情况下的人工操作,可以通过向该字段发送一个 TAB 键来解决问题。 因此,对我来说,首选方法是
public static readonly string Tab = Convert.ToString
(Convert.ToChar(0xE004, CultureInfo.InvariantCulture), CultureInfo.InvariantCulture);
...
element.SendKey(Control_a);
?element.SendKey("text to be input" + Tab);
从下拉列表中选择一个选项
Selenium 建议从下拉列表中选择一个选项的方法是
SelectElement select = new SelectElement(driver.FindElement(By.TagName("select")));
select.DeselectAll();
select.SelectByText(Edam");
但是,当使用 "optiongrp
" 包含多个选项时,它不起作用。 一种简单的解决方法是像在浏览器中一样使用 SendKeys()
操作。
IWebElement element = theWebDriver.findElement(By.Id("selectId"));
...
element.SendKey("Edam" + Tab);
这样,我们只能通过文本选择选项,而不是通过其值,但这可以通过在调用 "SendKey()
" 之前匹配值来完成,并且对于大多数情况来说应该足够了。
访问表格
作为表格行/单元格的集合,访问表格的特定单元格比较麻烦,以下讨论仅限于行数相同的表格。
基本上,有 3 个步骤可以确定表格的结构
- 获取所有行(或标签名为 "
tr
" 的子元素); - 解析第一行,查看它是否包含标题(标签名为 "
th
" 的元素),并存储标题名称; - 保留实际的行号和列号,以便进行后续操作。
public int RowCount { get; private set; }
public int ColumnCount { get; private set; }
public List<string> Headers { get; private set; }
public bool WithHeaders { get; private set; }
ReadOnlyCollection<IWebElement> rows = driver.FindElements(By.CssSelector("tr"));
IWebElement firstRow = rows[0];
var headers = firstRow.FindElements(By.CssSelecor("th")).ToList();
RowCount = rows.Count();
if (headers.Count() != 0)
{
WithHeaders = true;
ColumnCount = headers.Count();
Headers = headers.Select(x => x.Text).ToList();
}
else
{
RowCount += 1;
WithHeaders = false;
Headers = null;
ColumnCount = rows.FirstOrDefault().FindElements(By.CssSelector("td")).Count();
}
然后,可以有多种方法来访问所需的单元格/行,如下面的示例所示。
- 通过
rowIndex
和columnIndex
访问单元格IWebElement table = driver.FindElement(By.Id("table")); public IWebElement cellOf(int rowIndex, int columnIndex) { if (columnIndex < 0 || columnIndex >= ColumnCount) throw new Exception("Column Index ranges from 0 to " + (ColumnCount-1)); if (rowIndex < 0 || rowIndex >= RowCount) throw new Exception("Row Index ranges from 0 to " + (RowCount-1)); if (rowIndex == 0 && !WithHeaders) throw new Exception("No headers (rowIndex=0) defined for this table."); String css = string.Format("tr:nth-of-type({0}) {1}:nth-of-type({2})", rowIndex + 1, rowIndex == 0 ? "th" : "td", columnIndex); return table.FindElement(By.CssSelector(css)); }
- 通过
rowIndex
和标题名称访问单元格IWebElement table = driver.FindElement(By.Id("table")); public IWebElement cellOf(int rowIndex, string headername) { int columnIndex = Headers.FindIndex(s => s.Contains(headerKeyword)); return this[rowIndex, columnIndex]; }
- 更具体地说,返回包含特定值在标题下的行
IWebElement table = driver.FindElement(By.Id("table")); public IWebElement rowOf(string headerKeyword, Func<string, bool> predicate) { int columnIndex = Headers.FindIndex(s => s.Contains(headerKeyword)); var allRows = table.FindElements(By.CssSelector("tr")); if (WithHeader) allRows.Skip(1); foreach( var row in allRows) { var td = row.FindElement(By.CssSelector(string.Format("td:nth-of-type({0})", columnIndex + 1))); if (predicate(td.Text)) return row; } return null; }
看点
在本技巧中,我们讨论了一些非常详细的程序,用于操作一些正在工作但未记录的常见 HTML 元素。