Async testing in Jasmine 2.0

2,828 views
Skip to first unread message

José Mota

unread,
Jul 16, 2013, 11:54:37 AM7/16/13
to jasmi...@googlegroups.com
Judging from the source code at Github at the moment, `runs` and `waitsFor`
have been removed. What should we use to test promises and async calls?

I've taken a look at Derick Bailey's jasmine.async lib but it uses those
methods underneath anyway, so that's not good.

Thanks guys.

Davis W. Frank

unread,
Jul 16, 2013, 12:20:32 PM7/16/13
to jasmi...@googlegroups.com
We've adopted the Mocha "done" callback to beforeEach, it and afterEach. If you declare the fns with a "done" parameter we'll pass you a function that's meant to be called when the setup/spec is done. It's not documented yet, but will be soon.

Give it a try and see what you think.

--dwf




--
You received this message because you are subscribed to the Google Groups "Jasmine" group.
To unsubscribe from this group and stop receiving emails from it, send an email to jasmine-js+...@googlegroups.com.
To post to this group, send email to jasmi...@googlegroups.com.
Visit this group at http://groups.google.com/group/jasmine-js.
For more options, visit https://groups.google.com/groups/opt_out.
 
 



--
thx,
--dwf

José Mota

unread,
Jul 16, 2013, 7:15:46 PM7/16/13
to jasmi...@googlegroups.com
Awesome, thanks Davis, I'll get back to you as soon as I try it.

José Mota

unread,
Jul 16, 2013, 7:32:51 PM7/16/13
to jasmi...@googlegroups.com
Ok, so I've tried it now with a sample test I'm creating. I want to put an
RSVP Promise to test so I've come up with something like this:

describe("Promises", function() {
  it("is resolved", function(done) {
    var sample_url = "/examples/promised.json";
    var output = "";

    getJSON(sample_url)
    .then(function() {
      output += "JSON got back!";
    })
    .then(function() {
      expect(output).toEqual("JSON got back");
    });

    done();

  });
});

The production code is:

function getJSON(sample_url) {
  var promise = new RSVP.Promise(function(fulfill, unfulfill) {
    $.ajax({
      dataType : "json",
      url      : sample_url,
      success  : function(data) { fulfill(data); },
      error    : function(error) { unfulfill(data); }
    });
  });

  return promise;
}

The end result is a pending step because the expectation is not being run for
some reason. Am I doing something wrong here?
Message has been deleted

José Mota

unread,
Jul 17, 2013, 12:13:40 PM7/17/13
to jasmi...@googlegroups.com
I've removed the second then statement because it didn't make sense. Here's the updated version.

describe("Promises", function() {
  it("is resolved", function(done) {
    var sample_url = "/examples/promised.json";
    var output = "";

    getJSON(sample_url)
    .then(function() {
      output += "JSON got back!";
    });
    
    expect(output).toEqual("JSON got back");
    done();

  });
});

I've found a DOMException 12 error when running my tests. They were silent
but I've found them by narrowing it down to jQuery's getJSON() method. I've
also run a separate jQuery.getJSON() call in a separate environment, without
Jasmine. It worked that way so I suspect Jasmine might be involved.

What should I do in this situation?

JR Boyens

unread,
Jul 17, 2013, 12:52:02 PM7/17/13
to jasmi...@googlegroups.com
Hi, José

You should call the done() function and make your expectation inside the .then().

That way you know that getJSON() comes back and everything is fine otherwise it just runs out the method before your async call comes back.


--

José Mota

unread,
Jul 17, 2013, 2:08:20 PM7/17/13
to jasmi...@googlegroups.com
Sadly it's not working like you suggested. The runner hangs.


--
You received this message because you are subscribed to a topic in the Google Groups "Jasmine" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/jasmine-js/1Nw3olgCVI8/unsubscribe.
To unsubscribe from this group and all its topics, send an email to jasmine-js+...@googlegroups.com.

Sheel Choksi

unread,
Jul 18, 2013, 1:31:39 AM7/18/13
to jasmi...@googlegroups.com
Hi José,

The runner hanging in an async spec is typically because the done callback was never executed. 

I'm suspecting that the ajax request to 'sample_url' is failing, which means the success handler is never called. The RSVP library seems to take two arguments for the 'then' function, one for success and another for failure. Adding in a failure handler should get you a syntactically correct (albeit failing) async spec:

describe("Promises", function() {
  it("is resolved", function(done) {
    var sample_url = "/examples/promised.json";
    var output = "";

    getJSON(sample_url)
    .then(function() {
      output += "JSON got back!";
      expect(output).toEqual("JSON got back");
      done();
    }, function() {
      expect(output).toEqual("JSON got back");
      done();
    });
  });
});

