Let us consider the block of code below, which are additional methods on the Car object. The driveForward method on a Car instance makes a call to hasEnoughtFuel.
Car.prototype.moveForward = function(distance) {
console.log("Move car by " + distance);
};
Car.prototype.stayPut = function() {
console.log("I do not have enought fuel to move");
};
Car.prototype.hasEnoughFuel = function(fuel, distance) {
var deferred = $.Deferred();
$.ajax({
url: "/check_forward_movement_ability.json",
type: "GET",
})
.done(function(response) {
deferred.resolve(response.canMove);
}).fail(function(response) {
deferred.fail();
});
return deferred.promise();
};
Car.prototype.driveForward = function(distance) {
var promise = this.hasEnoughFuel(this.fuel, distance);
var self = this;
$.when(promise).done(function(canMove) {
if (canMove) self.moveForward(distance);
else self.stayPut(distance);
});
};
When we call
var car = new Car();
car.driveForward(5)
The code makes an ajax request to a hypothetical server. When unit testing front end code, we should avoid making actual requests to the server as this will consume unnecessary resources, delay the tests and is outside the scope of unit tests.
A workaround for this is FakeServer provided by sinonjs. This can mocks the actual call to the server and help us keep the testing scope limited to the unit tests. Here is what this implementation looks like..
describe("Car movement", function() {
beforeEach(function() {
this.server = sinon.fakeServer.create();
this.car = new Car();
sinon.stub(this.car, "moveForward");
sinon.stub(this.car, "stayPut");
});
afterEach(function() {
this.server.restore();
this.car.moveForward.restore();
this.car.stayPut.restore();
delete this.car;
});
it("should call moveForward, when server responds with canMove as True", function(done) {
this.server.respondWith("GET", "/check_forward_movement_ability.json",
[200, { "Content-Type": "application/json" },
'{ "canMove": true }']);
this.car.driveForward(5);
this.server.respond();
sinon.assert.calledOnce(this.car.moveForward);
//Tell mocha to wait for response, and then run the test
//by calling done() callback
done();
});
it("should not call moveForward, when server responds with canMove as False", function(done) {
this.server.respondWith("GET", "/check_forward_movement_ability.json",
[200, { "Content-Type": "application/json" },
'{ "canMove": false }']);
this.car.driveForward(5);
this.server.respond();
sinon.assert.notCalled(this.car.moveForward);
done();
});
});
Note: Here we initialize a new instance of Car for every test run by initializing it in the beforeEach call. This is because the first test calls moveForward on a car instance. So the second test which checks that moveForward is not called, should run on a different instance, or this test may fail on some browsers like PhantomJS.