57

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 :)

Simon Lomax
  • 8,714
  • 8
  • 42
  • 75
  • 1
    http://stackoverflow.com/questions/14761045/jasmine-tests-angularjs-directives-with-templateurl (I didn't flag as duplicate, because the problems seem different to an extent). – Ricky Mutschlechner Aug 09 '13 at 13:31
  • 1
    Please remember to mark your question as resolved, based on your edit it looks like it has been fixed. :) – Chris Foster Aug 02 '14 at 21:59
  • 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 Feb 29 '16 at 04:33
  • 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 Jul 22 '16 at 15:54

2 Answers2

56

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(); 
Jonathan Palumbo
  • 6,851
  • 1
  • 29
  • 40
  • 3
    Unfortunately, even if I add ```$httpBackend.expectGET("internalapi/quotes");```, I get the same error. Any other ideas? – Simon Lomax Aug 09 '13 at 14:21
  • That should work. Just a guess but try injecting the `$httpBackend` directly into your test. I will update the post to show this. – Jonathan Palumbo Aug 09 '13 at 14:27
  • No, same thing. I've looked at lots of examples and I agree, I appear to be doing it correctly, but no joy unfortunately. – Simon Lomax Aug 09 '13 at 14:38
  • 5
    Oh dear, I feel very stupid. I've worked it out now, it was simple. I had configured ```Restangular``` thus ```RestangularProvider.setBaseUrl("/internalapi");``` and expected a call to```internalapi/quotes```. Notice the missing slash. My bad. Thanks for your help. – Simon Lomax Aug 09 '13 at 14:53
  • 1
    Its happens, at least one of us noticed it. – Jonathan Palumbo Aug 09 '13 at 15:09
  • Hi, is there a way to make unit test on $resource working using absolute path? I call the $resource in my service using an absolute path because is crossorigin call. I'm trying this for days but the result is the same "Unexpected request: GET". Did anyone succeed, I see that is working correctly with simple $http but not with $resource? Thanks! – Pufi Jun 14 '15 at 06:11
  • @SimonLomax Almost 7 years later I have to thank you. Just spent hours learning all of the ins and outs of $httpBackend, and it turns out I had a trailing slash before my query param in the URL :facepalm: – Josh May 01 '20 at 18:09
18

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

gronnbeck
  • 993
  • 1
  • 7
  • 16