Getting “Unexpected request” error when running Karma unit test in an AngularJS app

6,564 views
Skip to first unread message

Gillian

unread,
Jul 7, 2014, 7:23:37 AM7/7/14
to ang...@googlegroups.com
I'm trying to write a unit test for a controller which fetches article details using $http service.


Controller:

     .controller('ArticleDetailCtrl',function($scope, Article, $routeParams, API_URL, ARTICLE_URL, $http, $sce){
   
    $scope.url = API_URL + ARTICLE_URL + '/' + $routeParams.articleId;
    
    $http.get($scope.url).then(function(response) {
    //console.log(response.data);
            $scope.heading = response.data.Headline;
            $scope.rawBody = response.data.Body;
            $scope.body = $sce.trustAsHtml($scope.rawBody);
            $scope.image = response.data.Assets[0].URL;
    });   
        });



Unit test:

    'use strict';
    
    describe('Controller: Article', function () {
    
        var scope,
            $httpBackend,
            articleEndpoint;
            
          
    
        // load the controller's module
        beforeEach(module('myApp'));
        
        
        describe('ArticleDetailCtrl', function () {
    
            var ArticleDetailCtrl,
                jsonObject,
                ArticleId = '123';
            
            // Initialize the controller and a mock scope
            beforeEach(inject(function ($controller, $rootScope, _$httpBackend_, Article, API_URL, ARTICLE_URL) {
                
                scope = $rootScope.$new();
                ArticleDetailCtrl = $controller('ArticleDetailCtrl', { $scope: scope });
                $httpBackend =  _$httpBackend_;
                articleEndpoint = API_URL + ARTICLE_URL + '/' + ArticleId;
                
                jsonObject = {
                    'Headline': 'Headline',
                    'Body': '<p>Body</p>',
                    'Assets': [
                        {
                            'URL': 'path/to/image/article1.jpg'
                        }
                    ]
                };
                
                $httpBackend.when('GET', articleEndpoint).respond(jsonObject);
            }));
            
            afterEach(function() {
                $httpBackend.verifyNoOutstandingExpectation();
                $httpBackend.verifyNoOutstandingRequest();
            });
    
            it('should fetch article details from the API', function () {
                //expect(scope.articles.length).toEqual(3);
                
                $httpBackend.expectGET(articleEndpoint);
                $httpBackend.flush();
            });
      
        });    
        
    });


But I keep on getting the following error:


Error: Unexpected request: GET http://localhost:3000/api/articles/undefined
Expected GET http://localhost:3000/api/articles/123
   at $httpBackend (/Users/gill/Documents/projects/angularjs-test/app/bower_components/angular-mocks/angular-mocks.js:1179)
   at sendReq (/Users/gill/Documents/projects/angularjs-test/app/bower_components/angular/angular.js:8181)
   at /Users/gill/Documents/projects/angularjs-test/app/bower_components/angular/angular.js:7921
   at /Users/gill/Documents/projects/angularjs-test/app/bower_components/angular/angular.js:11319
   at /Users/gill/Documents/projects/angularjs-test/app/bower_components/angular/angular.js:11405
   at /Users/gill/Documents/projects/angularjs-test/app/bower_components/angular/angular.js:12412
   at /Users/gill/Documents/projects/angularjs-test/app/bower_components/angular/angular.js:12224
   at /Users/gill/Documents/projects/angularjs-test/app/bower_components/angular-mocks/angular-mocks.js:1438
   at /Users/gill/Documents/projects/angularjs-test/test/spec/controllers/article.js:77
Error: Unsatisfied requests: GET http://localhost:3000/api/articles/123
   at /Users/gill/Documents/projects/angularjs-test/app/bower_components/angular-mocks/angular-mocks.js:1472
   at /Users/gill/Documents/projects/angularjs-test/test/spec/controllers/article.js:65


This is the first time am writing unit tests which I followed along by reading some tutorials. I don't know what am I doing wrong?

Charly Poly

unread,
Jul 7, 2014, 9:24:14 AM7/7/14
to ang...@googlegroups.com
Hi Gillian,

The reason is that your controller make the request at startup, when initialized.

So when you do 
  ArticleDetailCtrl = $controller('ArticleDetailCtrl', { $scope: scope });

in your beforeEach() block, the request start immediately.

So when you set your
  $httpBackend.expectGET(articleEndpoint);
the request is already gone.

Here what you need to do, put your 
  $httpBackend.expectGET(articleEndpoint);

before doing
  ArticleDetailCtrl = $controller('ArticleDetailCtrl', { $scope: scope });

You understand why ?

Regards,
Charly.

Gillian

unread,
Jul 8, 2014, 1:46:06 AM7/8/14
to ang...@googlegroups.com

Thanks Charly for your reply. 

I did exactly what you mentioned i.e. re-arranged the code so that it now looks like this (in beforeEach block):

     $httpBackend.when('GET', articleEndpoint).respond(jsonObject);

            
     ArticleDetailCtrl = $controller('ArticleDetailCtrl', { $scope: scope });




