单元测试AngularJS指令:示波器没有更新?示波器、指令、单元测试、AngularJS

2023-09-13 03:42:14 作者:衹願做妳的小傻瓜

短版:我有一个用的是新天地指令(即范围:真正的;的不的分离物范围内)出现在工作的时候,我与应用程序交互得很好,但它不会出现在可观测的方式来更新范围单元测试。 为什么对指令的适用范围的不的观察到在单元测试?

Short version: I have a directive that is using a "new scope" (i.e., scope:true; not an isolate scope) which appears to work just fine when I'm interacting with the application, but which does not appear to update the scope in an observable way in the unit tests. Why are the changes to field on the directive's scope not observable in the unit test?

实例Plunker: http://plnkr.co/edit/gpzHsX?p = preVIEW

Example in 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];
          }
        });
      }
    };
  }
]);

这是越来越大致使用方法如下:

It's getting used roughly as follows:

<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>

假设字段看起来像约:

$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');
  });
});

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

Now, when interacting with the application:

我可以键入输入和密钥的任何更新在 $ scope.fields 被推迟到在那场blur事件。在测试中,茉莉间谍报道称,在调用 $适用正在发生的但 ... ...应该是的范围内被执行的函数 $应用的(显然)没有得到调用。 ...也没有了 $观看前pression被调用。 I can type into the input and any updates to the keys in $scope.fields are deferred until the blur event on that field. In the test, the Jasmine spy is reporting that the call to $apply is happening but... ...the function that should be executed within the context of that $apply is (apparently) not getting called. ...nor does the $watch expression get called.

在运行的应用程序的情况下该指令本身似乎运作得很好,但我似乎无法找到任何原因,我无法与单元测试观察其变化。

The directive itself in the context of the running application appears to operate just fine, but I cannot seem to find any reason why I cannot observe the changes with a unit test.

除非该指令的重新设计(例如,使用隔离范围和 $发出事件):有,我已经在这里错过什么?这是我应该改变有关的指令?否则一些技巧,使这些变化在单元测试中观察到的?

Barring a redesign of the directive (e.g., to use isolate scope and $emit events): is there anything that I have missed here? Something I should change about the directive? or else some trick to make these changes observable in the unit test?

推荐答案

在一言以蔽之:不要忘了 .andCallThrough()的间谍

In a nutshell: don't forget .andCallThrough() on the spy.

更改一无所知指令本身,是需要测试的工作版本:

Changing nothing about the directive itself, the working version of the test needed to be:

// 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');
});

所以...

茉莉花间谍需要 andCallThrough() 使用 element.scope()来访问正确的范围。 The Jasmine spy needed andCallThrough() Use element.scope() to access the correct scope.