Jasmine.Async: Making Asynchronous Testing With Jasmine Suck Less

I love Jasmine. It’s a great BDD-style testing framework for browser based JavaScript, and my preferred tool for doing that kind of work. But the asynchronous testing story in Jasmine is painful at best.

Jasmine’s Async Is Painful

Here’s a short example of how you make Jasmine work with asynchronous JavaScript:

describe("an async spec", function(){

  beforeEach(function(){
    var done = false;

    function doStuff(){
      // simulate async stuff and wait 10ms
      setTimeout(function(){
        done = true;
      }, 10); 
    }

    runs(doStuff);

    waitsFor(function(){
      return done;
    });
  });

  it("did stuff", function(){
    expect(done).toBe(true);
  });

});

This isn’t fun. That “runs” and “waitsFor” code gets repeated all over the place – every time you need to wait for something async to complete. By contrast, look at my previous post on asynchronous testing with Mocha. That simple little “done” function in the beforeEach and it callbacks is so easy to work with. Just add the parameter to the callback, and call “done()” when the async code has completed.

I want Jasmine to work this way, too, because there are things I like about Jasmine vs Mocha and when I use Jasmine, I don’t want to be stuck with horrible async tests. Thus, Jasmine.Async was born out of frustration and little bit of jealousy in how easy it is to do async tests with Mocha.

Jasmine.Async

To use Jasmine.Async, you need to include the jasmine.async.js file in your test suite. In your “describe” functions, create a new instance of the “AsyncSpec” object and pass in the current context (“this”). Now instead of calling “beforeEach”, you can call “async.beforeEach” which gives you a “done” parameter in the callback function, like Mocha does.

describe("an async spec", function(){

  var foo = false,
      async = new AsyncSpec(this);

  async.beforeEach(function(done){

    // simulate async stuff and wait 10ms
    setTimeout(function(){
      foo = true;
      done();
    }, 10); 

  });

  it("did stuff", function(){
      expect(foo).toBe(true);
  });

});

There’s an “async.beforeEach”, “async.afterEach” and “async.it” – all of which are given the “done” callback. This is so much more clean and easy to understand now. 

So go grab Jasmine.Async and make your async tests suck less. 


Post Footer automatically generated by Add Post Footer Plugin for wordpress.

About Derick Bailey

