如何在指令中对 $emit 进行单元测试?

4

如何在指令的单元测试中检查$emit是否被调用?

我的指令非常简单(为了说明):

angular.module('plunker', [])
.directive('uiList', [function () { 
    return {
        scope: {
            lengthModel: '=uiList',
        },
        link: function (scope, elm, attrs) {
            scope.$watch('lengthModel', function (newVal) {
                        scope.$emit('yolo');
            });
        }
    }
}])

每当uiList属性改变时,它都会触发该事件。 以下是我的单元测试代码:
describe('Testing $emit in directive', function() {
  var scope;
  var element;


  //you need to indicate your module in a test
    beforeEach(function () {
        module('plunker');
        inject(function ($rootScope, $compile) {
            scope = $rootScope.$new();
            scope.row= 1;
            spyOn(scope,'$emit');
        element = angular.element('<ul id="rows" ui-list="row">');
        $compile(element)(scope);
        });
    });

  it('should emit', function() {

    scope.$digest();
    scope.row = 2;
    scope.$digest();
    expect(scope.$emit).toHaveBeenCalledWith("yolo");
  });
});

这总是会给我一个错误,指出 scope.$emit 从未被调用过。 scope 有问题吗?请有人帮忙吗?
Plunker: http://plnkr.co/edit/AqhPwp?p=preview
2个回答

6
您的指令创建了一个隔离作用域,调用了$emit,所以您需要监视它 ;)
describe('Testing $emit in directive', function() {
  var scope;
  var element;
  var elementScope;

  beforeEach(module('plunker'));

  beforeEach(inject(function($rootScope, $compile) {
      scope = $rootScope.$new();
      scope.row = 1;
      element = angular.element('<ul id="rows" ui-list="row">');
      $compile(element)(scope);
      scope.$digest();
      elementScope = element.scope();
  }));

  it('should emit', function() {
    // arrange
    spyOn(elementScope, '$emit');

    // act
    scope.$apply(function() {
      scope.row = 2;
    });

    // assert
    expect(elementScope.$emit).toHaveBeenCalledWith("yolo");
  });
});

这里是已修复的 Plunker :)


在一个不错的回答中讽刺性地使用“yolo”一词,点个赞。 - Andrew Luhring

0

我不确定glepetre是如何做到的(实际上我也不确定他是否做到了)。对我来说,它没有起作用。问题在于指令在传入作用域上运行$new,因此它在内部创建的作用域和element.scope()是不同的。您可以检查它们的$id字段。因此,窥视从element.scope()获得的作用域并没有帮助。我遇到了类似的问题,不得不做一点小技巧才能使它起作用。

这里是我的测试:

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

        scope.$apply(function () {
            scope.field = null;
            scope.name = 'nolength';
        });

        spyOn(scope, '$new').and.returnValue(scope);
        spyOn(scope, '$emit');

        var element = angular.element('<my-directive name="name" field="field" title="\'Title\'" ></my-directive>');
        noLengthValidation = $compile(element)(scope);

        scope.$apply();
        elementScope = element.scope();
    }));

所以诀窍就是在scope上模拟$new函数,这样它不会在幕后创建一个新的作用域并搞乱事情,而是返回自身!下面是测试本身:

    it('The directive should not react on string length if no max-chars attribute presented', function () {
        scope.$apply();
        noLengthValidation.isolateScope().field = 'fieldisssssssveeeeerryyyyyylooooooonnnngggggggggggggggggggggggggggg';
        scope.$apply();
        expect(scope.$emit).toHaveBeenCalledWith('ON_MORE_AWASOME_EVENT', 'nolength');
    });

还有指令中调用$emit的部分。以防万一:

        function validate() {
            scope.validate = 1;
            if (scope.field) {
                if (!isValid()) {
                    scope.$emit('ON_AWASOME_EVENT', {code : scope.name, text : 'Field ' + scope.title + '  is feels bad'});
                } else {
                    scope.$emit('ON_MORE_AWASOME_EVENT', scope.name);
                }

            }
        }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接