How to unit test an angularjs promise chain using $httpBackend

All we need is an easy explanation of the problem, so here it is.

Using AngularJS, I am trying to unit test a function that makes multiple calls to $http.

My test looks something like this:

it('traverses over a hierarchical structure over multiple chained calls', function() {

    .then(function(theAggregateResult) {
        // never fulfilled


Other single-call tests will register the callback passed to .then() and execute it as soon as I call .flush().

The code under test looks something like this.

function traverseTheStuff(){

    // This will make a call to $http to fetch some data
    return getRootData()

    // It is fulfilled at the end of the test when I $httpBackend.flush()

        // Another call to $http happens AFTER $httpBackend.flush()
        return getNextLevel(rootData.someReference);

    // The second promise is never fulfilled and the test fails
        return aggregateTheStuff(...);

For what its worth, each of the single calls is unit tested separately. Here, I want to traverse a tree, aggregate some data and unit test a) that the promise chaining is hooked up correctly and b) the aggregation is accurate. Flattening it out into separate discrete calls is already done.

How to solve :

I know you bored from this bug, So we are here to help you! Take a deep breath and look at the explanation of your problem. We have many solutions to this problem, But we recommend you to use the first method because it is tested & true method that will 100% work for you.

Method 1

I’m a beginner in testing Angular, but I’ve setup a plnkr that tests a very similar setup to yours with a sucessfull “second” then/promise call

The below code snippets are slightly simplified versions of the above plnkr.

The key points I’ve found are

  • I note the function traverseTheStuff doesn’t call $http/$httpBackend at all. It only uses functions defined in $q promises, so the testing on assumes use of $q, and injects that

    var deferred1 = null;
    var deferred2 = null;
    var $q = null;
    beforeEach(function() {
      inject(function(_$q_) {
        $q = _$q_;
    beforeEach(function() {
      deferred1 = $q.defer();
      deferred2 = $q.defer();
  • The functions to be called asynchronously are spied/stubbed with their promise return values, where the promise is created in the test itself, so their actual implementation isn’t called when testing traverseTheStuff

  • There aren’t any calls to “then” in the test, only to “resolve” on the promises created in the test, followed by $rootScope.$apply(), to then actually call the “then” callbacks in traverseTheStuff, which we can also test are called

    beforeEach(function() {
      spyOn(deferred1.promise, 'then').andCallThrough();
    beforeEach(function() {
      $rootScope.$apply(); // Forces $q.promise then callbacks to be called
    it('should call the then function of the promise1', function () { 
  • Each promise must be resolved/$apply-ed to call the next “then” function in the chain. So. to get the test to call aggregateTheStuff (or rather, its stub), the second promise, returned from the getNextLevel stub, must also be resolved:

    beforeEach(function() {
      $rootScope.$apply(); // Forces $q.promise then callbacks to be called
    it('should call aggregateTheStuff with ' + testLevel, function () {

An issue with all of the above, is that it assumes certain behaviour from $q and $rootScope. I was under the understanding unit tests like this shouldn’t make this assumptions, in order to truly only test one bit of code. I’ve not worked out how to get around this, or if I’m misunderstanding.

Note: Use and implement method 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from or, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply