Unit Testing
Single Page Applications
By @johnkpaul
johnkpaul.com/html5devs
github.com/johnkpaul/twitter-show-more-example
Unit Testing - Confidence
Domenic did an amazing job. I bet he convinced you all.
- I'm was tired of manually refreshing and manually debugging everything
- I was tired of not knowing when I've broken something
- I was tired of using my app to find all the edge cases
Imperative code is easy to test
function add(){
var sum = 0;
for(var i = 0;i<arguments.length;i++){
sum += arguments[i];
}
return sum;
}
equal(10, add(1, 2, 3, 4), "sum should be 10");
equal(100, add(50, 50), "sum should be 100");
refactoring is awesome
function add(){
return Array.prototype.slice.call(arguments)
.reduce(function(prev, current){
return prev + current;
});
}
equal(10, add(1, 2, 3, 4), "sum should be 10");
equal(100, add(50, 50), "sum should be 100");
cross browser test runners can verify that your tests pass everywhere
Imagine if you wanted to unit test
But our code doesn't look like that.
Our lives are so much easier with client side MV*
We have modularity
We have "classes"
What to test?
imperative logic & event logic
- models, collections and views each have a bit of both
- it's logic we want to test, not every nitty gritty detail
- views and templates are the most difficult to sort out
Quick App Demo
And then into the code!
First, we'll take a look at the collection
- ensure we store the last fetched id
- ensure that last fetched id is sent with every subsequent request
- ensure that when fetched, it always uses add:true option
QUnit test - sinon ajax example
Collection's fetch method
Now, onto the view
- ensure that collection is fetched when rendered
- ensure that collection is fetched periodically for update
- ensure that subview is created for each model in the collection
- ensure that new subviews are hidden when models are added to collection
- ensure that show more button is visible, if there are hidden subviews
- ensure that when clicking on show more button, hidden subviews are now visible
- ... and on and on...
collection is fetched when rendered
Complex View test - sinon timer example
Code to pass test
What exactly is a unit?
- On the client, it's a little blurry
- How do we deal with units of code with dependencies?
- is a template separately testable?
- minimize, but if necessary, integrate some pieces
template conventions
- .js- and .js-test- class prefixes
- keep templates out of the DOM for sharing between app and tests
template dependent test
event handling
- make clean separation between triggering and handling of event
- in Backbone's case, there is no need to test that view events fire correctly
- But in the case of custom events, test that they are fired when expected
How do we run all of these tests?
Grunt
Grunt is a task-based command line build tool for JavaScript projects.
grunt-junit
demo
Did I forget the router?
You know what to do
Real confidence
Jenkins
(although any continuous integration system will do)
QUnit alternatives
- Jasmine - BDD
- Chai - TDD/BDD
- BusterJS
- JSTestDriver
Cross browser testing services
- Testling
- Browserling
- Browserstack
QUESTIONS
By @johnkpaul
www.johnkpaul.com