Full-stack integration testing help

I’m an ember newbie recently started with an ember-cli project and am trying to add some full stack end-to-end tests for my application from ember client through to the real backend. However I’m having trouble understanding how to manage the asynchronous relationship between the built-in test helpers and my ajax requests.

For example, for the authentication process I have a test that visits the login route, fills in some credentials and submits the login form, and then tries to verify that the current route is now as expected.

expect(2); visit(‘/’); andThen(function(){ equal(currentRouteName(), ‘login’); });

fillIn(‘input.email-field’, ‘a_username’); fillIn(‘input.password-field’, ‘a_password’); click(‘.signin’);

andThen(function(){ equal(currentRouteName(), ‘about’); });

But I can’t get this final assertion to pass as the current route is always still the login route when the assertion executes. The controller action for the submit button creates a promise to wrap the authentication api call to the server, and then calls transitionToRoute() on successful resolution of this promise.

If I add breakpoints in the chrome debugger to try to understand the sequence of execution of my test code and the app code, I can see that the assertion in the andThen wrapper is called before the ajax call to the authentication api returns, so understandably it fails.

So my question is how to get the test to wait for the completion of my ajax calls before it executes its assertions? From my google searches, it seems that I have to do something in my test to manage the ember run loop but I have not been able to discover a magic formula that will work.

Thanks for any help.

I highly recommend this blog post on demystifying the Ember async test helpers. Your test should likely read:

expect(2);
visit('/');
andThen(function(){
  equal(currentRouteName(), 'login', 'precond - login page');
});
andThen(function(){
  fillIn('input.email-field', 'simon@olsbergfamily.net');
  fillIn('input.password-field', 'arsenal');
  click('.signin');
});
andThen(function(){
  equal(currentRouteName(), 'about', 'about page is reached after login');
});
2 Likes

Thanks for your response. I had also already tried the same additional andThen() wrapper but it doesn’t make any difference. The article you pointed to is very helpful but I stll don’t understand how the test helpers are able to wait until my promises which wrap the ajax calls to the server are getting resolved. This seems to be where my problem lies.

I should mention that these ajax calls are via a 3rd party library - i.e. not with jQuery ajax or ic-ajax.

@solsberg If you want to know exactly what it going on at that level, you will need to dive into the code.

There is a wait function that checks for pending ajax:

https://github.com/emberjs/ember.js/blob/24e6366006e90443491953bd09d899d98a2fd252/packages/ember-testing/lib/helpers.js#L176

And the pendingAjaxRequests value is incremented on each jQuery request:

https://github.com/emberjs/ember.js/blob/d4d1e7f55881dc3375238be58dfdd4321c4b2aa5/packages/ember-testing/lib/setup_for_testing.js#L46

If you want to add you own ajax method to the pending requests, I suggest just emitting the jQuery send and complete event with your own ajax code:

jQuery(document).trigger('ajaxSend');
myGetWithoutJQuery("/whut").then(function(d){
  console.log('got data!', d);
}).finally(function(){
  jQuery(document).trigger('ajaxComplete');
});

Alternatively, you can register your own waiters and decouple your code from the jQuery events using registerWaiter:

http://emberjs.com/api/classes/Ember.Test.html#method_registerWaiter

Thanks so much for this explanation. This seems to have helped. I have added calls to trigger the ajaxSend/Complete events around the 3rd party ajax calls and this seems to allow the tests to run as intended. Thanks again for sticking with me through all this.