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

时间:2014-08-05 21:14:11

标签: angularjs unit-testing angularjs-scope karma-runner karma-jasmine

如何在指令的单元测试中检查是否已调用$ 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");
  });
});

这总是会让我错误地说明范围。$ emit从未被调用过。 范围有问题吗?有人可以帮忙吗?

Plunker:http://plnkr.co/edit/AqhPwp?p=preview

2 个答案:

答案 0 :(得分:7)

你的指令创建了一个独立的范围,它正在调用$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");
  });
});

Fixed plunker here:)

答案 1 :(得分:0)

我不确定glepetre是如何工作的(不确定它确实如此)。对我来说没有。问题是指令在命令范围内运行registerNewReturnedType(Class c),因此它在内部创建的范围和$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(); })); 上模拟$new函数,所以不是在场景后面创建一个新的范围而是把事情弄得乱七八糟,它会自行返回!测试本身来了:

scope

指令中调用 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