Jasmine has a number of other useful features, which help you write tests that are more advanced.
Another useful feature of Jasmine is actually a twofer: beforeEach and afterEach. They allow you to execute some code—you guessed it—before and after each spec. This can be very useful for factoring out common code or cleaning up variables after tests.
To execute some code before every spec, simply put it in a beforeEach. Note that you have to scope variables properly in order to have them throughout each spec:
describe("employee", function() {
var employee; // Note the scoping of this variable.
beforeEach(function() {
employee = new Employee;
});
it("has a name", function() {
expect(employee.name).toBeDefined();
});
it("has a role", function() {
expect(employee.role).toBeDefined();
});
});Similarly, if you’d like to execute something after each spec, simply put it in the cleverly named afterEach. I use this much less than beforeEach, but it’s useful when you want to do cleanup, for example:
describe("Calculator", function() {
var calculator = new Calculator;
afterEach(function() {
calculator.reset();
});
it("can add two positive integers", function() {
expect(calculator.add(5, 12)).toEqual(17);
});
it("can add two negative integers", function() {
expect(calculator.add(-5, -12)).toEqual(-17);
});
});As your code gets more complex, you might want to organize your suites into groups, subgroups sub-subgroups, and so on. Jasmine makes it very easy for you to do that by simply nesting the specs.
Put a describe block inside another describe block like this:
describe("chat", function() {
describe("buddy list", function() {
it("contains a list of users", function() {
expect(chat.buddyList instanceof Array).toBeTruthy();
expect(chat.buddyList[0] instanceof chat.User).toBeTruthy();
});
});
describe("messages object", function() {
it("contains a sender and a body", function() {
var message = new chat.Message;
expect(message.body).toEqual("");
expect(message.sender instanceof chat.User).toBeTruthy();
});
});
});To give you an idea of this feature’s utility: my most recent project had a group with about 20 subgroups, and each subgroup had about 5 sub-subgroups. Jasmine makes nesting suites very easy indeed!
When you code specs, sometimes you might want to skip a few. Maybe a spec isn’t finished; maybe it’s too slow; maybe you’re just not in the mood to see one red spec in a sea of green ones.
Instead of commenting specs out, just add an x before the word it, and the code will behave as though you had commented the spec out. In the following example, we haven’t finished the spec that tests a double rainbow’s brightness, so we’ll x it out:
describe("double rainbow", function() {
it("is all the way across the sky", function() {
// This spec will run.
});
xit("is so bright", function() {
// Because we've x'd this spec out, it won't run.
});
});Now when you run your specs, you won’t see the “double rainbow is so bright” spec at all.
You can also x out entire suites, which will skip all of the specs inside. In this example, none of the Leonardo DiCaprio specs will run:
xdescribe("Leonardo DiCaprio", function() {
it("is not named after Leonardo da Vinci", function() {
expect("Leonardo DiCaprio").not.toEqual("Leonardo da Vinci");
});
it("is in the movie Inception", function() {
expect(Inception.cast).toContain("Leonardo DiCaprio");
});
it("is not in the movie Braveheart", function() {
expect(Bravehart.cast).not.toContain("Leonardo DiCaprio");
});
});No specs for poor Leo.
Because all of your specs and suites are defined in functions, you can skip all specs and suites after a certain point in the function with a clever return. Because return halts a function’s execution, you can stop some specs from running, like so:
describe("I'm only going to run SOME of these", function() {
it("will run this spec", function() {});
it("will run this spec", function() {});
return; // This will stop the function from doing anything else.
it("will not run this spec", function() {});
it("will not run this spec", function() {});
});This is not a Jasmine feature, but a hack “given to us” from JavaScript. It might be a little unclear to other developers what you’re doing, so I’d recommend leaving a comment about the fact that you aren’t running some specs.
Sometimes you don’t care what the value is; you care what type it is. To indicate this, use jasmine.any. This is a lot like JavaScript’s instanceof operator, though a bit different with regard to primitive types.
Let’s say that we create a function called rand that generates a random number. We want to make sure that, no matter what, it returns a number. We don’t really care what the number is—we just care that it’s a number:
expect(rand()).toEqual(jasmine.any(Number));
Of course, this doesn’t just work for numbers. All of these specs succeed:
expect("Hello world").toEqual(jasmine.any(String));
expect({}).toEqual(jasmine.any(Object));
expect(new MyObject).toEqual(jasmine.any(MyObject));These are incredibly useful when you want your results to be of a certain type but don’t need to be more specific than that.