Question

I am trying to test an ember component with mocha and sinon. I wanted to test one of the actions of the component which makes an ajax call by using sinon's "useFakeXMLHttpRequest". But this test is causing time-out error. I am using mocha test adapter for ember taken from https://github.com/teddyzeenny/ember-mocha-adapter, I couldn't find the js file in cloud so I have pasted in whole code - so it might look bit messy in the jsbin.

Here is a jsbin link to the issue : http://jsbin.com/usajOhE/1/

The code for the component is :

        AS.QuestionViewComponent = Ember.Component.extend({
            templateName: "components/question-view",
            actions: {
                makeAjaxCall: function() {
                    jQuery.ajax({
                        url: "/todo/items",
                        success: function(data) {

                            //callback(null, data);
                        }
                    });
                }
            }

        });

The handle bar associated with the component is :

<a {{action "makeAjaxCall"}} class="test-link">Make ajax call</a>   

And my test script is:

        describe("Testing", function() {


            var xhr, requests;
            before(function() {

                xhr = sinon.useFakeXMLHttpRequest();
                requests = [];
                xhr.onCreate = function(req) {
                    requests.push(req);
                };

            });

            after(function() {
                xhr.restore();
            });

            beforeEach(function() {
                AS.reset();
                visit("/");
            });

            it("shoud make ajax call", function() {
                //TIMESOUT HERE                   
                click($("a.test-link:first")).then(function() {
                    console.log(requests);
                    expect(requests.length).to.be(1);
                });
            });
        });

Your help will be much appreciated. Thanks

Was it helpful?

Solution

Most likely it is because you have not responded to the fake ajax request. The ember-testing package counts the pending ajax requests made by jQuery (see pendingAjaxRequests here). If this stays at 1, the ember-testing wait() helper never resolves.

The ember-testing package increments this counter via ajaxStart and ajaxStop filters.

To clarify what's happening here: When you use the click() helper, this sends a click message to the element, and then defers to the wait() helper (a promise). The same applies for other helpers such as fillIn(), keyEvent() etc. You can see from the comments in the source for wait() that it will not progress on with the rest of your specs:

// 1. If the router is loading
// 2. *If there are pending Ajax requests
// 3. If there are scheduled timers or we are inside of a run loop

The fix:

Unfortunately, if you never make it to the then block of your test, you cannot fake a response via requests[0].respond(...).

Instead, I've solved this by using sinon's fake server:

var server;

beforeEach(function () {
  server = sinon.fakeServer.create();
  server.autoRespond = true;
  server.autoRespondAfter = 1; // ms
  App.reset();
});

afterEach(function () {
  server.restore();
});

it("should make ajax call", function() {
  // set up the fake response
  server.responses[0].response = [200, { "Content-Type": "application/json" }, '{ "todos": [] }'];

  visit('/')
  .click($("a.test-link:first"))
  .then(function() {
    // should make it to here now
  });
});

This pattern works fine when you are expecting a single, or a deterministic order of ajax requests going into your fake server. If you expect lots of requests (with different paths), you can use server.respondWith([regex], ...) to match certain urls to specific responses.

Another thing to note is that it's generally good practice to put the success part of your ajax call into an Ember.run:

jQuery.ajax({
  url: "/todo/items",
  success: function(data) {
    Ember.run(function () {
      //callback(null, data);
    })
  }
});
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top