Background
We’re in the initial stages of a new project here at iMeta that looks likely to have a large proportion of logic in the client browser rather than the web server. JQuery is the ideal tool for the job here and it just so happens that I’m a huge fan of it too!
Before the project gets properly underway I want to experiment with unit testing JQuery. My ultimate aim being to develop a pattern for including JQuery unit tests in CI builds – with this achieved I can add real value to the project going forward.
After a bit of research I came across the following great blog post, it’s a worth a read as a primer for the remainder of my post - http://www.lostechies.com/blogs/joshuaflanagan/archive/2008/09/18/running-jquery-qunit-tests-under-continuous-integration.aspx.
Joshua wrote his post in 2008, as a result WatiN’s codebase has since moved on. I also wanted to use MSTest rather than NUnit, purely because we will be running our builds on a Team Foundation Build server. This meant that I needed to find a replacement for NUnit’s IterativeTest add-in (or the more up to date TestCaseSource attribute) in MSTest. Another bit of research unearthed http://codeclimber.net.nz/archive/2008/01/18/How-to-simulate-RowTest-with-MS-Test.aspx – perfect!
Code
Pulling all this research together gave a nice end result, which I hope will benefit others. You will probably notice that my JavaScriptTester class is much simpler – this is firstly because of advances in the WatiN codebase for finding page elements and secondly because I only check and report pass/failure for whole QUnit tests rather than for each individual assertion within that test. You could easily extend the below to report on individual QUnit assertions should your scenario require it.
JavaScriptTester.cs
- namespace QunitJack.Tests
- {
- [TestClass]
- public class JavaScriptTester
- {
- private IE _ie;
-
- [TestInitialize]
- public void TestInitialize()
- {
- _ie = new IE();
- _ie.ShowWindow(NativeMethods.WindowShowStyle.Hide);
- }
-
- public TestContext TestContext { get; set; }
-
- [DeploymentItem("QunitJack.Tests\\JavaScriptTester.xml"), TestMethod]
- [DataSource("Microsoft.VisualStudio.TestTools.DataSource.XML", "|DataDirectory|\\JavaScriptTester.xml", "Row", DataAccessMethod.Sequential)]
- public void RunQUnitTests()
- {
- _ie.GoTo(string.Format("http://localhost:90/{0}", TestContext.DataRow["Filename"]));
- _ie.WaitForComplete(5);
-
- AssertQUnitTestResults();
- }
-
- private void AssertQUnitTestResults()
- {
- var liElements = _ie.ElementsWithTag("li").Filter(x => x.Parent.Id == "qunit-tests");
- foreach(var liElement in liElements)
- {
- Assert.IsTrue(liElement.ClassName == "pass", liElement.DomContainer.ElementsWithTag("strong")[0].Text);
- }
- }
- }
- }
JavaScriptTester.xml
- <?xml version="1.0" encoding="utf-8" ?>
- <Rows>
- <Row>
- <Filename>Test1.htm</Filename>
- </Row>
- <Row>
- <Filename>Test2.htm</Filename>
- </Row>
- </Rows>
There are a couple of great QUnit blog posts over at http://indomitablehef.com/?cat=35, I have made use of the static Assert methods and dynamically setting up/tearing down the DOM.
Test1.htm
- <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
- <html>
- <head>
- <link rel="stylesheet" href="http://github.com/jquery/qunit/raw/master/qunit/qunit.css" type="text/css" />
- <script type="text/javascript" src="Scripts/jquery-1.4.1.js"></script>
- <script type="text/javascript" src="http://github.com/jquery/qunit/raw/master/qunit/qunit.js"></script>
- <script type="text/javascript" src="Scripts/Assert.js"></script>
- <script type="text/javascript" src="Scripts/DOMSetup.js"></script>
- <script type="text/javascript" src="Scripts/DOMTearDown.js"></script>
-
- <script type="text/javascript">
- $(document).ready(function() {
-
- test("renderJsonGridTests", function() {
-
- DOMSetup('<div id="target" />');
-
- var json = jQuery.parseJSON('{ "tableId" : "foo" }')
- $("div#target").html('<table id = "' + json.tableId + '"></table>');
-
- Assert.AreEqual(true, $("#target > table").length == 1, "table exists");
- Assert.AreEqual("foo", $("#target > table").attr("id"), "table has correct id");
-
- DOMTearDown("div#target");
-
- });
-
- });
- </script>
-
- </head>
- <body>
- <h1 id="qunit-header">
- QUnit example</h1>
- <h2 id="qunit-banner">
- </h2>
- <h2 id="qunit-userAgent">
- </h2>
- <ol id="qunit-tests">
- </ol>
- </body>
- </html>
Summary
I’m sure that the above approach to our JQuery CI will evolve as the project does – but as an initial pattern I think it will do the job. Any refinements that I make will be added to this post somehow.