-
Notifications
You must be signed in to change notification settings - Fork 0
Jasmine TDD
#Initialization and directory structure
In the project root directory, run
jasmine init
This creates two directories and a file:
spec/support/jasmine.json
Next, create two files:
touch spec/spec.js
touch app.js
If your app uses a Constructor function, name the filename to match the Constructor, e.g., car.js.
The directory should now look like:
spec/support/jasmine.json
spec/spec.js
app.js
#app.js app.js is an object of keys and methods. The name of the object is module.exports.
module.exports = {
helloWorld: function() {
console.log("Connected!");
return "Hello world.";
},
addOne: function(num) {
return num + 1;
},
upperCASE: function(arr) {
var hold = [];
for (var i = 0; i < arr.length; i++) {
hold.push(arr[i].toUpperCase());
}
return hold;
}
};
The line console.log("Connected!"); will indicate whether spec.js and app.js are hooked up.
Each method must return something. The name of the returned variable doesn't matter.
With a Constructor function, define the Constructor on the first line. The first line can be any of the following:
var Car = function (mpg) {
function Car (mpg) {
var Car = function Car (mpg) {
The latter is very clear. Capitalize the Constructor.
Include arguments to pass through from calling the function.
Then on the last line set module.exports equal to the Constructor"
module.exports = Car;
###Properties of Constructors
Declare properties in the Constructor, using this:
this.model = model;
this.gallons = 0;
The Constructor is a function, not an object, so it uses = and ; instead of : and ,.
this refers to the Constructor, similar to self in Ruby. It's better than saying Car.model = model; etc.(Why?)
Values passed in as arguments are declared as properties, in the format this.arg = arg.
Values that are declared instead of passed in are just declared, e.g., this.value = 25.
###Methods of Constructors
There are two ways to include a method in a Constructor function. It can be defined in the declaration:
var Car = function Car (mpg) {
this.gallons = 0;
this.fill = function (gallons) {
this.gallons += gallons;
};
};
module.exports = Car;
This is simple and clear but has problems with inheritance. Inheritance works better if the method is declared outside the Constructor function, using prototype and the Constructor name instead of this:
var Car = function Car (mpg) {
this.gallons = 0;
};
Car.prototype.fill = function (gallons) {
this.gallons += gallons;
};
module.exports = Car;
prototype is a method on every object. It enables inheritance.
What's the difference between Car.fill and Car.prototype.fill?
#spec.js
The Jasmine keywords are describe, it, xit, expect, and toEqual.
In spec.js:
var app = require('./../app.js');
describe('Test helloWorld', function() {
it('Hello world test', function() {
expect(app.helloWorld())
.toEqual("Hello world.");
});
});
describe('Test addOne', function() {
it('Adds one to a number', function() {
expect(app.addOne(1))
.toEqual(2);
});
});
var colors = ['red', 'green', 'blue'];
describe('Test upperCASE', function() {
xit('Make uppercase', function() {
expect(app.upperCASE(colors))
.toEqual(['RED', 'GREEN', 'BLUE']);
});
});
You can write the test on one line:
expect(app.nameOfTest(inputData)).toEqual(outputData);
However, the nested parentheses can be confusing. Breaking this into two lines makes the parentheses more clear. If you get the error message "undefined is not a function" on this line, then you may have a parentheses nesting problem.
xit comments out a test. Remove the x to run the test.
##Constructor Function Testing
To reduce confusion, make the first part of the first line of the test match the first part of the first line of app.js:
var Car =
Then put in require and the path:
var Car = require('../car');
The path goes to the app.js file.
#Run jasmine Run the tests from the root directory with the command
jasmine
##Nested Functions
If you're testing methods of a Constructor function/object/class then next the methods in the Constructor function:
var Car = require('./../car.js');
describe('Car', function() {
describe('car.fill', function() {
it("gives the car gas", function() {
var car = new Car(10);
expect(car.gallons).toEqual(0);
car.fill(5);
expect(car.gallons).toEqual(5);
car.fill(6);
expect(car.gallons).toEqual(11);
});
});
});
###New Instance of Constructor
In the test, create a new instance of the Constructor class/object/function:
var car = new Car("Honda Civic", 1992, 10);
These arguments could represent the make and model, the year, and the mpg.
Then call a method of the Constructor:
car.fill(5);
or
console.log(car.fill(5));
The argument could represent the gallons to fill the car.
In the expect declaration, use methods of the Constructor:
expect(car.gallons).toEqual(5)