I have a bunch of input[type=submit]
buttons inside a GridView. The id
s and name
s of these buttons, while predictable because they use an index number, are not well suited to automation using SpecFlow and Coded UI Tests. I'm finding it difficult to search for those button elements.
A snippet of the HTML delivered to the browser:
<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">
The button text is generic in each row ("Apply" and "Renew"), but the data-task-id
attribute is unique. I would like to use this attribute and value to identify a button to click on. I'm trying to use the SearchProperties
and FilterProperties
but I keep getting exceptions:
System.NotSupportedException: The property DataTaskId is not supported for this control.
How I'm attempting to find the control:
HtmlInputButton button = new HtmlInputButton(document);
button.SearchProperties["data-task-id"] = "123";
// or button.SearchProperties["DataTaskId"] = "123";
Some additional details:
localhost
and is marked "trusted" in the Internet Options Security SettingsUpdate: Thanks to both marcel de vries and AfroMogli for their answers. Marcel's uses JavaScript to find the element, and AfroMogli's uses pure C# and the CodedUI API. Both answers worked equally well, and I didn't notice a performance difference between either one. Two equally good solutions.
You can accomplish this by searching with the ControlDefinition as propertyname. The following line of code did the trick for me:
HtmlInputButton button = new HtmlInputButton(document);
button.SearchProperties.Add(new PropertyExpression(HtmlControl.PropertyNames.ControlDefinition, "data-task-id=\"123\"", PropertyExpressionOperator.Contains));
Example method allowing you to pass in any attribute name and value:
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;
}
EDIT:
Or if the attribute name doesn't change, do the following?
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"));
The simplest way of doing this is by using a simple javascript execute to get the control based on any attribute name and value you provide. something like this:
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));`
The variable control now contains the control you are looking for and is of the correct type. So if it is e.g. and HtmlHyperLink you can use it as such right a way.
I have a longer story about how to use this in Angular sites here: http://fluentbytes.com/testing-angular-sites-with-codedui/ since angular uses even custom attributes like ng-*
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With