最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - TypeError: Cannot read property 'then' of undefined in testing AngularJS controller with Karma - St

programmeradmin4浏览0评论

I am trying to write unit tests for a controller that gets a promise from a service, but in Jasmine I am getting:

TypeError: Cannot read property 'then' of undefined

In controller I call .then() on returned promise from service.

Can anybody help please? I am surely missing something obvious.

Here is a plunk:

'use strict';

describe('Language controller', function() {
    var scope, translationService, createController;

    beforeEach(function() {
        var mockTranslationService = {};
        module('dictApp', function($provide) {
            $provide.value('translationService', mockTranslationService);
        });

        inject(function($q) {
            mockTranslationService.languages = [
                {
                    name: 'slovak'
                },
                {
                    name: 'czech'
                }
            ];

            mockTranslationService.languagesWithWords = [{
                name: 'slovak',
                words: [{
                    key: 'Car',
                    translation: 'Auto',
                    createdOn: 0
                }, {
                    key: 'Flower',
                    translation: 'Kvet',
                    createdOn: 0
                }]
            }, {
                name: 'czech',
                words: {
                    key: 'Plaza',
                    translation: 'Namesti',
                    createdOn: 0
                }
            }];

            mockTranslationService.getLanguages = function() {
                var deferred = $q.defer();

                deferred.resolve(this.languages);
                return deferred.promise;
            };
        });
    });

    beforeEach(inject(function($controller, $rootScope, _translationService_) {
        scope = $rootScope.$new();
        translationService = _translationService_;
        createController = function () {
            return $controller('LanguageCtrl',
                    {$scope: scope, translationService: translationService});
        };
        scope.$digest();
    }));

    it('should get the language array', function() {
        spyOn(translationService, 'getLanguages');
        createController();
        expect(translationService.getLanguages).toHaveBeenCalled();
    });
});

and this is the controller:

   dictControllers.controller('LanguageCtrl', ['$scope', 'translationService', function($scope, translationService){


        $scope.getLanguages = function() {
            translationService.getLanguages().then(function(){
                $scope.languages = translationService.languages;
            });
        };

        $scope.getLanguages();

        $scope.getWords = function(language) {
            translationService.getWords(language);
        };


        $scope.newWord = {};

        $scope.addWord = function(language) {
            translationService.addWord($scope.newWord, language);
            $scope.newWord = {};
            };

    }]);

I am trying to write unit tests for a controller that gets a promise from a service, but in Jasmine I am getting:

TypeError: Cannot read property 'then' of undefined

In controller I call .then() on returned promise from service.

Can anybody help please? I am surely missing something obvious.

Here is a plunk: http://plnkr.co/edit/vJOopys7pWTrTQ2vLgXS?p=preview

'use strict';

describe('Language controller', function() {
    var scope, translationService, createController;

    beforeEach(function() {
        var mockTranslationService = {};
        module('dictApp', function($provide) {
            $provide.value('translationService', mockTranslationService);
        });

        inject(function($q) {
            mockTranslationService.languages = [
                {
                    name: 'slovak'
                },
                {
                    name: 'czech'
                }
            ];

            mockTranslationService.languagesWithWords = [{
                name: 'slovak',
                words: [{
                    key: 'Car',
                    translation: 'Auto',
                    createdOn: 0
                }, {
                    key: 'Flower',
                    translation: 'Kvet',
                    createdOn: 0
                }]
            }, {
                name: 'czech',
                words: {
                    key: 'Plaza',
                    translation: 'Namesti',
                    createdOn: 0
                }
            }];

            mockTranslationService.getLanguages = function() {
                var deferred = $q.defer();

                deferred.resolve(this.languages);
                return deferred.promise;
            };
        });
    });

    beforeEach(inject(function($controller, $rootScope, _translationService_) {
        scope = $rootScope.$new();
        translationService = _translationService_;
        createController = function () {
            return $controller('LanguageCtrl',
                    {$scope: scope, translationService: translationService});
        };
        scope.$digest();
    }));

    it('should get the language array', function() {
        spyOn(translationService, 'getLanguages');
        createController();
        expect(translationService.getLanguages).toHaveBeenCalled();
    });
});

and this is the controller:

   dictControllers.controller('LanguageCtrl', ['$scope', 'translationService', function($scope, translationService){


        $scope.getLanguages = function() {
            translationService.getLanguages().then(function(){
                $scope.languages = translationService.languages;
            });
        };

        $scope.getLanguages();

        $scope.getWords = function(language) {
            translationService.getWords(language);
        };


        $scope.newWord = {};

        $scope.addWord = function(language) {
            translationService.addWord($scope.newWord, language);
            $scope.newWord = {};
            };

    }]);
Share Improve this question edited Jun 7, 2015 at 17:24 Ondrej Slinták 32k21 gold badges96 silver badges127 bronze badges asked Feb 9, 2015 at 9:58 Július RetzerJúlius Retzer 1,0751 gold badge11 silver badges25 bronze badges
Add a ment  | 

1 Answer 1

Reset to default 4

Use spyOn(mockTranslationService, 'getLanguages').and.returnValue(deferred.promise); instead. It also makes more sense to resolve the promise after the getLocations() has been called rather than before getLocations() returns the promise. You should also check the languages.

inject(function($q) {
    deferred = $q.defer();

    mockTranslationService.languages =  [
        {
            name: 'slovak'
        },
        {
            name: 'czech'
        }
    ];

    mockTranslationService.languagesWithWords = [{
        name: 'slovak',
        words: [{
            key: 'Car',
            translation: 'Auto',
            createdOn: 0
        }, {
            key: 'Flower',
            translation: 'Kvet',
            createdOn: 0
        }]
    }, {
        name: 'czech',
        words: {
            key: 'Plaza',
            translation: 'Namesti',
            createdOn: 0
        }
    }];

    mockTranslationService.getLanguages = function () {
    };

    spyOn(mockTranslationService, 'getLanguages').and.returnValue(deferred.promise);

});

it('should get the language array', function() {
    createController();

    deferred.resolve();
    scope.$digest();

    expect(translationService.getLanguages).toHaveBeenCalled();
    expect(scope.languages).toEqual(translationService.languages);
});

Plunkr

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论