Testing JavaScript
by Kevin Isom
Why test
- IE 6
- IE 7
- IE 8
- IE 9...11
- Google Chrome
- FireFox
- Safari
- Opera
- Mobile Safari
- Android Browser
- Mobile Chrome
- Mobile IE
- Opera Mini
- ...
Testing frameworks
- Q Unit
- Jasmin
- Mocha
- Buster.js
- YUITest
- And heaps more
QUnit
QUnit.test( "hello test", function( assert ) {
assert.ok( 1 == "1", "Passed!" );
});
Jasmine
describe("A suite", function() {
it("contains spec with an expectation", function() {
expect(true).toBe(true);
});
});
Mocha
var assert = require("assert")
describe('Array', function(){
describe('#indexOf()', function(){
it('should return -1 when the value is not present', function(){
assert.equal(-1, [1,2,3].indexOf(5));
assert.equal(-1, [1,2,3].indexOf(0));
});
});
});
Chai - Should
chai.should();
foo.should.be.a('string');
foo.should.equal('bar');
foo.should.have.length(3);
tea.should.have.property('flavors')
.with.length(3);
Chai - Expect
var expect = chai.expect;
expect(foo).to.be.a('string');
expect(foo).to.equal('bar');
expect(foo).to.have.length(3);
expect(tea).to.have.property('flavors')
.with.length(3);
Chai - Assert
var assert = chai.assert;
assert.typeOf(foo, 'string');
assert.equal(foo, 'bar');
assert.lengthOf(foo, 3)
assert.property(tea, 'flavors');
assert.lengthOf(tea.flavors, 3);
Power-Assert
var assert = require('power-assert');
describe('Array', function(){
describe('#indexOf()', function(){
it('should return index when the value is present', function(){
assert([1,2,3].indexOf(0) === 2);
});
it('should return -1 when the value is not present', function(){
assert.ok([1,2,3].indexOf(2) === -1, 'THIS IS AN ASSERTION MESSAGE');
});
});
});
Buster.js
Test Case
buster.testCase("My thing", {
"has the foo and bar": function () {
assert.equals("foo", "bar");
},
"states the obvious": function () {
assert(true);
}
});
Buster.js
Describe
buster.spec.expose();// Expose describe and it functions globally
describe("My thing", function () {
it("has the foo and bar", function () {
expect("foo").toEqual("bar");
});
it("states the obvious", function () {
expect(true).toBe(true);;
});
});
YUI Test
Test Case
var testCase = new Y.Test.Case({
name: "TestCase Name",
//traditional test names
testSomething : function () {
Y.assert(true === true, "Message")
},
testSomethingElse : function () {
Y.Assert.isFunction(function(){});
}
});
YUI Test
Test Case with text names
var testCase = new Y.Test.Case({
name: "TestCase Name",
//traditional test names
"Something should happen here" : function () {
Y.assert(true === true, "Message")
},
"Check something else" : function () {
Y.Assert.isFunction(function(){});
}
});
Legacy Code
The main thing that distinguishes legacy code from non-legacy code is tests, or rather a lack of tests.
Michael Feathers - Working Effictively With Legacy Code
Legacy Code
- People are writing legacy code right now.
- Are you writing legacy code?
But JavaScript is hard to test
Right?
The way we write it makes all the difference
Nested callbacks
var fs = require('fs');
fs.mkdir('./hello',0777,function(err){
if (err) throw err;
fs.writeFile('./hello/world.txt', 'Hello!', function(err){
if (err) throw err;
console.log('File created with contents: ');
fs.readFile('./hello/world.txt', 'UTF-8', function(err, data){
if (err) throw err;
console.log(data);
});
});
});
var fs = require('fs');
fs.mkdir('./hello',0777,makeDirectory);
function makeDirectory(err){
if (err) throw err;
fs.writeFile('./hello/world.txt', 'Hello!', writeFile);
}
function writeFile(err){
if (err) throw err;
console.log('File created with contents: ');
fs.readFile('./hello/world.txt', 'UTF-8', readFile);
}
function readFile(err, data){
if (err) throw err;
console.log(data);
}
Heavily chained jquery calls
Next steps
- Code Coverage
- Testing in the cloud