BDD-Style QUnit Testing ASP.NET MVC’s jQuery Validation

Client-Side Unit Testing


<div></div>
The goal of this blog post is to show how you can utilize some helpful techniques to easily Unit Test your Web Application. In this post I will focus on Unit Testing the Client-Side validation rules that ASP.NET MVC generates. You can apply the following techniques to pretty much any scenario, but since this is something I do, I thought I’d share.

Our sample applications is a Contact Manager. At this point we only have a toolbar with a “New Contact” button. When the button is clicked a “New Contact” dialog will appear with several input fields and a “Save” and “Cancel” button. All of the fields are required, so if the user clicks the “Save” button client-validation should verify that all fields have a value.

<h4>ASP.NET MVC Contact ViewModel</h4>
First lets take a look at our ViewModel which will drive the rules of our client-side validation.

<pre>using System;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;

namespace jQueryUnitTestingFormValidation.Models
{
public class ContactViewModel
{
[HiddenInput(DisplayValue = false)]
public System.Guid Id { get; set; }

[Required(ErrorMessage = “Name Required”)]
[DisplayName(“Name”)]
[StringLength(50, ErrorMessage = “Name must be less than or equal to 50 characters”)]
public string Name { get; set; }

[Required(ErrorMessage = “Email Required”)]
[DisplayName(“E-mail”)]
[StringLength(50, ErrorMessage = “Email must be less than or equal to 50 characters”)]
[DataType(DataType.EmailAddress)]
[RegularExpression(@”^([a-z0-9!#$%&’+/=?^_{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_{|}~-]+)@(?:a-z0-9?.)+a-z0-9?\s;?\s)+$”, ErrorMessage = “Email must be valid”)]
public string Email { get; set; }

[Required(ErrorMessage = “Phone Number Required”)]
[DisplayName(“Phone Number”)]
[StringLength(50, ErrorMessage = “Phone must be less than or equal to 50 characters”)]
public string PhoneNumber { get; set; }

[Required(ErrorMessage = “Date of Birth Required”)]
[DisplayName(“Date of Birth”)]
public DateTime? DateOfBirth { get; set; }

[Required(ErrorMessage = “Required”)]
[DisplayName(“Is Married”)]
public bool IsMarried { get; set; }
}
}</pre>
<h4>ASP.NET MVC Contact View</h4>
Our View is pretty simple. I decided for this sample to not modify the MasterPages that the Templated Helpers use. You’ll see that I’m call the LabelFor, EditorFor, and ValidationMessageFor and organizing them as I wish. If you are interested in a cleaner way to do this you can check out a previous blog entry I wrote entitled Opinionated ASP.NET MVC 2 Template Helpers.

<pre><div id="createDialog" title="New Contact" style="display: none;">
<% Html.EnableClientValidation(); %>
<% using (Html.BeginForm(“Create”, “Contact”, FormMethod.Post, new {@id = “createPost”})) { %>
<dl>
<dt><%= Html.LabelFor(m => m.Name) %></dt>
<dd>
<%= Html.EditorFor(m => m.Name) %>
<%= Html.ValidationMessageFor(m => m.Name) %>
</dd>
<dt><%= Html.LabelFor(m => m.Email) %></dt>
<dd>
<%= Html.EditorFor(m => m.Email) %>
<%= Html.ValidationMessageFor(m => m.Email)%>
</dd>
<dt><%= Html.LabelFor(m => m.PhoneNumber) %></dt>
<dd>
<%= Html.EditorFor(m => m.PhoneNumber) %>
<%= Html.ValidationMessageFor(m => m.PhoneNumber)%>
</dd>
<dt><%= Html.LabelFor(m => m.DateOfBirth) %></dt>
<dd>
<%= Html.EditorFor(m => m.DateOfBirth) %>
<%= Html.ValidationMessageFor(m => m.DateOfBirth)%>
</dd>
<dt><%= Html.LabelFor(m => m.IsMarried) %></dt>
<dd>
<%= Html.EditorFor(m => m.IsMarried) %>
<%= Html.ValidationMessageFor(m => m.IsMarried)%>
</dd>
</dl>
<% } %>
</div></pre>
<h4>JavaScript Contact Revealing Module</h4>
The Contact Revealing Module contains the logic to initialize the button and dialog events, post the form to the Controller, etc…

Note: I am utilizing the Revealing Module Pattern for those of you who might not be aware of it. It is very helpful in splitting up your JavaScript code into testable and reusable modules.

<pre>var contactCreateModule = (function () {
var public = {},
dialogWidth = 800;

public.createDialog;
public.createPost;

public.init = function () {
public.createDialog = $(“#createDialog”);
public.createPost = $(“#createPost”);

public.initEventHandlers();
};

public.initEventHandlers = function () {
public.initToolbar();

public.initDialog();
};

public.initToolbar = function () {
$(“#toolbar button”).button();

$(“#createContact”).click(function () {
public.displayCreate();
});
};

public.initDialog = function () {
$(“.datePicker”).datepicker();

public.createDialog.dialog({
autoOpen: false
, width: dialogWidth
, modal: true
, open: validationModule.clearValidationMessages
, buttons: {
“Cancel”: function () {
public.createDialog.dialog(“close”);
},
“Save”: function () {
if (public.createPost.valid()) {
public.createDialog.dialog(“close”);
public.postContact();
}
}
}
});
};

public.displayCreate = function () {
public.createDialog
.dialog(“open”)
.find(“input:first”)
.focus();
};

public.postContact = function (callback) {
$.ajaxSettings.traditional = true;
$.ajax({
url: public.createPost.attr(“action”),
data: public.createPost.serialize(),
type: “POST”,
success: function (data, textStatus, xhr) {
public.postContactSuccess(data, textStatus, xhr);
callback(data && data.Success);
},
error: public.postContactError
});
};

public.postContactSuccess = function (data, textStatus, xhr) {
if (data && data.Success) {
notificationModule.displayMessage(true, “Your contact has been created!”);
} else {
notificationModule.displayMessages(data.Success, data.Messages);
}
};

public.postContactError = function (xhr, textStatus, error) {
var errorMessage = exception ? exception : xhr.statusText;
notificationModule.displayMessage(false, “There was an error creating your contact: “ + errorMessage);
};

return public;
} ());</pre>
<h4>Classic QUnit Style Tests</h4>
I initially started this blog post using standard QUnit syntax, but there was something about it that didn’t stand well with me. In particular, I didn’t like how I had a bunch of asserts all lumped together. Later in this article I switch out the classic QUnit-Style with a BDD-Style syntax.

The following are some screenshots from the Unit Tests…

<div></div>
The following is a slightly zoomed in view of the above image. You can see that all the asserts for one particular test are hidden beneath it. You can expand &| collapse the test to see each individual assert.

<div></div>
You can view the unit tests below that generated the above screen shots.
Since I don’t want the $.ajax call to actually occur in my Unit Tests, I swap out the default functionality with a stub function instead in the module setup (which is called before each test). In the module teardown (which is called after each test) I restore the default functionality in case any future test needs it.

<pre>var contactWasPosted = false;
module(“Contact: Create”, {
setup: function () {
contactWasPosted = false;

contactCreateModule.postContactBackup = contactCreateModule.postContact;
contactCreateModule.postContact = function (callback) {
contactWasPosted = true;
};
},
teardown: function () {
contactCreateModule.postContact = contactCreateModule.postContact;
contactCreateModule.createDialog.dialog(‘close’);
}
});

test(“When New Contact Button Clicked”, function () {
//Arrange

//Act
$(“#createContact”).click();

//Assert
ok($(“#createDialog:visible”).length, “Dialog Should Display”);
ok($(“#Name_validationMessage:not(:visible)”).length, “Name Validation Should Not Display”);
ok($(“#Email_validationMessage:not(:visible)”).length, “Email Validation Should Not Display”);
ok($(“#PhoneNumber_validationMessage:not(:visible)”).length, “PhoneNumber Validation Should Not Display”);
ok($(“#DateOfBirth_validationMessage:not(:visible)”).length, “DateOfBirth Validation Should Not Display”);
ok($(“#IsMarried_validationMessage:not(:visible)”).length, “IsMarried Validation Should Not Display”);
});

test(“When Click Save On an Empty Form”, function () {
//Arrange
$(“#createContact”).click();

//Act
$(“.ui-button-text:contains(‘Save’)”).parent().click();

//Assert
ok($(“#Name_validationMessage:visible”).length, “Name Validation Should Display”);
ok($(“#Email_validationMessage:visible”).length, “Email Validation Should Display”);
ok($(“#PhoneNumber_validationMessage:visible”).length, “PhoneNumber Validation Should Display”);
ok($(“#DateOfBirth_validationMessage:visible”).length, “DateOfBirth Validation Should Display”);
ok($(“#IsMarried_validationMessage:visible”).length, “IsMarried Validation Should Display”);
ok($(“#createDialog:visible”).length, “Dialog Should Remain Displayed”);
});

test(“When Click Save On an Complete Form”, function () {
//Arrange
$(“#createContact”).click();

$(“#Name”).val(“xNamex”);
$(“#Email”).val(“tasty@bacon.com”);
$(“#PhoneNumber”).val(“xPhoneNumberx”);
$(“#DateOfBirth”).val(“xDateOfBirthx”);
$(“#IsMarried”).attr(“checked”, true);

//Act
$(“.ui-button-text:contains(‘Save’)”).parent().click();

//Assert
ok($(“#Name_validationMessage:not(:visible)”).length, “Name Validation Should Not Display”);
ok($(“#Email_validationMessage:not(:visible)”).length, “Email Validation Should Not Display”);
ok($(“#PhoneNumber_validationMessage:not(:visible)”).length, “PhoneNumber Validation Should Not Display”);
ok($(“#DateOfBirth_validationMessage:not(:visible)”).length, “DateOfBirth Validation Should Not Display”);
ok($(“#IsMarried_validationMessage:not(:visible)”).length, “IsMarried Validation Should Not Display”);
ok(contactWasPosted, “Contact Should Post”);
ok($(“#createDialog:not(:visible)”).length, “Dialog Should Be Closed”);
});</pre>
<h4>BDD Style QUnit Tests </h4>
After talking more with Dan Mohl (@dmohl) I decided I wanted to try to find a Behavior Driven style of writing QUnit tests. I know there are several other BDD Client-Side Unit Test frameworks out there, but I wanted to keep to the QUnit runner for now.

So, during my research the author of Pavlov, Michael Monteleone (@namelessmike), let me know about his project, which ended up to be exactly what I was looking for.

The following is the output of my tests using QUnit and Pavlov…

<div></div>
Here is a slightly zoomed in view of the QUnit Pavlov test output…

<div></div>
The structure of the Unit Tests is dramatically different from the above classic Unit Tests.

The first thing you’ll notice is that I am extending the Assertion definitions to clean up some of the assert code that I had in my previous Unit Tests.

I still have the same logic in from the above Unit Tests that was in the setup and teardown methods, but now you can find those in the before and after methods.

The syntax of Pavlov is very readable from an English standpoint. You basically describe some scenario in words, and then split it out into code. It was very refreshing once I put it all together.

<pre>QUnit.specify.extendAssertions({
isNotDisplayed: function(actual, expected, message) {
ok(actual.is(“:hidden”) || actual.text().length == 0, message || “okay: isNotDisplayed”);
},
isDisplayed: function (actual, expected, message) {
ok(actual.is(“:visible”) || actual.text().length > 0, message || “okay: isDisplayed”);
}
});

QUnit.init({ moduleTestDelimeter: “, it “ });
QUnit.specify.globalApi = true;
QUnit.specify(“Contact”, function () {

describe(“Create”, function () {

var contactWasPosted;

before(function () {
contactWasPosted = false;

contactCreateModule.postContactBackup = contactCreateModule.postContact;
contactCreateModule.postContact = function (callback) {
contactWasPosted = true;
};

$(“#createContact”).click();
});

after(function () {
contactCreateModule.postContact = contactCreateModule.postContact;
contactCreateModule.createDialog.dialog(‘close’);
});

describe(“When the contact button is clicked”, function () {
it(“should display the dialog”, function () {
assert($(“#createDialog:visible”).length).isEqualTo(1);
});

it(“should not display name validation”, function () {
assert($(“#Name_validationMessage:visible”)).isNotDisplayed();
});

it(“should not display email validation”, function () {
assert($(“#Email_validationMessage:visible”)).isNotDisplayed();
});

it(“should not display PhoneNumber validation”, function () {
assert($(“#PhoneNumber_validationMessage:visible”)).isNotDisplayed();
});

it(“should not display DateOfBirth validation”, function () {
assert($(“#DateOfBirth_validationMessage:visible”)).isNotDisplayed();
});

it(“should not display IsMarried validation”, function () {
assert($(“#IsMarried_validationMessage:visible”)).isNotDisplayed();
});
});

describe(“When clicking save on an empty form”, function () {
before(function () {
$(“.ui-button-text:contains(‘Save’)”).parent().click();
});

it(“should keep the dialog displayed”, function () {
assert($(“#createDialog:visible”).length).isEqualTo(1);
});

it(“should display Name validation”, function () {
assert($(“#Name_validationMessage:visible”)).isDisplayed();
});

it(“should display Email validation”, function () {
assert($(“#Email_validationMessage:visible”)).isDisplayed();
});

it(“should display PhoneNumber validation”, function () {
assert($(“#PhoneNumber_validationMessage:visible”)).isDisplayed();
});

it(“should display DateOfBirth validation”, function () {
assert($(“#DateOfBirth_validationMessage:visible”)).isDisplayed();
});

it(“should display IsMarried validation”, function () {
assert($(“#IsMarried_validationMessage:visible”)).isDisplayed();
});
});

describe(“When clicking save on a completed form”, function () {
before(function () {
$(“#Name”).val(“xNamex”);
$(“#Email”).val(“tasty@bacon.com”);
$(“#PhoneNumber”).val(“xPhoneNumberx”);
$(“#DateOfBirth”).val(“xDateOfBirthx”);
$(“#IsMarried”).attr(“checked”, true);

$(“.ui-button-text:contains(‘Save’)”).parent().click();
});

it(“should not display name validation”, function () {
assert($(“#Name_validationMessage:visible”)).isNotDisplayed();
});

it(“should not display email validation”, function () {
assert($(“#Email_validationMessage:visible”)).isNotDisplayed();
});

it(“should not display PhoneNumber validation”, function () {
assert($(“#PhoneNumber_validationMessage:visible”)).isNotDisplayed();
});

it(“should not display DateOfBirth validation”, function () {
assert($(“#DateOfBirth_validationMessage:visible”)).isNotDisplayed();
});

it(“should not display IsMarried validation”, function () {
assert($(“#IsMarried_validationMessage:visible”)).isNotDisplayed();
});

it(“should post contact”, function () {
assert(contactWasPosted).isTrue();
});

it(“should close the dialog”, function () {
assert($(“#createDialog:visible”).length).isEqualTo(0);
});
});

});

});</pre>
<h4>Conclusion</h4>
The more and more I find myself creating highly dynamic websites, the more I find the need to Unit Test the browser interaction.

I hope you found the above example helpful. I would be interested to hear what tools you use to help Unit Test your client-side code. Please share… it makes us all better :)
You can find some other helpful client-side Unit Testing tools in the Script Junkie article I wrote entitled jQuery Test-Driven Development. In addition I wrote several other jQuery related articles that you can find on Script Junkie.

Note: It was not my intention to exhaustively Unit Test everything in the above example. There are other things I would Unit Test, but to make this example easy to understand in a bite-sized chuck, I limited myself to some simple examples.

Download Source Code


Read More »

My 7 jQuery Articles on Script Junkie








Recently a brand new Microsoft website has been launched called Script Junkie that focuses on JavaScript, HTML, CSS, and more…
<ul><li>Script Junkie Website </li><li>Twitter (@script_junkie) </li><li>Twitter List of Authors (@script_junkie/script-junkie-authors) </li><li>Script Junkie RSS Feed</li></ul>Over the past 7 months or so I’ve written 7 articles that are now available on Script Junkie. I was honored to write these articles for the launch of the website. I hope this clues you into why the blog posts on this site have been lacking.
<ol><li>Six Things Every jQuery Developer Should Know</li><li>How to Debug Your jQuery Code</li><li>History and Back Button Support</li><li>Intro to Error Handling in Ajax Apps</li><li>Custom jQuery Events and Selector Filters</li><li>How to Create Your Own jQuery Plugin</li><li>jQuery Test-Driven Development</li></ol>I am taking a break from writing for Script Junkie for a while. Our 3rd baby is due in August ;)
I hope you find the above articles helpful.

Read More »

Switching to the Strategy Pattern in JavaScript

A Typical Switch Statement Scenario

Recently I’ve been working on some highly dynamic User Interfaces and at one point in the project I found my first reflex on a certain task to use a switch statement in JavaScript.

Now, my previous training in studying the Design Patterns has told me that the switch statement is bad. The design pattern drilled into me to resolve the switch statement is the the Strategy Pattern, however, I’ve never used the Strategy Pattern in JavaScript before.

The following example is a simple demo application where I start with a switch statement and then refactor the code later in the blog post to use the Strategy Pattern.

A Simple Super Hero Demo Application

SuperHeroShadow

The sample application is a Super Hero creator. You provide a Super Hero name and then you select your Super Hero power. The power can be a variety of things ranging from Flying, Invisibility, to nothing at all. Some of the powers have additional questions (metadata) about that particular power.

Once the Super Hero is created, the application should build up a object with the appropriate power type and supporting metadata. For now, I’m just outputting the object in the Firebug Lite console using console.dir().

First Pass at a Switch Statement Solution

Here is the above application written using a switch statement to build up the Power type and metadata. The solution is fairly simple in nature. I am utilizing the Revealing Module Pattern.

Note: You can view, run, and edit the following code… http://jsfiddle.net/elijahmanor/KzAMX/

var superHeroModule = (function () {
var public = {};

public.init = function() {
$("input:radio[name='Power']").click(function() {
var selectedPower = this.value;

$("#powers .power").hide();
$("#powers ." + selectedPower).show();
});

$("#create").click(function() {
var superHero = public.scrapeSuperHero();
console.dir(superHero);
});
};

public.scrapeSuperHero = function() {
var superHero = {};

superHero.Name = $("#Name").val();
superHero.Power = public.scrapePower();

return superHero;
};

public.scrapePower = function() {
var power = {};

var selectedPower = $("input:radio[name='Power']:checked").val();
switch (selectedPower) {
case "Flying" :
power.type = "Flying";
power.speed = $("#flyingSpeed").val();
break;
case "Invisibility" :
power.type = "Invisibility";
break;
case "Strength" :
power.type = "Strength";
power.lift = $("#strengthLift").val();
power.strongerThan = $("#strengthStrongerThan").val();
break;
case "Vision" :
power.type = "Vision";
power.distance = $("#visionDistance").val();
power.seeInDark = $("#visionDark").is(":checked");
power.xrayVision = $("#visionXray").is(":checked");
break;
}

return power;
};

return public;
} ());

superHeroModule.init();

cooltext439925164

Pros of this Solution

  • Simple Implementation
  • All the code is in one place to handle building up the Super Hero power metadata

Cons of this Solution

For those of you aware of Bob Martin’s (@unclebobmartin) SOLID Principles, the “O” represents the Open/Closed Principle which states that…

Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification

The switch solution violates the Open/Closed Principle in that every time a new Super Hero power is added to the list that the same piece of code will need to be modified. This is problematic in that new bugs can easily be introduced as new features are added or as defects are resolved.

Let’s look at a better way to solve the solution.

Refactoring Using the Strategy Pattern

A lof of the code will remain the same in the refactored solution. We mainly want to pull out the switch statement into something that is more maintainable and less error prone for future enhancment.

Note: You can view, run, and edit the following code… http://jsfiddle.net/elijahmanor/K8CkZ/

var superHeroModule = (function () {
var public = {};

public.init = function() {
$("input:radio[name='Power']").click(function() {
var selectedPower = this.value;

$("#powers .power").hide();
$("#powers ." + selectedPower).show();
});

$("#create").click(function() {
var superHero = public.scrapeSuperHero();
console.dir(superHero);
});
};

public.scrapeSuperHero = function() {
var superHero = {};

superHero.Name = $("#Name").val();
superHero.Power = public.scrapePower();

return superHero;
};

public.scrapePower = function() {
var power = {};

var selectedPower = $("input:radio[name='Power']:checked").val();
var scrapePowerFunction = "public.scrapePower" + selectedPower;
power = eval(scrapePowerFunction)();

return power;
};

public.scrapePowerFlying = function() {
var power = {};

power.type = "Flying";
power.speed = $("#flyingSpeed").val();

return power;
};

public.scrapePowerInvisibility = function() {
var power = {};

power.type = "Invisibility";

return power;
};

public.scrapePowerStrength = function() {
var power = {};

power.type = "Strength";
power.lift = $("#strengthLift").val();
power.strongerThan = $("#strengthStrongerThan").val();

return power;
};

public.scrapePowerVision = function() {
var power = {};

power.type = "Vision";
power.distance = $("#visionDistance").val();
power.seeInDark = $("#visionDark").is(":checked");
power.xrayVision = $("#visionXray").is(":checked");

return power;
};

return public;
} ());

superHeroModule.init();

cooltext439925164

Pros of this Solution

  • Abides by the Open/Closed Principle by opening the code for extension, but closing it for modification.

Cons of this Solution

  • The solution is more complex than the previous switch statement implementation
  • You might have noticed the use of the eval function. Douglas Crockford labeled the eval function as a Bad Part of JavaScript for some very good reasons, however, in this case I think the benefits it brings in this situation outweighs the risks. With every hard and fast rule, there comes a place and time to examine the benefits and risks.

Conclusion

I found that separating the switch statement logic into the above Strategy Pattern has made my current project much more maintainable and less error prone when adding new features.

How have you addressed similar situation? Have you implemented a different solution to the switch statement problem? Please share with me, I’d love to know!

Read More »

Couch Potato 1.1 Bookmarklet – Expand/Collapse

4146293_ac8f

I updated the Couch Potato bookmarklet to add the ability to expand and collapse the details of each document from the list page by clicking the “+” to the left of the document key.

You can also click the “Expand All Documents” action located in the right navigation column.

The Bookmarklet

To use the bookmarklet, drag the following link to your bookmark/favorites list:

» Couch Potato 1.1 «

Read More »

Couch Potato Bookmarklet – Lazy Features for CouchDB’s Futon

The Problem

We’ve been using CouchDB in our current project at work and I’ve been using the CouchDB Futon manager more and more lately to create, edit, or delete documents.

FutonBeforeDropShadow

After a lot of test data gets into our document store, I end up needing to clear out the documents. I could Delete the whole database with a button, but I’d rather not remove the CouchDB design documents defining custom views.

In order to delete documents from Futon, you have to manually drill down into each document and then click the delete button. I found this very monotonous, so I decided to make a bookmarklet to help me out some.

The Solution

So, I created the CouchDB Potato Bookmarklet (because I’m lazy). The bookmarklet creates a new delete column and provides a “Delete Documents” link to delete all the checked documents. I also added a “Select All Documents” which only selects non-design documents (so that I don’t accidentally delete a CouchDB view). These links can be found in the right navigation column under the “Recent Databases” section.

FutonAfterDropShadow

The Bookmarklet

To use the bookmarklet, drag the following link to your bookmark/favorites list:

» Couch Potato «

Then, when you're on a listing page in Futon, just click the bookmarklet.

Ideas for Future Development

I’ve considered adding some more functionality to Couch Potato such as

  • Converting it into a GreaseMonkey script (Google Chrome & Firefox)
  • Add tooltips to the document rows showing the details of the stored document

Do you have any ideas you’d like to see?

Read More »