Flushing successful mock POST request using Jasmine does not execute the AngularJS success function

痴心易碎 提交于 2019-12-22 10:08:10

问题


This is my AngularJS post.js:

angular.module("PostPageApp", ["BaseApp"])
    .controller("MainCtrl", ["$http", "$window", "BaseService", function($http, $window, BaseService) {

        var self = this;

        self.add = function() {
            BaseService.add.post(self.post, function() {
                self.cerrorMessages = BaseService.cerrorMessages;
            });
        };
    }]);

This is base.js:

angular.module("BaseApp", [])
    .config(['$httpProvider', function($httpProvider) {
        $httpProvider.defaults.xsrfCookieName = 'csrftoken';
        $httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken';
    }])

    .config(['$locationProvider', function($locationProvider){
        $locationProvider.html5Mode(true);
    }])

    .factory("BaseService", ["$http", "$window", function($http, $window) {
        var self = this;
        self.posts = [];
        self.cerrorMessages = [];

        /* This function sets self.cerrorMessages. After calling this function,
         * you should do a callback to a function on the front-end which
         * sets cerrorMessage. */
        self.accessErrors = function(data) {
             self.cerrorMessages = [];
             for (prop in data) {
                 if (data.hasOwnProperty(prop)){
                     /* if (data[prop] != null && data[prop].constructor ==  Object) {
                         self.accessErrors(data[prop]);
                     }
                     else { */
                     self.cerrorMessages.push(data[prop]);
                     // }
                 }
             }
         };

        self.add = {
            post: function(post, callback) {
                $http.post("/posts/", post)
                .then(function(response) {
                    $window.location.href = "/";
                }, function(response) {
                    self.accessErrors(response.data);
                    callback();
                });
            }
         };

        return self;
    }]);

And this is my test_post.js:

describe('Controller: MainCtrl', function() {
    beforeEach(module('PostPageApp'));

    var ctrl, $loc;

    beforeEach(inject(function($controller, $location, $httpBackend, BaseService) {
        ctrl = $controller('MainCtrl');
        $loc = $location;
        mockBackend = $httpBackend;

        spyOn(BaseService, 'add').and.callThrough();
        baseService = BaseService;
    }));

    it('should have an add function', function() {
        expect(ctrl.add).toBeDefined();
    });

    it('should be able to create a post object', function() {
        $loc.path('/post');
        ctrl.post = {'post':'Test post'}
        mockBackend.expectPOST('/posts/', ctrl.post)
            .respond(201, {'post':'TestPost', 'posting': 1});

        ctrl.add();

        mockBackend.flush();
        expect(baseService.add).toHaveBeenCalled();
        expect($loc.path()).toEqual('/');
        expect(ctrl.cerrorMessages).toBeUndefined();
    });
});

Now, when I run karma start, it returns this:

Chromium 47.0.2526 (Ubuntu 0.0.0) Controller: MainCtrl should be able to create a valid post object FAILED
    Expected spy add to have been called.
        at Object.<anonymous> (/home/u/Documents/CMS/CMSApp/static/js/karma/tests/test_post.js:32:33)
    Expected '/post' to equal '/'.
        at Object.<anonymous> (/home/u/Documents/CMS/CMSApp/static/js/karma/tests/test_post.js:33:29)
Chromium 47.0.2526 (Ubuntu 0.0.0): Executed 3 of 3 (1 FAILED) (0 secs / 0.119 secChromium 47.0.2526 (Ubuntu 0.0.0): Executed 3 of 3 (1 FAILED) (0.163 secs / 0.119 secs)

As you can see, spy add was expected to be called, but since Expected spy add to have been called. was printed on the terminal, from my understanding, this means that it was not called, right?

Also, it also printed Expected '/post' to equal '/'. onto the terminal so this also means that the URL is still at '/post', correct?

Any idea why the URL did not change and spy add was not called?


回答1:


If you're testing the controller, only test the controller. That's why it's called a unit test. You should be mocking any external services.

describe('Controller: MainCtrl', function() {
    var ctrl, mockBaseService;

    beforeEach(function() {
        mockBaseService = {
            cerrorMessages: 'whatever',
            add: jasmine.createSpyObj('BaseService.add', ['post'])
        };

        mockBaseService.add.post.and.callFake(function(something, cb) {
            cb(); // execute the callback immediately
        });

        module('PostPageApp');

        inject(function($controller) {
            ctrl = $controller('MainCtrl', {
                BaseService: mockBaseService
            });
        });
    });

    it('add calls through to BaseService.add.post', function() {
        ctrl.post = 'something'; // just adding this because I can't see it anywhere else

        ctrl.add();

        expect(mockBaseService.add.post).toHaveBeenCalledWith(ctrl.post, jasmine.any(Function));
        expect(ctrl.cerrorMessages).toBe(mockBaseService.cerrorMessages);
    });
});


来源:https://stackoverflow.com/questions/34623322/flushing-successful-mock-post-request-using-jasmine-does-not-execute-the-angular

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!