With jQuery making its mark prominent in the recent times and unit tests based on it coming in demand day by day, it was only a matter of time that a requirement like this would crop up. During a project of mine, I had to combine the effectiveness of qUnit tests in checking controls on the client side, and the ASP Wjimo jQuery controls, and test scenarios in Test Case Manager. (In case you haven’t heard of it, which is highly improbable, here are more details.) So, in order to achieve the ideal scenario of selecting a test case in TCM and executing automated tests, there was only one option in front of me; to devise a means to run qUnit scripts from within CodedUI tests. Test Case Manager only recognizes the CodedUI tests as valid automation scripts for its test cases. Once I could call qUnit test scripts from within them, I could effectively use one CodedUI script, for say a batch of similar qUnit tests and run them as one scenario. This approach, easier as it sounds, wasn't that transparent upon implementation. Here is how I went about establishing the framework:

  1. Create single CodedUI Script. Do not record any UIActions using the CodedUI test builder.
  2. Invoke the test html page from within CodedUI tests so that the qUnit scripts are executed.
  3. Now comes the tricky part wherein we need to use CodedUI assertions in order to check failures in the qUnit tests. We scratched our heads and tried searching over the net for this one as well, and then it struck us !! The solution to the whole idea was a simple search. We implemented a search on the invoked html page’s DOM, in order to look for “Failed” classes, and wherever we found one, we saved its inner text onto a separate string.
  4. This string was then displayed with the rest of the assertion text.

There were a few simple CodedUI best practices that we also kept in mind, like putting ample wait time before actions, and making sure all UI threads pending are executed before any new thread is started. The following is the method to implement the above technique:

//set delays between actions so that each and every action is independent of previous ones  
Playback.PlaybackSettings.DelayBetweenActions = 500;  
Playback.PlaybackSettings.WaitForReadyLevel = WaitForReadyLevel.AllThreads;  
Playback.PlaybackSettings.WaitForReadyTimeout = 500;  

//open the existing html file in a browser window  
BrowserWindow.CurrentBrowser = "IE";  
string filename=Path.GetFullPath(<name of the html file to be opened>);  
if(!File.Exists(filename))  
    Assert.Fail(filename+" - Test file for launching qUnit test does not exist");  
BrowserWindow bw = BrowserWindow.Launch(filename);

Once this file is opened, it ought to run all the qUnit tests by itself, as is the implementation of qUnit tests. Once all the tests are run, they provide the results right there on the same HTML page. The following code would go through that page in a jiffy and sniff out all the locations where the failed class exists.

HtmlCustom passedscripts = new HtmlCustom(doc);  
passedscripts.SearchProperties["TagName"] = "LI";  
passedscripts.FilterProperties["Class"] = "pass";  

msg += passedscripts.FindMatchingControls().Where(p1 => !p1.FriendlyName.StartsWith("wij")).ToList().Count.ToString()  
+ " assertions passed." + linebreak;  
List<UITestControl> errors = failedscripts.FindMatchingControls().Where(p1 => !p1.FriendlyName.StartsWith("wij")).ToList();  
if (errors.Count == 0)  
  Assert.IsTrue(true);  
else  
 {  
     msg += errors.Count + " assertions failed " + Environment.NewLine;  
     foreach (UITestControl c in errors)  
     {  
        msg += (c as HtmlCustom).InnerText + linebreak;  
     }  
     Assert.Fail(msg);  
 }

Once the above script runs to completion and in case any qUnit tests fail, they would show up in the Test Run Details for the CodedUI tests. This not only gave me the leverage to put all my tests in one location, but I can now automate using powerful client side scripting and use it with a test suite meant for only running .NET based tests. **FindMatchingControls() method and the HTMLCustom object is created from custom class, built separately. This class calls on the native MS objects so that looking through the dom is alot easier.