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

element.click in directive unit test not assigning value to variables

我正在测试下面使用独立作用域的指令。我知道 triggerHandler 正在工作,但出于某种原因我一直收到错误

Expected undefined to equal '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);
        });

    });
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 分配给您的测试元素的范围。由于您使用的是独立作用域,因此您的指令将无法访问这些方法和属性。您可能应该将它们移动到服务并将它们注入指令。

它不是 "correct",但要测试理论,您可以将指令更改为:

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());
        });
    });
});

这不是您在生产代码中想要的东西,但我只是想演示不同范围之间的相互关系。