2

简短版本:我有一个使用“新范围”(即scope:true不是隔离范围)的指令,当我与应用程序交互时,它似乎工作得很好,但似乎没有更新scope可观察的在单元测试中的方式。为什么在单元测试中无法观察到指令范围的更改?field

Plunker 中的示例:http ://plnkr.co/edit/gpzHsX?p=preview

这是指令:

angular.module('app').directive('ngxBlurry', [
  function() {
    return {
      restrict:'C',
      replace:false,
      scope:true,
      link: function(scope, element, attrs) {
        element.bind('blur', function() {
          var val = element.val();
          scope.$apply(function(scope) {
            scope.field = val;
          });
        });

        scope.$watch('field', function(n, o) {
          if (n !== o) {
            scope.fields[n] = scope.fields[o];
            delete scope.fields[o];
          }
        });
      }
    };
  }
]);

它的使用大致如下:

<div ng-controller="FooContoller">
  <div ng-repeat="(field, value) in fields">
    <input value="{{field}}" type="text" class="ngx-blurry"/>
    <strong>"field" is &laquo;{{field}}&raquo;</strong>
  </div>
</div>

假设这fields看起来大约像:

$scope.fields = {
  'foo':true,
  'bar':true,
  'baz':true,
  '':true
};

这是单元测试:

describe('ngxBlurry', function() {
  var scope,
      element,
      template = '<input value="{{field}}" type="text" class="ngx-blurry"/>';

  beforeEach(module('app'));
  beforeEach(inject(function($rootScope, $compile) {
    scope = $rootScope.$new();
    scope.fields = {'foo':true, '':true};
    scope.field = '';

    element = $compile(template)(scope);
  }));

  it('defers update until after blur', function() {
    spyOn(scope, '$apply');

    element.val('baz');
    element.triggerHandler('blur');

    // true:
    expect(scope.$apply).toHaveBeenCalled();
    // false!?
    expect(scope.field).toBe('baz');

    scope.$digest();
    // still false:
    expect(scope.field).toBe('baz');

    element.scope().$digest();
    // *still* false:
    expect(scope.field).toBe('baz');
    // also false:
    expect(element.scope().field).toBe('baz');
  });
});

现在,在与应用程序交互时:

  1. 我可以输入input并且对中的键的任何更新$scope.fields都被推迟到该字段上的模糊事件。
  2. 在测试中,Jasmine 间谍报告调用$apply正在发生,但是......
  3. ...应该在上下文中执行的函数$apply(显然)没有被调用。
  4. ...也不会$watch调用表达式。

正在运行的应用程序上下文中的指令本身似乎运行得很好,但我似乎找不到任何理由无法通过单元测试观察到变化。

除非重新设计指令(例如,使用隔离范围和$emit事件):这里有什么我遗漏的吗?我应该对指令进行一些更改吗?或者一些技巧可以在单元测试中观察到这些变化?

4

1 回答 1

3

简而言之:不要忘记.andCallThrough()间谍。

对指令本身没有任何改变,测试的工作版本需要是:

// everything about the `describe` stays the same...
it('defers update until after blur', function() {
  spyOn(scope, '$apply').andCallThrough();

  element.val('baz');
  element.triggerHandler('blur');

  expect(scope.$apply).toHaveBeenCalled();
  expect(element.scope().field).toBe('baz');
});

所以...

  1. 茉莉花spy需要andCallThrough()
  2. 用于element.scope()访问正确的范围。
于 2013-10-02T18:32:29.073 回答