As a sidenote, here is the story to keep the test suite going even if a done callback was never executed.

José Mota

unread,
Jul 18, 2013, 7:20:02 AM7/18/13
to jasmi...@googlegroups.com
Hi Sheel, thanks for getting back to me!

I have followed your suggestion and the expectation is now run, awesome! I'm
just a little twisted by the duplicate expectation but that's the least problem...!

* * *

The thing that concerns me now regards that DOM Exception 12. Like I've
mentioned, that error is swallowed somehow and I've had to manually trigger the
getJSON() method to acknowledge it. Running the method on a separate page
without Jasmine works just fine.

The error message and stack I get is this one:

Ben Loveridge

unread,
Jul 18, 2013, 11:43:52 AM7/18/13
to jasmi...@googlegroups.com
I would pursue this line in the stack trace:

at Object.x.support.cors.e.crossDomain.send (http://localhost:8001/js/vendor/jquery.js:6:8988)

This looks like an error making a disallowed cross domain request. I am not sure what sample_url you are using or what browser agent you are using to test it, but if it is a real URL served on a different host/port you might be running into cross origin problems. 

If you are using a real URL, you may want to consider stubbing out the api response. Tools like sinon or jasmine-jquery may help you here, depending on your project environment. Personally I have been using sinon for a long time with great success. 

If you really must have a real URL and you control the endpoint you may be able to add CORS response headers to get things working. 

This could be the wrong tree but not knowing more about your project, the stack trace you shared would make me look here next. 
-- 
Ben Loveridge
--

José Mota

unread,
Jul 18, 2013, 2:02:27 PM7/18/13
to jasmi...@googlegroups.com
That's actually the weird part. Why would it work outside a test runner
and it won't inside? I looked at the stack trace too and thought it was
really odd because I am not using CORS (at least I don't want to!).


To clarify, the string I was passing is "/examples/promised.json". It's
just some dummy fixture JSON file with this content:

{
  "done" : "ok"
}

As for stubbing, the point of my test is educational and I want to force a
request to be made so that I can explain about async testing. Sure,
Sinon or regular spies work fine for stubbing async calls in normal 
development but that's not the point for this very particular case, imo.

I just hope I don't have to take my work back on this and stick to spies
because I've been around the subject for a while and I'm starting to lose it.

Thanks for helping guys.

Sheel Choksi

unread,
Jul 18, 2013, 11:17:46 PM7/18/13
to jasmi...@googlegroups.com
If this is tied to sample/educational code, is there some place we can check out the project to see this exception? I'm thinking that this might not be related to the Jasmine async code anymore, but it'd be great to see the spec working and know for sure.

Additionally, when you 'manually trigger the getJSON()', is this inside the source JS files, or in the console when on a page from your application? If you could provide the steps you're doing in the successful case, that'd be a great help as well.

José Mota

unread,
Jul 19, 2013, 7:25:16 AM7/19/13
to jasmi...@googlegroups.com
This definitely doesn't have to do with Jasmine async test errors. And
yes, absolutely, I'll put the project up on GitHub or something. I feel
this should be explored further.

I'll let you know really soon.

José Mota

unread,
Jul 19, 2013, 7:02:36 AM7/19/13
to jasmi...@googlegroups.com
Okay, here we go, I've posted the project on GitHub:


I've posted a README on how to run the concrete example. The current branch is `promises`.

Sheel Choksi

unread,
Jul 20, 2013, 1:01:21 AM7/20/13
to jasmi...@googlegroups.com
Great, thanks for posting that. It seems to be an inconsistency with the version of jQuery you're using. I'm not sure why it would be different between an the index page of your site versus the test runner, but downgrading to jQuery 1.10.2 got it working in both places. This could be an interesting area to further explore in jQuery if you want.

Some other steps I had to take to get it to work:
- Include jQuery as a script tag in test.html fairly early
- Fix up the spec to have an expectation and call 'done' in the success handler (now that the ajax started working)

Hopefully that helps!

José Mota

unread,
Jul 20, 2013, 3:12:23 AM7/20/13
to jasmi...@googlegroups.com
Wonderful! I would have never thought of swapping back jQuery's
version, that was keen of you, Sheel.
I'm going to bring this example back to the folks at jQuery so the
bug can be worked out.

Thank you Davis, JR, Ben and Sheel for helping in the situation at
hand. I am relieved to see this off my back. I'm going to update the
GitHub issue associated and think about documenting the new way
of testing async calls.
Reply all
Reply to author
Forward
0 new messages