element.click在指令单元测试中没有为变量赋值

时间:2015-02-05 02:06:32

标签: angularjs unit-testing jasmine

我正在测试下面使用隔离范围的指令。我知道triggerHandler正在工作但由于某种原因我不断收到错误

  

预期未定义为等于'http://www.gravatar.com/avatar/12345?s=40&d=identicon'。

指令:

angular.module('pb.webSites.directives')
    .directive('pbOrganizationImagePicker', [ function () {

        return {
            restrict: "E",
            template: '<img data-ng-src="{{ imageSource }}" width="{{width}}" height="{{height}}" alt="Image Picker" class="img-rounded" />',
            scope: {
                fileId: '=pbFileId',
                defaultSrc: '@pbDefaultSrc',
                width: '@pbWidth',
                height: '@pbHeight'
            },
            controller: 'pbOrganizationImagePickerController',

            link: function (scope, element, attrs) {
                scope.$watch('defaultSrc', function (value) {
                    if (value !== undefined) {
                        scope.imageSource = value;
                    }
                });

                element.on('click', function () {
                    scope.pickImage().then(function (image) {
                        scope.imageSource = image.storageUrl;
                        scope.fileId = image.fileId;
                    }, function () {
                        console.log('Modal dismissed at: ' + new Date());
                    });
                });
            }
        };
    }]);

试验:

describe('pbOrganizationImagePicker', function () {

    beforeEach(module('pb.webSites.controllers'));
    beforeEach(module('pb.webSites.directives'));
    beforeEach(module('ui.router'));
    beforeEach(module('ui.bootstrap'));

    var compile;
    var scope;
    var mockModal = {};
    var image;

    beforeEach(inject(function ($compile, $rootScope) {
        compile = $compile
        scope = $rootScope.$new();
    }));


    beforeEach(inject(function ($q, $injector) {

        $httpBackend = $injector.get('$httpBackend');
        $httpBackend.whenGET('/app/webSites/directives/OrganizationImagePicker.html').respond(200, '');

        scopeObject = {
            profileImageUrl: 'http://www.gravatar.com/avatar/12345?s=40&d=identicon',
            profileImageId: 54634
        };

        scope.webSite = {
            profileImageId: 6436
        };

        scope.pickImage = function () {
            var defer = $q.defer();
            defer.resolve(scopeObject);
            return defer.promise;
        };

    }));

describe('element.click()', function () {

        beforeEach(function () {
            var html = angular.element('<pb-organization-image-picker data-pb-default-src="{{ webSite.profileImageUrl || \'/content/img/placeholder-lg.jpg\' }}" data-pb-file-id="webSite.profileImageId" data-pb-width="200"></pb-organization-image-picker>');
            element = compile(html)(scope);
            element.triggerHandler('click');
        });

        it('should assign value to scope variables', function () {
            scope.pickImage();
            scope.$digest();
            expect(scope.imageSource).toEqual(scopeObject.profileImageUrl);
            expect(scope.fileId).toEqual(scopeObject.profileImageId);
        });

    });

});

我也尝试将测试更改为以下内容,因为我在上面的测试中非常确定我正在尝试测试。但是在这里我得到的pickImage()从未被调用过。即使您没有看到问题,您认为哪种方法更适合测试?

describe('element.click()', function () {


        it('should assign value to scope variables', function () {
            element = compile(html)(scope);
            spyOn(scope, 'pickImage');
            element.triggerHandler('click');
            scope.$apply();
            //scope.pickImage();
            expect(scope.pickImage).toHaveBeenCalled();
            scope.$digest();
            expect(scope.imageSource).toEqual(scopeObject.profileImageUrl);
            expect(scope.fileId).toEqual(scopeObject.profileImageId);
        });

    });

1 个答案:

答案 0 :(得分:0)

element.on('click', function () {
    scope.$apply(function() {
       scope.pickImage().then(function (image) {
           scope.imageSource = image.storageUrl;
           scope.fileId = image.fileId;
       }, function () {
           console.log('Modal dismissed at: ' + new Date());
       });
    });
});

将您的点击处理程序中的代码包装在$ apply。

我怀疑真正的问题是你的指令使用了一个隔离范围,所以它实际上没有“pickImage()”方法,当你分配imageSource和fileId时,你将它们放在指令范围内,而不是您的测试尝试验证的范围(父范围)。

您的测试将pickImage()和webSite分配给测试元素的范围。由于您使用隔离范围,因此您的指令将无法访问这些方法和属性。您应该将它们移动到服务中并将它们注入到指令中。

这不是“正确”,但为了测试理论,您可以将指令更改为:

element.on('click', function () {
    scope.$apply(function(){
        scope.$parent.pickImage().then(function (image) {
            scope.$parent.imageSource = image.storageUrl;
            scope.$parent.fileId = image.fileId;
        }, function () {
            console.log('Modal dismissed at: ' + new Date());
        });
    });
});

这不是你想要的生产代码,但我只想说明不同的范围是如何相互关联的。