In a Visual Studio 2013 WebTest, I am using the "Selected Option" extraction rule to extract the value of a DropDown into a Context Parameter. It works fine as long as a selected option exists. If a selected option does not exist (which in my test is perfectly acceptable) the test throws an exception, "The select tag 'SuchAndSuch' was not found."
The error message is misleading. When I look at the Response I see that the select tag "SuchAndSuch" does indeed exist, it just does not have a selected option. That is to say, this Html tag exists:
<select name="SuchAndSuch">
But it does not have a child tag like this:
<option selected="selected">
I also tried using "Extract Attribute Value" Extraction Rule to extract the selected item in a dropdown, since this latter rule has a "Required" property.
The rule is to look for the first instance of the tag "option" that has the attribute "selected=selected," and then extract the value of the "value" attribute. I have "Required" false because this drop-down will not always have a selected item.
The properties of my Extract Attribute Value rule are as follows:
<RuleParameters>
<RuleParameter Name="TagName" Value="option" />
<RuleParameter Name="AttributeName" Value="value" />
<RuleParameter Name="MatchAttributeName" Value="selected" />
<RuleParameter Name="MatchAttributeValue" Value="selected" />
<RuleParameter Name="HtmlDecode" Value="True" />
<RuleParameter Name="Required" Value="False" />
<RuleParameter Name="Index" Value="0" />
</RuleParameters>
This works fine as long as the drop-down has a selected item. When it does not the WebTest throws the WebTestException
Context Parameter 'SuchAndSuch' not found in test context
and the Request does not execute.
My desired behavior is when this particular drop-down lacks a selected item I want that particular Request to continue to execute and I want the test to NOT log a WebTestException. Is that possible?
The answer in this case is to write a custom extraction rule: https://msdn.microsoft.com/en-us/library/ms243179(v=vs.120).aspx
The rule I created for my own use is below, it is based on code I stole from here: https://social.msdn.microsoft.com/Forums/en-US/df4f2a0b-2fc4-4d27-9380-ac80100ca0b7/need-help-with-complex-extraction-rule?forum=vstswebtest
I first created the rule in the same project as the webtest. When I ran the webtest it immediately errored out with a "FileNotFound" exception when it tried to load the extraction rule. I moved the extraction rule to a separate project and referenced it from the web test project and it solved that problem.
[DisplayName("Extract Single-Select Dropdown")]
[Description("Extracts the attribute value of AttributeName from the selected option if selected option exists.")]
public class ExtractSingleSelectDropdown : ExtractionRule
{
[Description("The 'name' attribute of the rendered 'select' tag.")]
public string DropdownName { get; set; }
[Description("The name of the attribute of the rendered 'option' tag that contains the value that is extracted to the Context Parameter.")]
public string OptionAttributeName { get; set; }
[Description("When true, sets Success 'false' if a selected option is not found.")]
public bool Required { get; set; }
public override void Extract(object sender, ExtractionEventArgs e)
{
if (e.Response.HtmlDocument != null)
{
var tags = e.Response.HtmlDocument.GetFilteredHtmlTags(new string[] { "select", "option" });
if (tags != null && tags.Count() > 0)
{
//find the first <select><option selected="selected"> tag
var selectedOption = tags.SkipWhile(tag => String.IsNullOrWhiteSpace(tag.GetAttributeValueAsString("name")) || !tag.GetAttributeValueAsString("name").Equals(this.DropdownName, StringComparison.InvariantCultureIgnoreCase)) // skip tags that aren't the select tag we're looking for
.Skip(1) // skip the <select> tag
.TakeWhile(tag => tag.Name.Equals("option"))
.Where(tag => String.IsNullOrWhiteSpace(tag.GetAttributeValueAsString("selected"))) //
.FirstOrDefault();
if (selectedOption == null)
{
e.Message = string.Format("Zero selected options in Dropdown {0}", DropdownName);
e.WebTest.Context[ContextParameterName] = string.Empty;
e.Success = (this.Required ? false : true);
}
else
{
e.WebTest.Context[ContextParameterName] = selectedOption.GetAttributeValueAsString(OptionAttributeName);
e.Success = true;
}
}
}
}
}