In a previous post I wrote about a new feature that was added for VS 2010 called extensible recorder plug-ins.  Here is that post: Recorder Plug-ins Basically recorder plug-ins give you the opportunity to modify a recorded web test prior to the test being saved back to the web test editor.  So if you always have to manually do a set of steps prior to being able to run a web test, you could create a recorder plug-in which will do those steps for you.  In my previous post I showed you how to create a plug-in which will correlate dynamic parameters.  I added a extraction rule to one of the requests in the recorded test and then bound the extracted value to a query string parameter further down the web test. 

In this post I am going to give you another example of what you can do with recorder plug-ins.  In this post we are going to add validation rules to the web test.  We will add a validation rule that will validate the value of the Title tag matches the value at record time.  Follow these steps.

  1. Create a new class library project
  2. Right Click references node and select “Add reference…”
  3. Click the .NET tab and add the Microsoft.Visual Studio.QualityTools.WebTestFramework assembly
  4. Copy the code below and add it to your class file 
    using System.ComponentModel;
    using Microsoft.VisualStudio.TestTools.WebTesting;
    using Microsoft.VisualStudio.TestTools.WebTesting.Rules;
    
    namespace SampleRecorderPlugin
    {
        [DisplayName("WebTestRecorderPlugin that adds title validation rule")]
        [Description("Adds a validation rule that verifies the recorded title tag matches playback title tag value")]
        public class RecorderPluginThatAddsTitleValidation : WebTestRecorderPlugin
        {
            public override void PostWebTestRecording(object sender, PostWebTestRecordingEventArgs e)
            {
                WebTestResultIteration recordedIteration = e.RecordedWebTestResult;
                foreach (WebTestResultUnit resultUnit in recordedIteration.Children)
                {
                    WebTestResultPage pageResult = resultUnit as WebTestResultPage;
                    if (pageResult != null)
                    {
                        WebTestRequestResult finalRequestResult = pageResult.RequestResult;
    
                        //if there were redirects then need to get the last redirected requests
                        if (pageResult.RedirectedPages.Count > 0)
                        {
                            finalRequestResult = 
    pageResult.RedirectedPages[pageResult.RedirectedPages.Count - 1].RequestResult; } //now get the response for the final request WebTestResponse response = finalRequestResult.Response; if (response.IsHtml) { HtmlTagInnerTextParser innerTextParser = new HtmlTagInnerTextParser(response.BodyString); HtmlTagInnerText titleInnerTextTag = null; //search for the <Title> tag foreach (HtmlTagInnerText innerTextTag in innerTextParser.GetInnerTextForHtmlTags("title", true, false, false)) { if (!string.IsNullOrEmpty(innerTextTag.Value)) { titleInnerTextTag = innerTextTag; break; } } if (titleInnerTextTag == null) { continue; } //if we found a title tag then add a validation rule ValidationRuleReference validateTitleRuleReference = new ValidationRuleReference(); validateTitleRuleReference.Type = typeof(ValidateHtmlTagInnerText); validateTitleRuleReference.ValidationLevel = ValidationLevel.Medium; validateTitleRuleReference.Properties.Add(new PluginOrRuleProperty("TagName", "title")); validateTitleRuleReference.Properties.Add(new PluginOrRuleProperty("ExpectedInnerText", titleInnerTextTag.Value)); validateTitleRuleReference.Properties.Add(new PluginOrRuleProperty("Index", "0")); validateTitleRuleReference.Properties.Add(new PluginOrRuleProperty("RemoveInnerTags", "False")); validateTitleRuleReference.Properties.Add(new PluginOrRuleProperty("HasClosingTags", "True")); validateTitleRuleReference.Properties.Add(new PluginOrRuleProperty("IgnoreCase", "True")); validateTitleRuleReference.Properties.Add(new PluginOrRuleProperty("CollapseWhiteSpace",
    "False")); // Get the corresponding request in the Declarative Web test WebTestRequest requestInWebTest = e.RecordedWebTest.GetItem(pageResult.DeclarativeWebTestItemId) as WebTestRequest; if (requestInWebTest != null) { requestInWebTest.ValidationRuleReferences.Add(validateTitleRuleReference); e.RecordedWebTestModified = true; } } } } } } }
  5. Copy the dll to \Program Files\Microsoft Visual Studio 10.0\Common7\IDE\PrivateAssemblies\WebTestPlugins

  6. Restart VS and go to your test project.

  7. Add a new Web Performance Test. You will see the following dialog:

  8. Select the plug-in we just created and record your web test

  9. When test completes, expand the requests nodes and look for the validation rules. You should see the following:

  10. I had a validation rule added for each of my requests.

 

Let’s walk through parts of the code. Here is the first part of the method. In this code fragment we are looping through all the recorded items and looking for pages. You can also add comments during playback which is why the code is checking for page results.

            WebTestResultIteration recordedIteration = e.RecordedWebTestResult;
            foreach (WebTestResultUnit resultUnit in recordedIteration.Children)
            {
                WebTestResultPage pageResult = resultUnit as WebTestResultPage;
                if (pageResult != null)
                {
 

Once we have the page result, we are checking to see if the page was part of a redirect.  If so, we are grabbing the last request in the redirect chain: 

                    WebTestRequestResult finalRequestResult = pageResult.RequestResult;

                    //if there were redirects then need to get the last redirected requests
                    if (pageResult.RedirectedPages.Count > 0)
                    {
                        finalRequestResult = pageResult.RedirectedPages[pageResult.RedirectedPages.Count - 1].RequestResult;
                    }

 

 

Next we are going to grab the response and run it through the tag parser.  Once we have the tag collection it is going to iterate over that collection looking for the Title tag: 

                   //now get the response for the final request
                    WebTestResponse response = finalRequestResult.Response;
                    if (response.IsHtml)
                    {
                        HtmlTagInnerTextParser innerTextParser = new HtmlTagInnerTextParser(response.BodyString);
                        HtmlTagInnerText titleInnerTextTag = null;

                        //search for the <Title> tag
                        foreach (HtmlTagInnerText innerTextTag in 
                                 innerTextParser.GetInnerTextForHtmlTags("title", true, false, false))
                        {
                            if (!string.IsNullOrEmpty(innerTextTag.Value))
                            {
                                titleInnerTextTag = innerTextTag;
                                break;
                            }
                        }

If we find a title tag it will break out of the loop and add a validation rule.  First we create the reference: 

                        //if we found a title tag then add a validation rule
                        ValidationRuleReference validateTitleRuleReference = new ValidationRuleReference();
                        validateTitleRuleReference.Type = typeof(ValidateHtmlTagInnerText);
                        validateTitleRuleReference.ValidationLevel = ValidationLevel.Medium;
                        validateTitleRuleReference.Properties.Add(new PluginOrRuleProperty("TagName", "title"));
                        validateTitleRuleReference.Properties.Add(new PluginOrRuleProperty("ExpectedInnerText", 
                                                                                           titleInnerTextTag.Value));
                        validateTitleRuleReference.Properties.Add(new PluginOrRuleProperty("Index", "0"));
                        validateTitleRuleReference.Properties.Add(new PluginOrRuleProperty("RemoveInnerTags", "False"));
                        validateTitleRuleReference.Properties.Add(new PluginOrRuleProperty("HasClosingTags", "True"));
                        validateTitleRuleReference.Properties.Add(new PluginOrRuleProperty("IgnoreCase", "True"));
                        validateTitleRuleReference.Properties.Add(new PluginOrRuleProperty("CollapseWhiteSpace", "False"));

 

Then we find the request in the web test that corresponds to this result page and add the reference to the validation rule collection: 

                       // Get the corresponding request in the Declarative Web test
                        WebTestRequest requestInWebTest = 
                                e.RecordedWebTest.GetItem(pageResult.DeclarativeWebTestItemId) as WebTestRequest;
                        if (requestInWebTest != null)
                        {
                            requestInWebTest.ValidationRuleReferences.Add(validateTitleRuleReference);
                            e.RecordedWebTestModified = true;
                        }

Hopefully this shows you another use for recorder plug-ins. Try it out and let us know what you think.