56
votes

I've defined the following service in my angular app :

services.factory('MyService', ['Restangular', function (Restangular) {
       return {
           events : { loading : true },

           retrieveQuotes : function() {
               return Restangular.all('quotes').getList().then(function() {
                   return { hello: 'World' };
               });
           }
    };
}]);

and I'm writing the following spec to test it :

describe("MyService", function () {

    beforeEach(module('MyApp'));
    beforeEach(module("restangular"));

    var $httpBackend, Restangular, ms;

    beforeEach(inject(function (_$httpBackend_, _Restangular_, MyService) {
        ms = MyService;
        $httpBackend = _$httpBackend_;
        Restangular = _Restangular_;
    }));


    it("retrieveQuotes should be defined", function () {
        expect(ms.retrieveQuotes).toBeDefined();
    });

    it("retrieveQuotes should return array of quotes", function () {

        $httpBackend.whenGET("internalapi/quotes").respond({ hello: 'World' });
        ms.retrieveQuotes();
        $httpBackend.flush();
    });

});

Whenever I run the tests, the first test passes but the second test produces the error :

Error: Unexpected request: GET /internalapi/quotes

What am I doing wrong?

EDIT:

It turned out I'd configured Restangular like so ... RestangularProvider.setBaseUrl("/internalapi");. But I was faking calls to internalapi/quotes. Notice the lack of the "/". Once I added the slash /internalapi/quotes all was good :)

2
stackoverflow.com/questions/14761045/… (I didn't flag as duplicate, because the problems seem different to an extent). - Ricky Mutschlechner
Please remember to mark your question as resolved, based on your edit it looks like it has been fixed. :) - Chris Foster
It may be obvious to others, but in case it's not, these expectMETHOD calls expect you to pass in the full URL, not just the path, if you're calling external services. - kungphu
Another way to avoid this whole difficulty (if a certain test doesn't need that much specificity) is to pass in a regular expression instead of a string. E.g., $httpBackend.expectGET(/internalapi/) or $httpBackend.expect('GET', /quotes/) - Marcus

2 Answers

56
votes

You need to tell $httpBackend to expect a GET request.

describe("MyService", function () {

   beforeEach(module('MyApp'));
   beforeEach(module("restangular"));

   var Restangular, ms;

    beforeEach(inject(function (_Restangular_, MyService) {
        ms = MyService;

        Restangular = _Restangular_;
    }));


    it("retrieveQuotes should be defined", function () {
        expect(ms.retrieveQuotes).toBeDefined();
    });

    it("retrieveQuotes should return array of quotes", inject(function ($httpBackend) {

        $httpBackend.whenGET("internalapi/quotes").respond({ hello: 'World' });

        //expect a get request to "internalapi/quotes"
        $httpBackend.expectGET("internalapi/quotes");

        ms.retrieveQuotes();
        $httpBackend.flush();
    }));

});

Alternatively you can put your respond() on your expectGET(). I prefer to put my whenGET() statements in a beforeEach() that way I do not have to define the response within every test.

        //expect a get request to "internalapi/quotes"
        $httpBackend.expectGET("internalapi/quotes").respond({ hello: 'World' });

        ms.retrieveQuotes();
        $httpBackend.flush(); 
18
votes

I had the same problem as you guys. My solution was to add a '/' at the start of the URL-parameter of the .expectGET. Using your example:

$httpBackend.expectGET("/internalapi/quotes").respond({ hello: 'world'})

Best of luck