Migrating from Jasmine 1.3 to Jasmine 2.0

  • Post by Nicolas Ramz
  • May 22, 2015
Migrating from Jasmine 1.3 to Jasmine 2.0

If you just started a new JavaScript project with Jasmine, you likely started using Jasmine 2. But if you’re working on an existing project, it’s highly possible you’re using Jasmine 1.3 and maybe want, like me, migrate to Jasmine 2. Here are a few tips how to do it.

Spies

The way spies are used has slightly changed in Jasmine 2.

spyOn(foo, 'bar').andReturn(0);
spyOn(foo, 'bar').andThrow('Oops');

foo.bar(true);
expect(foo.bar.callCount).toEqual(1);
expect(foo.bar.calls[0].args).toEqual([true]);
expect(foo.bar.mostRecentCall.args.length).toBe(1);

becomes:

spyOn(foo, 'bar').and.returnValue(0);
spyOn(foo, 'bar').and.throwError('Oops');

foo.bar(true);
expect(foo.bar.calls.count()).toEqual(1);
expect(foo.bar.calls.argsFor(0)).toEqual([true]);
expect(foo.bar.calls.mostRecent().args.length).toBe(1);

Async tests

In Jasmine 1.3, if you wanted to test methods that are asynchronous, you had to use a lach coupled with waitFor and runs. Otherwise your test wouldn’t wait for the async call to return and could break into another test, with no direct relation. You could for example have something like this:

it('my test', function() {
   var done = false;

   // async test
   runs(function() {
      asyncStuff.done(function(success) {
       expect(success).toEqual('yes');
      }).fail(function(err) {
       expect(err).toEqual('no');
      }).always(function() {
       // this will make the test end
       done = true;
      });
   });

   waitsFor(function() {
     done = true;
   });
});

Jasmine 2.0 opted for a new async syntax that is similar to Mocha, and much easier to use than the older method. You don’t have to add to call any runs() or waitFor() functions. The only thing you have to do is to use the extra done parameter that is now available to beforeEach(), it() and afterEach(). The above code could be written like this:

it('my test', function(done) {
   asyncStuff.done(function(success) {
    expect(success).toEqual('yes');
   }).fail(function(err) {
    expect(err).toEqual('no');
   }).always(done);
});

As you can see it’s way more simple and straightforward. Note that test will fail if done method isn’t called before jasmine.getEnv().defaultTimeoutInterval.

new Clock

beforeEach(function() {
  jasmine.clock().install();
});

afterEach(function() {
  jasmine.clock().uninstall();
});

it('mock test', function() {
   jasmine.clock().tick(1);
   // ...
});

using karma-jasmine-html-reporter with AngularJS

If you are using Jasmine with AngularJS to test directives, you may have an helper file that gets loaded by Karma with the following code:

beforeEach(function() {  
  angular.element('body > [class!="html-reporter"]').each(function() {
    if (this.tagName !== 'LINK') {
      angular.element(this).remove();      
    }
  });
  
  angular.element(document.body).removeData();
});

This isn’t optimized at all, but at least it doesn’t break the plugin anymore.

I think that the new async stuff is enough to migrate to Jasmine 2 if you are still using Jasmine 1.3. And as you can see, migrating isn’t that complicated so there’s no reason to stick with an outdated Jasmine 1.3.