Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to do Ember unit testing with asynchronous routes?

I'm using the functionality described in the Ember.js Asynchronous Routing guide. Namely, I'm returning a promise from my asynchronous route's model hook to delay transitioning to the route, which works as expected.

However, it breaks the ability to unit test my app. When I run my tests, I get the following error in the console:

Assertion failed: You have turned on testing mode, which disabled the run-loop's autorun. You will need to wrap any code with asynchronous side-effects in an Ember.run

I've wrapped all code with asynchronous side-effects in Ember.run, but I still get the error.

Here's a JSFiddle with a minimal example: http://jsfiddle.net/nRHfv/3/

The example is based on the Ember Starter Kit and the test runner it comes with. It has a working asynchronous index route. If you set testing: false to true in the _config object (line 10), it will turn on the test suite, and you should see the above error in your console.

My asynchronous route's model hook is on line 38. I've tried several variations on wrapping the code in Ember.run. For example, I've tried defining the promise outside of Ember.run, doing all the asynchronous stuff inside, and then returning the promise outside. I've also tried wrapping just the contents of then() in Ember.run, like I've seen on some other answers (e.g. ember integration test error. dealing with asynchronous side-effects).

What am I doing wrong?

like image 705
No Surprises Avatar asked Nov 11 '22 12:11

No Surprises


1 Answers

After more searching, I found this notable comment on Guide: Asynchronous side-effects in testing on the Ember.js discussion forum by EmberSherpa:

BTW, there was a library released today that's designed to replace $.getJSON and makes this process a lot easier https://github.com/instructure/ic-ajax

I tried the ic-ajax library, and it worked! After digging in to see what it's doing, here's how I should have written my asynchronous route's model hook:

var promise = new Ember.RSVP.Promise(function (resolve, reject) {
  Ember.$.ajax({
    url: '/echo/json/',
    type: 'POST',
    data: {
      json: '{ "text": "Hello from Ember.js" }',
      delay: 0.25
    },
    dataType: 'json',
    success: function (response, textStatus, jqXHR) {
      Ember.run(null, resolve, response);
    }
  })
});

return promise.then(function (response) {
  return response;
});

I guess jQuery promises are not interchangeable with Ember.RSVP.Promise when testing (but they are for triggering asynchronous routing actions).

Here's an updated JSFiddle with asynchronous routing and testing working: http://jsfiddle.net/nRHfv/5/

I think I'm going to stick with ic-ajax for the sake of cleaner code, and because of the ability to load static fixtures instead of live API endpoints when testing.

like image 159
No Surprises Avatar answered Nov 14 '22 22:11

No Surprises