如何使用编码UI测试按自定义HTML属性搜索元素
本文关键字:HTML 属性 搜索 元素 自定义 何使用 编码 UI 测试 | 更新日期: 2023-09-27 18:05:49
我在GridView中有一堆input[type=submit]
按钮。这些按钮的id
s和name
s虽然可以预测,因为它们使用索引号,但不太适合使用SpecFlow和Coded UI测试进行自动化。我发现很难搜索这些按钮元素。
传递给浏览器的HTML片段:
<input type="submit" id="abc_xyz_0" data-task-id="123" value="Apply">
<input type="submit" id="qrs_tuv_0" data-task-id="345" value="Renew">
按钮文本在每行("Apply"answers"Renew")中是通用的,但是data-task-id
属性是唯一的。我想使用此属性和值来标识要单击的按钮。我试图使用SearchProperties
和FilterProperties
,但我不断得到异常:
系统。NotSupportedException:此控件不支持属性DataTaskId。
我如何尝试找到控件:
HtmlInputButton button = new HtmlInputButton(document);
button.SearchProperties["data-task-id"] = "123";
// or button.SearchProperties["DataTaskId"] = "123";
一些附加细节:
- Windows 7
- Internet Explorer 11
-
localhost
提供的网站,在Internet选项安全设置 中标记为"可信"
更新:感谢marcel de vries和AfroMogli的回答。Marcel使用JavaScript来查找元素,而AfroMogli使用纯c#和CodedUI API。两种答案都同样有效,我没有注意到两者之间的性能差异。两个同样好的解决方案
您可以通过使用ControlDefinition作为属性名进行搜索来完成此操作。下面这行代码为我解决了这个问题:
HtmlInputButton button = new HtmlInputButton(document);
button.SearchProperties.Add(new PropertyExpression(HtmlControl.PropertyNames.ControlDefinition, "data-task-id='"123'"", PropertyExpressionOperator.Contains));
允许传入任何属性名称和值的示例方法:
public HtmlInputButton InputButton(string attributeName, string attributeValue, UITestControl container = null)
{
string controlDefinition = string.Format("{0}='"{1}'"", attributeName, attributeValue);
HtmlInputButton button = new HtmlInputButton(container ?? document);
button.SearchProperties.Add(new PropertyExpression(HtmlControl.PropertyNames.ControlDefinition, controlDefinition, PropertyExpressionOperator.Contains));
return button;
}
编辑:
或者如果属性名没有改变,执行以下操作?
public PropertyExpression GetByTaskId(string value)
{
return new PropertyExpression(
HtmlControl.PropertyNames.ControlDefinition,
$"data-task-id='"{value}'"",
PropertyExpressionOperator.Contains
);
}
HtmlInputButton button = new HtmlInputButton(document);
button.SearchProperties.Add(GetByTaskId("123"));
最简单的方法是使用一个简单的javascript执行来根据您提供的任何属性名和值获得控件。像这样:
const string javascript = "return document.querySelector('{0}');";
var bw = BrowserWindow.Launch("your page");
string selector = "[data-task-id]='123']";
var control = bw.ExecuteScript(string.Format(javascript,selector));`
变量控件现在包含您正在查找的控件,并且具有正确的类型。因此,如果它是HtmlHyperLink,你可以这样使用它。
关于如何在Angular站点中使用它,我有一个更长的故事:http://fluentbytes.com/testing-angular-sites-with-codedui/因为Angular甚至使用自定义属性,如ng-*我编写了这些实用程序方法来测试JavaScript和其他答案中解释的直接解决方案。
我发现,虽然ControlDefinition
属性最初没有使用Visual Studio Marketplace (v1.7)上可用的开箱即装的Selenium跨浏览器组件跨浏览器工作,但在升级chromedriver.exe
(到v2.41)后,一切都开始按预期工作。
请注意,升级的chromedriver.exe
必须"解锁"才能工作。我使用PowerShell的Unblock-File
命令来做到这一点,注意必须使用Run as Administrator
启动才能成功。
实用方法:
public PropertyExpression GetByCustomAttribute(string attributeName, string value)
{
return new PropertyExpression(HtmlControl.PropertyNames.ControlDefinition,
$"{attributeName}='"{value}'"",
PropertyExpressionOperator.Contains);
}
public static T GetControlByCustomAttribute<T>(this BrowserWindow browserWindow,
string attributeName,
string value,
HtmlControl context = null)
where T : HtmlControl
{
string queryContext = (context != null ? "arguments[0]" : "document");
string script = $"return {queryContext}.querySelector('"[{attributeName}=''{value}'']'");";
return browserWindow.ExecuteScript(script, context) as T;
}
用法:
BrowserWindow.CurrentBrowser = "chrome";
var browser = BrowserWindow.Launch(new Uri("index.html"));
// first find parent of item with custom data attribute
var div = new HtmlControl(browser);
div.SearchProperties.Add(HtmlControl.PropertyNames.Id, "myDiv");
// Either using ControlDefinition solution:
HtmlEdit edit1 = new HtmlEdit(div);
edit1.SearchProperties.Add(GetByItemId("4711"));
// Or using JavaScript solution:
HtmlEdit edit2 = browser.GetControlByItemId<HtmlEdit>("4711", div);
// use control...
edit1.Text = "text";
edit2.Text = "text";