Cognitronic
Cognitronic

Reputation: 1436

Jasmine test fails making $httpbackend call due to angular mock receiving incorrect json format

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

Answers (1)

Bengt
Bengt

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

Related Questions