Derick Bailey is an entrepreneur, problem solver (and creator? :P ), software developer, screecaster, writer, blogger, speaker and technology leader in central Texas (north of Austin). He runs SignalLeaf.com - the amazingly awesome podcast audio hosting service that everyone should be using, and WatchMeCode.net where he throws down the JavaScript gauntlets to get you up to speed. He has been a professional software developer since the late 90's, and has been writing code since the late 80's. Find me on twitter: @derickbailey, @mutedsolutions, @backbonejsclass Find me on the web: SignalLeaf, WatchMeCode, Kendo UI blog, MarionetteJS, My Github profile, On Google+.
This entry was posted in Async, Jasmine, jasmine-async, Javascript, Unit Testing. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • mike

    You may want to have a look at mochajs. It has resolved this issue and has an interface identical to jasmine with some other niceties thrown in (ie, grep).
    http://visionmedia.github.com/mocha/

    • http://mutedsolutions.com Derick Bailey

      lol. always nice to know that people don’t bother reading before commenting :P

      • Mike

        My apologies Derick. I reread it and saw you did mention it. I had my family waiting for me and was rushed. I’ll do better next time.

        • http://mutedsolutions.com Derick Bailey

          :) no worries – i can’t tell you how many times i’ve missed blatantly obvious things even when i do read stuff

        • Kristian Ask

          Old post, I know but if mike hadn’t commented I would never have known that they’d fixed it. I only read with half an eye :)

  • Kevin Dente

    Just out of curiosity, what is it about Jasmine that you prefer over Mocha?

    • http://mutedsolutions.com Derick Bailey

      the ruby gem, for one. it’s nice to be able to run a command-line watcher script that picks up new files and file changes for me, running in sinatra. i know mocha has something like this, but i’ve never been able to get it to work the way i want.

      i also like the “expect” syntax of jasmine better than the available options for mocha. for my mocha use, i settled in on chai which gets close to jasmine but is too .-happy with things like “to.be.a()” and “to.equal()”. My .net background cringes when i see this, as it creates an un-needed layer of abstraction and complexity.

      also – jasmine if far easier to get up and running. you get jasmine and you get the syntax for describing behavior as well as setting expectations, and for basic spies (mocks / stubs). with mocha, you have to piece it together yourself. that makes it difficult for n00bs because they don’t know what to choose, and an annoyance for me because i have to remember to go get everything.

      mocha has benefits, though. if you’re testing NodeJS, it’s mocha. jasmine sucks for testing node. but jasmine’s browser based testing is easier for me than mocha.

      mocha’s flexibility and plugin architecture are also significantly better than jasmine’s. that gives you choice and options, which can be a good things. mocha also supports “pending” tests, which jasmine doesn’t.

      so for me, it comes down to what project i’m doing, and what options i need. i use both mocha and jasmine at this point, and i like to have the option of using either one.

      • http://twitter.com/cromwellryan Ryan Cromwell

        have you tried guard for your watcher needs? if there is no native guard-mocha, just use guard-shell

        • http://mutedsolutions.com Derick Bailey

          ah – good call. i use guard and guard-shell a lot, but hadn’t thought about using it for mocha. somehow the idea that i have to use their built in watcher got stuck in my head. will give that a try one a project, sometime soon probably.

      • Kevin Dente

        If you didn’t see them, there were a couple of new test runners released recently that give you similar capabilities as the Ruby gem (and more, especially multibrowser testing – cool stuff)
        Testem – https://github.com/airportyh/testem
        Testacular – http://vojtajina.github.com/testacular/

  • Guest

    This is really great.

    I was having the same thought about Jasmine’s complex asynchronous API versus Mocha’s simplicity.
    I will definitely try this.

  • Joseph chapman

    Can you not just mock asynchronous calls with andCallFake to return done

    • http://mutedsolutions.com Derick Bailey

      if you can, do that. it’s not always possible, though. There are times when it’s far more difficult or creates too much of a brittle test, to spy/mock/stub the internal working of an object. in those cases, async tests are important. the prime example for me, right now, is WinJS/Promises. but also in API design for my Backbone applications, I often want to ensure my promises are working correctly for loading data through an API in my app instead of directly through a model or collection.

  • http://rosenfeld.heroku.com/ Rodrigo Rosenfeld Rosas

    I’d like to hear your opinions on my own spec runner: oojspec

    https://github.com/rosenfeld/oojspec

    Since it supports beforeAll and afterAll and since all examples are run in a specific order and since the “runs” block is guaranteed to be run in any before blocks before the examples start, I don’t think the waitsFor/runs suck. Quite the opposite, I find the option you provide very limiting when you’re writing integration specs specially. This is a limiting factor in Buster.js for example in my opinion, which implements the approach you suggested…

    • http://mutedsolutions.com Derick Bailey

      in what way is this limiting? there’s nothing you can do with runs/waitsFor that can’t be done with a simple “done()” call.

  • Dan Hollenbeck

    Typo in your gist?

    async.it(“did stuff”, function(){
    instead of

    it(“did stuff”, function(){

  • Dan Hollenbeck

    Typo in your gist?

    async.it(“did stuff”, function(){
    instead of

    it(“did stuff”, function(){

    • http://mutedsolutions.com Derick Bailey

      the it statement doesn’t need to be async in this case, though the plugin does support it.

    • http://mutedsolutions.com Derick Bailey

      the it statement doesn’t need to be async in this case, though the plugin does support it.

  • millermedeiros

    jasmine-node monkey patches the `it`, `beforeEach` and `afterEach` methods: https://github.com/mhevery/jasmine-node/blob/master/lib/jasmine-node/async-callback.js – I find it simpler.

  • Alon Salant

    It’s worth noting that jasmine-node has supported the same async style as Mocha since Feb 2012. http://bytes.goodeggs.com/post/13332056735/better-asynchronous-jasmine-node-specs

    Note to the author of Jasmine.Async – if you wanted you could have Jasmine.Async patch jasmine (as shown in the post above) so then when you include it, jasmine would support the done callback without having to create a new AsyncSpec.

    • Alon Salant

      Oops. I see that another poster already pointed this out.

  • wcanyon

    Black text on a dark grey background? Yuck.

  • Daniel Harrington

    thank you so much!

  • Moshe Silberman

    I find that to make my tests more “unit” -y you can abstract away all the asynchronousity by spyihg the setTimeout / setInterval / jquery get etcetera, and then pulling the original function off the spy object and executing it. That works for even non-promise objects. For promises it get’s a little stickier, but a previous commenter already suggested returning a synchronous done. One of the advantages there, is that you can test the non- ‘success’ cases without having to mess with your server, but then that’s the general difference between functional and unit like tests.