cvk10 cvk10 - 18 days ago 5
AngularJS Question

AngularJS error: Unexpected request (No more requests expected)

In my AngularJS application, I'm having trouble figuring out how to unit test that the execution of a then promise changes a location.url. I have a function, login, that calls a service, AuthenticationService. It returns the promise, and the execution of the then promise changes the location.url.

This is the controller AuthCtrl:

angular
.module('bloc1App')
.controller('AuthCtrl', ['$scope', '$http','$location', 'AuthenticationService',
function($scope, $http, $location, AuthenticationService) {

this.AuthenticationService = AuthenticationService;
var self = this;

$scope.login = function(username, password){
self.AuthenticationService
.login(username, password)
.then(function(){
$location.url('/tasks');
});
};
}
]);


This is my attempt at the unit test:

describe('Controller: AuthCtrl', function () {

var scope,
location,
route,
q,
rootScope,
AuthCtrl;

beforeEach(module('bloc1App'));

beforeEach(inject(function($controller, $rootScope, $location, $route, $q) {
scope = $rootScope.$new();
q = $q;
rootScope = $rootScope;
location = $location;
route = $route;

AuthCtrl = $controller('AuthCtrl', {
$scope: scope,
$route: route,
$location: location
});

}));

it('login should redirect user to tasks view', function(){
var deferred = q.defer();
spyOn(AuthCtrl.AuthenticationService, 'login').andReturn(deferred.promise);
spyOn(location, 'url');
scope.login('foo', 'foo');
deferred.resolve();
scope.$apply();
expect(location.url).toHaveBeenCalledWith('/tasks');
});
});


When I run this test, I get this error. I get the same error if I use rootScope.$apply() instead:

Error: Unexpected request: GET views/AuthView.html
No more request expected


When I take out scope.$apply(), I get this error:

Expected spy url to have been called with [ '/tasks' ] but it was never called.


Any ideas on how to fix this? This is the first time that I'm unit testing a promise, and I'm probably conceptually misunderstanding how to do this.

Thank you in advance for your help.

Answer

When you're unit-testing with AngularJS, you're actually using mock services from ngMock module instead of real services. In this case, your error probably comes form $httpBackend mock, which has to be "primed" first, if you're expecting the tested units to use $http to send real requests. (I don't see your code using $http anywhere, so I'm guessing there's a part you're not showing here.)

Basically, you need to tell the $httpBackend mock that you're expecting a particular request using $httpBackend.when (or you can use $httpBackend.expect, if you want the mock to check that the request was really called) and what response should be returned.

So, your error has nothing to do with promises and everything to do with testing units that connect to server.