Reputation: 1436
I'm having trouble writing what I think should be a simple unit test. I have the following controller:
(function(){ 'use strict';
var LoginController = function($scope, $state, RestService){
var _user = {};
var _message = 'hello';
var _login = function(username, password){
var _success = function(response){
_message = response.success;
_user = response.user;
};
var _error = function(response){
_message = response.success;
};
RestService.postData('/api/login', {username: username, password: password}, _success, _error, {showLoader: true});
};
$scope.model = {
login: _login,
user: _user,
message: _message
};
};
angular.module('danny').controller('LoginController',['$scope', '$state', 'RestService',LoginController]);
})();
Here is the spec:
describe('LoginController', function(){
var scope, $httpBackend, controller, restService;
beforeEach(function(){
module('danny');
});
beforeEach(inject(function(_$controller_, _$rootScope_, _$httpBackend_, _RestService_){
$httpBackend = _$httpBackend_;
restService = _RestService_;
scope = _$rootScope_.$new();
controller = _$controller_('LoginController', {
$scope: scope,
RestService: restService
});
}));
afterEach(function() {
$httpBackend.verifyNoOutstandingExpectation();
$httpBackend.verifyNoOutstandingRequest();
});
describe('successfully logging in', function(){
it('should redirect to /blog when authenticated', function(){
var user = {"username":"[email protected]", "password":"test"};
expect(user.username).toEqual('[email protected]');
$httpBackend.expectPOST('/api/login', user);
scope.model.login(user);
$httpBackend.flush();
expect(scope.model.user).not.toBe(undefined);
});
});
});
When I run the test the karma output is this:
C:\Program Files (x86)\JetBrains\WebStorm 9.0.1\bin\runnerw.exe" C:\nodejs\node.exe c:\Users\danny_000\AppData\Roaming\npm\node_modules\grunt-cli\bin\grunt test
Running "karma:development" (karma) task
INFO [karma]: Karma v0.12.16 server started at http://localhost:9876/
INFO [launcher]: Starting browser PhantomJS
INFO [PhantomJS 1.9.8 (Windows 8)]: Connected on socket SWVDLzehlqv2Z3J0C2Av with id 62852294
PhantomJS 1.9.8 (Windows 8): Executed 0 of 1 SUCCESS (0 secs / 0 secs)
PhantomJS 1.9.8 (Windows 8) LoginController successfully logging in should redirect to /blog when authenticated FAILED
SyntaxError: Unable to parse JSON string
at fromJson (c:/Projects/dannyschreiber/public/vendors/angular/angular.js:1066)
at c:/Projects/dannyschreiber/public/vendors/angular-mocks/angular-mocks.js:1646
at $httpBackend (c:/Projects/dannyschreiber/public/vendors/angular-mocks/angular-mocks.js:1194)
at sendReq (c:/Projects/dannyschreiber/public/vendors/angular/angular.js:9616)
at c:/Projects/dannyschreiber/public/vendors/angular/angular.js:9331
at processQueue (c:/Projects/dannyschreiber/public/vendors/angular/angular.js:13171)
at c:/Projects/dannyschreiber/public/vendors/angular/angular.js:13187
at c:/Projects/dannyschreiber/public/vendors/angular/angular.js:14384
at c:/Projects/dannyschreiber/public/vendors/angular/angular.js:14200
at c:/Projects/dannyschreiber/public/vendors/angular-mocks/angular-mocks.js:1525
at c:/Projects/dannyschreiber/public/src/core/security/login-controller.spec.js:6
Error: [$rootScope:inprog] $digest already in progress
http://errors.angularjs.org/1.3.9/$rootScope/inprog?p0=%24digest
at beginPhase (c:/Projects/dannyschreiber/public/vendors/angular/angular.js:14738)
at c:/Projects/dannyschreiber/public/vendors/angular/angular.js:14180
at c:/Projects/dannyschreiber/public/vendors/angular-mocks/angular-mocks.js:1557
at c:/Projects/dannyschreiber/public/src/core/security/login-controller.spec.js:6
PhantomJS 1.9.8 (Windows 8): Executed 1 of 1 (1 FAILED) (0 secs / 0.031 secs)
PhantomJS 1.9.8 (Windows 8): Executed 1 of 1 (1 FAILED) ERROR (0.028 secs / 0.031 secs)
Warning: Task "karma:development" failed. Use --force to continue.
I ended up commenting out the angular-mocks line that was causing the error (line# 1646), and see that for some reason, somewhere, the data i'm sending is being formatted incorrectly. This is the error output now:
Running "karma:development" (karma) task
INFO [karma]: Karma v0.12.16 server started at http://localhost:9876/
INFO [launcher]: Starting browser PhantomJS
INFO [PhantomJS 1.9.8 (Windows 8)]: Connected on socket xGP0gRaa3WEdNVw1DrQm with id 89049214
PhantomJS 1.9.8 (Windows 8): Executed 0 of 1 SUCCESS (0 secs / 0 secs)
PhantomJS 1.9.8 (Windows 8) LoginController successfully logging in should redirect to /blog when authenticated FAILED
Error: Expected POST /api/login with different data
EXPECTED: {"username":"[email protected]","password":"test"}
GOT: username=danny%40ravenartmedia.com&password=test
at $httpBackend (c:/Projects/dannyschreiber/public/vendors/angular-mocks/angular-mocks.js:1196)
at sendReq (c:/Projects/dannyschreiber/public/vendors/angular/angular.js:9616)
at c:/Projects/dannyschreiber/public/vendors/angular/angular.js:9331
at processQueue (c:/Projects/dannyschreiber/public/vendors/angular/angular.js:13171)
at c:/Projects/dannyschreiber/public/vendors/angular/angular.js:13187
at c:/Projects/dannyschreiber/public/vendors/angular/angular.js:14384
at c:/Projects/dannyschreiber/public/vendors/angular/angular.js:14200
at c:/Projects/dannyschreiber/public/vendors/angular-mocks/angular-mocks.js:1525
at c:/Projects/dannyschreiber/public/src/core/security/login-controller.spec.js:6
Error: [$rootScope:inprog] $digest already in progress
http://errors.angularjs.org/1.3.9/$rootScope/inprog?p0=%24digest
at beginPhase (c:/Projects/dannyschreiber/public/vendors/angular/angular.js:14738)
at c:/Projects/dannyschreiber/public/vendors/angular/angular.js:14180
at c:/Projects/dannyschreiber/public/vendors/angular-mocks/angular-mocks.js:1557
at c:/Projects/dannyschreiber/public/src/core/security/login-controller.spec.js:6
PhantomJS 1.9.8 (Windows 8): Executed 1 of 1 (1 FAILED) (0 secs / 0.032 secs)
PhantomJS 1.9.8 (Windows 8): Executed 1 of 1 (1 FAILED) ERROR (0.029 secs / 0.032 secs)
Warning: Task "karma:development" failed. Use --force to continue.
The key piece of info being:
Error: Expected POST /api/login with different data
EXPECTED: {"username":"[email protected]","password":"test"}
GOT: username=danny%40ravenartmedia.com&password=test
Why is my json being altered?
Here is the postData function from the RestService, which I've used in many projects without issues:
var postData = function(url, params, data, successFunction, errorFunction, config) {
if(config && config.hasOwnProperty('showLoader')){
$rootScope.showLoader = config.showLoader;
}
$http({
method: 'POST',
url: url,
params: params,
data: data,
cache: false
})
.success(function(data, status, headers, config) {
$rootScope.showLoader = false;
if (successFunction === undefined) {
_defaultSuccessFunction(data, status, headers, config);
}
else {
successFunction(data, status, headers, config);
}
})
.error(function (data, status, headers, config) {
$rootScope.showLoader = false;
if (status !== 0){
_processError(data, status, headers, config, errorMsg, errorFunction);
}
});
};
Edit: I was able to hook all of this up in plnkr: http://plnkr.co/edit/lJTx0ldR9nEnlYbU5pJd and the test passes....but the exact same code gives me the error I'm referring to in this post. I'm running v. 1.3.9 of both Angular and Angular-Mocks.
Upvotes: 2
Views: 1433
Reputation: 4038
Your helper method is defined as function(url, params, data, successFunction, errorFunction, config)
, where data
is the third parameter.
Compare this to your invocation:
RestService.postData('/api/login', null, null, {username: username, password: password}, _success, 'Invalid login, please try again', _error, {showLoader: true});
Here you pass your data as the fourth parameter. So I think you want to remove one of the null
values. Unfortunately Javscript does not warn about wrong amounts of parameters (just ignores them).
Edit:
Meanwhile you have edited your question, however your invocation of postData
is probably still incorrect.
I've prepared a fiddle using your code: http://jsfiddle.net/qwteyak3/1/
The first invocation of postData
gets the data as the params
parameter. This tells $http
to send it as form data. The second invocation passes it in the data
field. $http
checks data, finds an object and then sends it as a JSON-body.
When running the fiddle, Chrome's network tab shows me a request to http://fiddle.jshell.net/echo/json?password=123&username=test
for the first invocation and http://fiddle.jshell.net/echo/json
(with data in body) for the second.
I hope this helps.
Upvotes: 1