22

I'm using Jasmine with Karma to test my app built on Angular.

I've to test a service that loads user data and I'm using $httpBackend to mock the responses. However, when I run the test, I got two errors:

Module:

'use strict';

app.service ('UserService', ['$resource', '$q', 'GITHUB_API_URL', function ($resource, $q, GITHUB_API_URL) {
  var userResource = $resource (GITHUB_API_URL + '/users/:user', {user: '@user'}) ,
      userModel = {};

  return {
    data: function () {
        return userModel;
    } ,
    populate: function (user) {
      var deferred = $q.defer () ,
          userRequest = userResource.get ({user: user});

      $q
          .when (userRequest.$promise)
          .then (function (data) {
              userModel = data;
              deferred.resolve (data);
          });

      return deferred.promise;
    }
  };
}]);

Test:

'use strict';

describe ('Service: UserService', function () {
    beforeEach (module ('myApp'));

    var $appInjector = angular.injector (['myApp']) ,
        UserService = $appInjector.get ('UserService') ,
        GITHUB_API_URL = $appInjector.get ('GITHUB_API_URL') ,
        GITHUB_USER = $appInjector.get ('GITHUB_USER') ,
        $httpBackend;

    beforeEach (inject (function ($injector) {
        $httpBackend = $injector.get ('$httpBackend');

        $httpBackend
            .when ('GET', GITHUB_API_URL + '/users/' + GITHUB_USER)
            .respond ({
                login: GITHUB_USER ,
                id: 618009
            });
    }));

    afterEach (function () {
        $httpBackend.verifyNoOutstandingExpectation ();
        $httpBackend.verifyNoOutstandingRequest ();
    });

    describe ('when populate method is called', function () {
        it ('should returns user data', function () {
            $httpBackend.expectGET (GITHUB_API_URL + '/users/' + GITHUB_USER);

            UserService.populate (GITHUB_USER);
            $httpBackend.flush ();
            expect(UserService.data ()).toEqual ({
                login: GITHUB_USER ,
                id: 618009
            });

        });
    });
});

Let's assume that GITHUB_API_URL is equal to 'https://api.github.com/' and GITHUB_USER is equal to 'wilk'.

I'm running this test with Karma-Jasmine 0.1.5 and AngularJS 1.2.6 (with Angular Mocks and Scenario 1.2.6).

What's wrong with this code?

3
  • I created a Plunker script with your code, but I don't know what GITHUB_USER is. Would you mind updating it? Commented Feb 5, 2014 at 13:36
  • @MichaelBenford It's a constant and as I mentioned is equal to the string 'wilk'. Commented Feb 5, 2014 at 13:44
  • My bad. Didn't notice it. Commented Feb 5, 2014 at 14:13

1 Answer 1

48

Let's talk about each error separately:

Error: No pending request to flush!

That's happening because no request was made through $httpBackend, so there's nothing to flush. That's because you are instantiating UserService before $httpBackend and so Angular doesn't know it should use it instead of the real $http. If you check out the console you'll see that a real request is being sent.

Error: Unsatisfied requests: GET https://api.github.com/users/wilk

Same reason as the above. Since $httpBackend isn't being used by the service, the expectation you've created is never fulfilled.

Here's your spec refactored after considering all of the above:

describe ('Service: UserService', function () {
    var UserService,
        GITHUB_API_URL,
        GITHUB_USER,
        $httpBackend;

    beforeEach(function() {
      module('plunker');

      inject(function( _$httpBackend_, _UserService_, _GITHUB_API_URL_, _GITHUB_USER_) {
        $httpBackend = _$httpBackend_;
        UserService = _UserService_;
        GITHUB_API_URL = _GITHUB_API_URL_;
        GITHUB_USER = _GITHUB_USER_;
      });
    });

    afterEach (function () {
        $httpBackend.verifyNoOutstandingExpectation ();
        $httpBackend.verifyNoOutstandingRequest ();
    });

    describe ('when populate method is called', function () {
        it ('should returns user data', function () {
            $httpBackend
              .whenGET(GITHUB_API_URL + '/users/' + GITHUB_USER)
              .respond ({
                  login: GITHUB_USER,
                  id: 618009
              }); 

            UserService.populate(GITHUB_USER);
            $httpBackend.flush();

            expect(UserService.data().login).toBe(GITHUB_USER);
            expect(UserService.data().id).toBe(618009);
        });
    });
});

Plunker

Note: I've changed the way things were being injected a little bit, but the way you are doing is just fine, as long as you create $httpBackend before everything else.

Sign up to request clarification or add additional context in comments.

5 Comments

Woah! +1 for the great answer! Clear and detailed! Thanks for the explanation! However I didn't understand yet how 'inject' function works. How can inject such those renamed params? I mean, how does it know that UserService it's a service of my module?
@Wilk When you call module('myApp') Angular loads all services that module contains so the injector can use any of them. The underscores in the param names are just to prevent variable names from clashing. Angular just ignores them. You don't need to use them if your local variables have different names, though. More info on that here.
Thanks so much, if I could +1 this again and again I would. I was pulling my hair out trying to figure out why my requests were unsatisfied.
I wish I could vote this up again, months ago I was here for the first error, now I found it again for the second error answer lol. Thanks again.
ummmm, can you elaborate "the expectation you've created is never fulfilled"? I am getting the Error: Unsatisfied requests: PUT /api/v1/categories/by_key/zoom error

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.