如何在AngularJS中对隔离范围指令进行单元测试

dan*_*lmb 81 javascript unit-testing jasmine angularjs angularjs-directive

在AngularJS中单元测试隔离范围的好方法是什么

JSFiddle显示单元测试

指令片段

    scope: {name: '=myGreet'},
    link: function (scope, element, attrs) {
        //show the initial state
        greet(element, scope[attrs.myGreet]);

        //listen for changes in the model
        scope.$watch(attrs.myGreet, function (name) {
            greet(element, name);
        });
    }
Run Code Online (Sandbox Code Playgroud)

我想,以确保指令监听的变化-这并不会与一个孤立的范围内工作:

    it('should watch for changes in the model', function () {
        var elm;
        //arrange
        spyOn(scope, '$watch');
        //act
        elm = compile(validHTML)(scope);
        //assert
        expect(scope.$watch.callCount).toBe(1);
        expect(scope.$watch).toHaveBeenCalledWith('name', jasmine.any(Function));
    });
Run Code Online (Sandbox Code Playgroud)

更新: 我通过检查预期观察者是否被添加到子范围来实现它,但它非常脆弱,并且可能以未记录的方式使用访问者(也可能更改,恕不另行通知!).

//this is super brittle, is there a better way!?
elm = compile(validHTML)(scope);
expect(elm.scope().$$watchers[0].exp).toBe('name');
Run Code Online (Sandbox Code Playgroud)

更新2: 正如我所说,这很脆弱!这个想法仍然有效,但在较新版本的AngularJS中,访问者已经从以下scope()变为isolateScope():

//this is STILL super brittle, is there a better way!?
elm = compile(validHTML)(scope);                       
expect(elm.isolateScope().$$watchers[0].exp).toBe('name');
Run Code Online (Sandbox Code Playgroud)

小智 102

请参阅angular element api docs.如果使用element.scope(),则获得在指令的scope属性中定义的元素范围.如果使用element.isolateScope(),则会获得整个隔离范围.例如,如果您的指令看起来像这样:

scope : {
 myScopeThingy : '='
},
controller : function($scope){
 $scope.myIsolatedThingy = 'some value';
}
Run Code Online (Sandbox Code Playgroud)

然后在测试中调用element.scope()将返回

{ myScopeThingy : 'whatever value this is bound to' }
Run Code Online (Sandbox Code Playgroud)

但是如果你调用element.isolateScope(),你就会得到

{ 
  myScopeThingy : 'whatever value this is bound to', 
  myIsolatedThingy : 'some value'
}
Run Code Online (Sandbox Code Playgroud)

从角度1.2.2或1.2.3开始就是如此,不确定.在以前的版本中,您只有element.scope().

  • 对我不起作用.`element.isolateScope()`返回`undefined`.并且`element.scope()`返回的范围不包含我放在我的范围内的所有东西. (22认同)
  • @mcv我发现我需要做`element.children().isolateScope()` (4认同)

And*_*lin 11

你可以做到var isolateScope = myDirectiveElement.scope()获得隔离范围.

你真的不需要测试$ watch被调用了..这比测试你的应用更多测试angularjs.但我想这只是问题的一个例子.

  • 我不确定我是否同意它是"测试角度"我没有测试$ watch的工作情况,只是说该指令是属性"有线"到角度. (2认同)