Angular.js: ngMock $httpBackend should keep a list of the received calls to debug tests

Created on 29 Dec 2014  路  19Comments  路  Source: angular/angular.js

Hi, I'm not sure if this is already possible, but I haven't found a way yet. In my unit tests I'm using $httpBacked to expect calls to an API. When the expectations fail, it would be useful to see a list of the actual calls, to see you .expectGET('..') failed because your code is calling the wrong url, or is sending the wrong data.

ngMock investigation

Most helpful comment

Agree.

Error: Unflushed requests: 2
    at Function.$httpBackend.verifyNoOutstandingRequest

isn't very informative. I'd like to know what the unflushed requests are.

All 19 comments

@fabiosussetto did you try, in your test:

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

AFAIK it should show failed expectations / additional requests. Docs here: https://docs.angularjs.org/api/ngMock/service/$httpBackend

@pkozlowski-opensource yes indeed, and my test fails with this stacktrace:

Error: No pending request to flush !
        at Function.$httpBackend.flush (/Users/fabio/Code/waypoints/web_client/bower_components/angular-mocks/angular-mocks.js:1526:34)
        at Object.<anonymous> (/Users/fabio/Code/waypoints/web_client/src/tests/eventModelSpec.js:100:22)
    Error: Unsatisfied requests: PUT http://localhost:8000/be/rest/timelines/1/events/2
        at Function.$httpBackend.verifyNoOutstandingExpectation (/Users/fabio/Code/waypoints/web_client/bower_components/angular-mocks/angular-mocks.js:1559:13)
        at Object.<anonymous> (/Users/fabio/Code/waypoints/web_client/src/tests/eventModelSpec.js:24:22)

And my test was failing because I was calling the wrong url (specifically I was using the wrong id in the url) from my code under testing. I'd love to have a way to immediately see that the expected url was not hit, and instead the wrong url was.

I'd love to have a way to immediately see that the expected url was not hit, and instead the wrong url was.

Not sure what you are proposing, exactly, I'm afraid. Which API call you would expect to fail "immediately"?

Sorry probably I haven't been very clear. Given my $httpBacked.expectGET() failed because I was calling the wrong url, I'd like to be able to do something along these lines:

console.log($httpBacked.calls)

and see a list of API calls received by the mocked http backend. That way I could see that I was calling the wrong URL.
At the moment I don't see a way to inspect the API calls I'm actually making during my unit tests.

From the failure message, I only know that for sure I didn't call the URL I was expecting to call, but then I'm in the dark, I don't know if I haven't call the API at all, or if I called it with the wrong URL (or wrong data, or headers).

@fabiosussetto are you _sure_ that you've got this line in your test: $httpBackend.verifyNoOutstandingRequest();? This is the one that should give you a list of unexpected requests...

http://plnkr.co/edit/zOSCORd25oAtccT6MZ6w?p=catalogue This is my actual test code. Here I'm expecting to call the wrong url, the failure I get is:

Error: No pending request to flush !
        at Function.$httpBackend.flush (/Users/fabio/Code/waypoints/web_client/bower_components/angular-mocks/angular-mocks.js:1526:34)
        at Object.<anonymous> (/Users/fabio/Code/waypoints/web_client/src/tests/eventModelSpec.js:48:22)
    Error: Unsatisfied requests: GET http://localhost:8000/be/rest/timelines/2/timeline
        at Function.$httpBackend.verifyNoOutstandingExpectation (/Users/fabio/Code/waypoints/web_client/bower_components/angular-mocks/angular-mocks.js:1559:13)
        at Object.<anonymous> (/Users/fabio/Code/waypoints/web_client/src/tests/eventModelSpec.js:24:22)

Which is fine, I know that I'm not doing a GET to http://localhost:8000/be/rest/timelines/2/timeline. The problem is that I am actually doing a GET to http://localhost:8000/be/rest/timelines/1/timeline instead (notice the wrong id the the url), but I don't see that in the error message. Am I doing something wrong in my test perhaps? If I change line 46 of my plunker to expect the right url (so http://localhost:8000/be/rest/timelines/1/timeline), then my test passes.

Btw I'm on angular 1.3.8.

Thanks a lot!

I just tried to swap the two calls to be:

$httpBackend.verifyNoOutstandingRequest();
$httpBackend.verifyNoOutstandingExpectation();

so that it first checks for outstanding requests, but I get the same error message.

~Another update: I tried to remove my $httpBackend.flush(); and now I get the correct error message:
Error: Unsatisfied requests: PUT http://localhost:8000/be/rest/timelines/1/events/2
Then am I using flush() in the wrong way?~

Sorry ignore the previous lines in this comment, it's not true, I get the same error message without the error "No pending request to flush !"

@fabiosussetto your plunker is not available (pasted a wrong link?) but I was just trying to replicate your issue and it seems to be correctly reporting both URLs on my end: http://plnkr.co/edit/IndYfHohO3KVznUEHdhL?p=preview

Error: Unexpected request: GET http://fooo.com Expected GET http://foo.com

Could you please share a plunker that shows your exact scenario?

@pkozlowski-opensource try to click on the scripts.js file in my plunker and you should see my code, it's not a working example as it depends on a lot of other code, so I pasted just the spec.
Thanks for your example, I'm gonna have a look and see if it's because I'm doing something dodgy.

@fabiosussetto yeh, please provide a reduced code example that doesn't depend on any other code - otherwise it is next to impossible to progress on a given issue.

@pkozlowski-opensource I understand, I'll post something more useful asap. Enjoy New Year's Eve tomorrow night :)

I totally support more details when failing $httpBackend expectations.

Ex. the cryptic "Error: Unflushed requests: 4" : Why can't we access the unflushed requests ? At last their url to give us a lead ?

+1 for accessing unflushed requests

With v1.2.25, the installation of an $exceptionHandler can prevent $httpBackend's "Unexpected request ..." exception from propagating out to Jasmine. It doesn't seem to affect other $httpBackend-thrown exceptions.

+1 for accessing unflushed requests, stacktrace as well.

Agree.

Error: Unflushed requests: 2
    at Function.$httpBackend.verifyNoOutstandingRequest

isn't very informative. I'd like to know what the unflushed requests are.

+1.
In my case, I'm testing a factory depending on ngResource using a cache and want to test if the same request is done twice, and I have no way to know wich one is failing.

server.expectGET('/data').respond([item]);
server.expectGET('/data').respond([item]);

var resource = new resource('/data');

resource.query();
resource.invalidateCache();
resource.query();

And this is what I get

Error: Unsatisfied requests: GET /data
    at Function.$httpBackend.verifyNoOutstandingExpectation (public/js/angular.js:2290:13)
    at Function.$httpBackend.flush (public/js/angular.js:2269:18)
    at Object.<anonymous> (tests/frontend/share/cached-resource.factory.test.js:52:16)

I'm quite new to ngMock and $httpBackend so probably there is a better way to test this. However, I think $httpBackend should provide an error message with more information

We just merged a commit into master / 1.6 that will make the following change:

Before this change:

Unflushed requests: 1

After this change:

Unflushed requests: 1
  GET /some

This doesn't cover all cases reported in this issue, only the most requested one: https://github.com/angular/angular.js/issues/10596#issuecomment-227725855

Stack Traces for unexpected requests are tracked here: https://github.com/angular/angular.js/issues/12231

Was this page helpful?
0 / 5 - 0 ratings