But some how am getting the same error. It shows id passed to api as undefined in the error:

    Error: Unexpected request: GET http://localhost:3000/api/articles/undefined



Am I still missing something?

Thanks
Gill

Charly Poly

unread,
Jul 8, 2014, 3:35:53 AM7/8/14
to ang...@googlegroups.com
Hi Gillian,

The ArticleID used in your test to call the endpoint is undefined, so the request made is  http://localhost:3000/api/articles/undefined
This is not what expect $httpBackend i guess.

I guess that $routeParams is undefined in your controller, you should try : 

$controller('ArticleDetailCtrl', { $scope: scope, $routeParams : { articleId : ArticleId } });

Regards,
Charly

On Monday, 7 July 2014 13:23:37 UTC+2, Gillian wrote:

Charly Poly

unread,
Jul 8, 2014, 3:38:11 AM7/8/14
to ang...@googlegroups.com
Sorry, I made a mistake

Replace "The ArticleID used in your test to call the endpoint is undefined, so the request made is  http://localhost:3000/api/articles/undefined
This is not what expect $httpBackend i guess." by :

The ArticleID used in your test to call the endpoint is '123', so $httpBackend expect a request to http://localhost:3000/api/articles/123

The problem is that your controller does not receive proper $routeParams, you should try to put : 

$controller('ArticleDetailCtrl', { $scope: scope, $routeParams : { articleId : ArticleId } });

Regards,
Charly.

On Monday, 7 July 2014 13:23:37 UTC+2, Gillian wrote:

Gillian

unread,
Jul 8, 2014, 3:48:34 AM7/8/14
to ang...@googlegroups.com

ok I did that and it did solved the undefined id problem. But now it shows another error:

Charly Poly

unread,
Jul 8, 2014, 4:30:52 AM7/8/14
to ang...@googlegroups.com
Yep,

You have to PUT   
 
$httpBackend.expectGET(articleEndpoint);

before

ArticleDetailCtrl = $controller('ArticleDetailCtrl', { $scope: scope });

not $httpBackend.when('GET', articleEndpoint).respond(jsonObject); before ArticleDetailCtrl = $controller('ArticleDetailCtrl', { $scope: scope });

You have to put your expectations before doing it :)

Do you understand ?

I suggest you to take 15min to read this : https://docs.angularjs.org/api/ngMock/service/$httpBackend
It will help you a lot !

Regards,
Charly


On Monday, 7 July 2014 13:23:37 UTC+2, Gillian wrote:

Gillian

unread,
Jul 8, 2014, 4:59:50 AM7/8/14
to ang...@googlegroups.com
ok great it did worked now! :)

I did went through the documentation of httpbackend which you provided but it didn't made much sense to me in terms of distinguishing when to use whenGET() and expectGET(). Am still confused about them.

but thanks anyways.

Gill

Charly Poly

unread,
Jul 8, 2014, 5:23:21 AM7/8/14
to ang...@googlegroups.com

When using Behavior Driven framework like Jasmine, you put expectations.
If the expectations fulfills, the tests pass.

whenGET(...) and expectGET(...) both allow you to change the behavior of $httpBackend for specific requests via exposing a respond(...) method.
The difference is that expectGET(...)  put an expectation on the request.
If the request does not occur, the test will fail with : "Error: Unsatisfied requests: ..."

You see the difference ?


Regards,
Charly.

On Monday, 7 July 2014 13:23:37 UTC+2, Gillian wrote:

Gillian

unread,
Jul 9, 2014, 6:52:00 AM7/9/14
to ang...@googlegroups.com

Thanks Charly, that was helpful.

Manish G

unread,
Aug 7, 2015, 1:20:12 AM8/7/15
to AngularJS
Hi Gillian,Charly

I am also facing similar issues.I have done as following:

beforeEach(inject(function($injector) {
     // Set up the mock http service responses
     $httpBackend = $injector.get('$httpBackend');    
     
     // backend definition common for all tests
     var url = 'xxxxx';
     var jsonObject={"userValid": true};
     $httpBackend.when('GET',url).respond(jsonObject);

     // Get hold of a scope (i.e. the root scope)
     $rootScope = $injector.get('$rootScope');
     // The $controller service is used to create instances of controllers
     var $controller = $injector.get('$controller');
     
     createController = function() {
       return $controller('loginCtrl', {'$scope' : $rootScope });
     };
   }));

afterEach(function() {
     $httpBackend.verifyNoOutstandingExpectation();
     $httpBackend.verifyNoOutstandingRequest();
   });
   
   it('should declare the user as valid', inject(function($controller) {
  $httpBackend.expectGET('xxxx);
    var controller = createController();
    $httpBackend.flush();     
    expect($rootScope.isUserValid).toEqual(true);
 }));

But I get error as:
Error: No pending request to flush !

Can you please tell me where am I going wrong?

Manish
Reply all
Reply to author
Forward
0 new messages