更新模板和调用 $digest 不会触发带有正确参数的 $watch - 单元测试 angularjs

Updating template and calling $digest does not trigger $watch with correct parameters - unit tests angularjs

我有一个简单的指令,它根据指令的 scope 属性 添加或删除 focus class 到元素。

我想写 2 个测试。

首先测试验证,当 scope.addFocus 属性 设置为 'true' 时,focus class 在元素上。此测试通过。

然后我更新指令的编译模板,将 scope.addFocus 属性 更改为 'false',触发 $digest() 并期望,该指令将更新元素的 classes 并删除 focus class。这个测试失败了。

这里是一个 link plunkr: http://plnkr.co/edit/k4PBcCwfivsJsbIEUwGd?p=preview

想知道为什么 $compiledTemplate.attr('add-focus', 'false'); $directiveScope.$digest(); 不更新 按预期更新 classes?

指令代码

myApp.directive('myDirective', function() {
    return {
        scope: {
            addFocus: '@'
        },
        restrict: 'A',
        link: function (scope, element, attr) {

            scope.$watch(
                function() { return scope.addFocus; },
                function (newValue, oldValue) {

                    if (newValue === 'true') {
                        element.addClass('focus');
                    } else {
                        element.removeClass('focus');
                    }
                },
                false
            );
        }
    };
});

测试

describe('myApp', function () {

  var $compile, $timeout, $rootScope;
  var $directiveScope;

  var template = '<div my-Directive add-focus="true"></div>';
  var $compiledTemplate;

  beforeEach(function () {
      module('myApp');
  });

  beforeEach(angular.mock.inject(function(_$compile_, _$timeout_, _$rootScope_) {
          $compile = _$compile_;
          $timeout = _$timeout_;
          $rootScope = _$rootScope_;
      }
  ));

  beforeEach(function() {
      $directiveScope = $rootScope.$new();
      $compiledTemplate = $compile(template)($directiveScope);
      $directiveScope.$digest();
  });

  // Test 1
  it('directive is compiled and has focus class', function() {
      console.log('test1', $compiledTemplate[0]);
      expect($compiledTemplate.hasClass('focus')).toBe(true);
  });

  // Test 2
  it('focus class is removed', function() {
      $compiledTemplate.attr('add-focus', 'false');
      $directiveScope.$digest();

      $timeout(function() {
          console.log('test2', $compiledTemplate[0]);
          expect($compiledTemplate.hasClass('focus')).toBe(false);
      }, 0);

      $timeout.flush();
  });

});

更新了 Plunker

问题是 watcher 没有被调用。我们需要同样使用 isolateScope。我创建了如下的 isolateScope :

        isolateScope = $compiledTemplate.isolateScope();

并切换规范中的 addFocus 值以触发观察器

        isolateScope.addFocus = false;

答案已给出并被接受,尽管它不好:当您使用输入测试指令时 - 测试输入,不要直接更改指令范围。

最短的例子是:

beforeEach(function() {
    $upperScope = $rootScope.$new();
    $upperScope.param = true;
    $compiledTemplate = $compile('<div my-Directive add-focus="{{param}}"></div>')($upperScope);
    $upperScope.$digest();
});

// Test 1
it('directive is compiled and has focus class', function() {
    expect($compiledTemplate.hasClass('focus')).toBe(true);
});

// Test 2
it('focus class is removed', function() {
    $upperScope.param = false; 
    $upperScope.$digest();

    expect($compiledTemplate.hasClass('focus')).toBe(false);
});