I have been getting deep into TDD lately, and qUnit became the framework of my choice. This is how I decided: I went to John Resing's site and looked what he uses :) (actually wrote/co-wrote it).
Anyway, I love TDD now. It is a lot of work, and write a good test is harder that writing a good code, but it will make you much better developer who writes much better code.
I have written a simple loader which allows you to load qUnit from an external file, rather than having to have to include the HTML on the page, which is nice in combination with some client side or server side mechanism that will include your tests with dev - exclude in production.
(function ($) {
//test case init
var stringBuilder = function () {
var s = [];
return {
// appends
append: function (v) {
if (v) {
s.push(v);
}
},
// clears
clear: function () {
s.length = 1;
},
// converts to string
toString: function () {
return s.join("");
}
}
};
var sb = stringBuilder();
sb.append("<div style=\"position:absolute; right:0%; width:350px;\">");
sb.append("<h1 id=\"qunit-header\">QUnit Test Suite</h1>");
sb.append("<h2 id=\"qunit-banner\"></h2>");
sb.append("<div id=\"qunit-testrunner-toolbar\"></div>");
sb.append("<h2 id=\"qunit-userAgent\"></h2>");
sb.append("<ol id=\"qunit-tests\"></ol>");
sb.append("<div id=\"qunit-fixture\">test markup</div>");
sb.append("</div>");
$("body").append(sb.toString());
})(jQuery);
Here is how I like to write my tests: despite of all of the methods being available as globals, this might be dangerous in a complex app, so I wrap the code in a closure, and use the namespaced methods which are available under the qunit namespace:
/*test 1*/
(function (T, $) {
//get elements
var doc = $(document);
T.module("First Test");
T.test("Toggle", function () {
//how many tests are expected to pass:
expect(2);
T.equals("block", "block");
T.equals("none", "none");
});
})(QUnit, jQuery);
To get some ideas how to write tests, there are some great test cases written as examples on the bottom of the qunit page showing how jquery itself is being tested.
I have seen this quote somewhere recently: "Debugging sucks, TDD rocks!"
So I have this new friend at my new job and he was introducing me today the russian UI developer community. This made me realize, there is some serious talent in the formal Soviet Union. He explained to me that there were too many unemployed PhDs desperate to find work, and given the fact that UI development is a combination of science, hacking and art, this fits the Russian culture very well. Combine this with some a lot of time and bright brains, and you got the perfect environment for "browser innovation."
Sergey (Siarhei) mentioned these two websites to be his favorite sources of inspiration:
http://habrahabr.ru/ (Каскадные Таблицы Стилей)
http://chikuyonok.ru/
So if you get get through the "azbuka" with your google translator, you might find some innovative ways to make your browser do things you did not know it was capable of.
I needed a very simple jQuery Star Ratings Plugin, and what I found available out there just seemed too cluttered and complicated, so I came up with my own. The idea was to create something with the small amount of code possible, that would have two features: show rating, and allow for adding star rating to any type of form simply taking over a input filed
So here is what I came up with in a few hours:
(function ($) {
$.fn.stars = function (op) {
var starHtml = "<div><ul class=\"stars clearfix\"><li><a href=\"#1\" class=\"star_1\" rating=\"1\"><span class=\"selected\"></span></a></li><li><a href=\"#2\" class=\"star_2\" rating=\"2\"><span class=\"selected\"></span></a></li><li><a href=\"#3\" class=\"star_3\" rating=\"3\"><span class=\"selected\"></span></a></li><li><a href=\"#4\" class=\"star_4\" rating=\"4\"><span></span></a></li><li><a href=\"#5\" class=\"star_5\" rating=\"5\"><span></span></a></li></ul></div>";
return this.each(function () {
var wrap = $(this),
html = $(starHtml),
d = $(".dd", html),
a = $("a", html),
currentRating = wrap.attr("rating"),
isReadOnly = true;
if (typeof currentRating == "undefined") {
currentRating = "0";
isReadOnly = false;
}
//rating
html.addClass("stars_" + currentRating);
//bind events if is not read only
if (isReadOnly) {
//return false on click
a.click(function () {
return false;
});
//kills link default cursor
a.css("cursor", "default");
}
else {
//add default rating (0)
wrap.val(currentRating);
//click
a.click(function () {
var _this = $(this),
r = _this.attr("rating");
//add value
wrap.val(r);
//remove class
var currentClass = html.attr("class");
html.removeClass(currentClass);
//add current class
html.addClass("stars_" + r);
//update current
currentRating = r;
return false;
});
//hover
a.hover(function () {
var _this = $(this),
r = _this.attr("rating");
//add value
wrap.val(r);
//remove class
var currentClass = html.attr("class");
html.removeClass(currentClass);
//add current class
html.addClass("hover_" + r);
return false;
},
function () {
var currentClass = html.attr("class");
html.removeClass(currentClass);
//add current class
html.addClass("stars_" + currentRating);
currentRating
return false;
});
}
//put on page
wrap.after(html).hide();
});
};
})(jQuery);
And this is how you can use this plugin:
<p>Display Stars</p>
<span class="star_rating" rating="1"></span>
<span class="star_rating" rating="2"></span>
<span class="star_rating" rating="3"></span>
<span class="star_rating" rating="4"></span>
<span class="star_rating" rating="5"></span>
<p>Rate With Stars</p>
<input name="rating" value="0" class="star_rating" />
And here is how you can initiate it:
$(".star_rating").stars();
It works great for blog post comments, or simple directories, as this is where I am using it
You can download the source code of the star jquery plugin here.