web-dev-qa-db-ja.com

ディレクティブのリンク関数で動作をテストする方法

一部のディレクティブでは、スコープに関数を追加して、ディレクティブに固有のロジックを処理しています。例えば:

link: function(scope, element, attrs) {
         scope.doStuff = function() {
            //do a bunch of stuff I want to test
         }        
      }

その機能をテストするにはどうすればよいですか?私はディレクティブをテストする方法をグーグルで探しましたが、 私が見つけたもの は要素の変更をテストすることに関するものでした。確かに、各テストの前にディレクティブをコンパイルできますが、それは毎回スコープを一掃します。スコープ変更のプロパティとして関数をテストしたい。

ディレクティブ定義から返されるオブジェクトを保持する方法はありますか?次に、リンク関数を直接呼び出して、スコープで定義された各関数の動作をテストできます。これをすべて行うより良い方法はありますか?

Jasmineを使用してテストを実行していますが、describe関数でスコープをセットアップしたいので、同じスコープデータに対して複数のit関数を使用できます。

46
dnc253

基本的に、リンク関数自体をテストするのではなく、プログラムでディレクティブの結果をテストします。ディレクティブを文字列に書き出し、$compileを使用してangularで処理します。出力をテストして、すべてが正しく接続されていることを確認します。

Angularのソースには、これを行う方法の良い例がたくさんあります。たとえば、 AngularによるngRepeatディレクティブのテスト

ディレクティブの設定、スコープの変更(この場合は$rootScope)が$digestedであることを確認し、出力されるDOMをテストしてすべてが接続されていることを確認しています正しく。ディレクティブがそれを変更している場合、スコープ内にあるものをテストすることもできます。

ngClickのテスト も非常に興味深いものです。これは、ブラウザの対話のテストとスコープへの影響を示しているためです。

完全を期すために、ngClickテストの抜粋を以下に示します。これは、ディレクティブのテストをかなりうまくまとめていると思います。

 it('should get called on a click', inject(function($rootScope, $compile) {
   element = $compile('<div ng-click="clicked = true"></div>')($rootScope);
   $rootScope.$digest();
   expect($rootScope.clicked).toBeFalsy();

   browserTrigger(element, 'click');
   expect($rootScope.clicked).toEqual(true);
 }));

だからあなたのscope.doStuff関数の場合、私はそれが何であるかをテストするのと同じように、それが何であるかをテストしませんdoingスコープで、その後DOM要素に影響します。

44
Ben Lesh

必要に応じて、ディレクティブのリンクメソッドを直接単体テストすることができます。角氷モジュールのユニットテスターを参照してください:「ディレクティブ構成のテスト」

http://bverbist.github.io/angular-ice/#/unitTester

使用例: https://github.com/bverbist/angular-ice/blob/master/app/components/icebank/bank-account-number-directive_link_test.js

あなたの場合、ディレクティブのリンクメソッドに渡すスコープオブジェクトへの参照を保持し、そのスコープでdoStuff関数を直接テストできます。

2
bverbist

私はこの問題を少し異なって解決しました。

ディレクティブに非常に単純なリンク関数があり、3番目の引数(attrs)が必要ない場合は、リンク関数を削除してディレクティブにcontroller代わりに。

app.directive('loadIndicator', function() {
  return {
    restrict: 'E',
    replace: true,
    templateUrl: 'blahblah/indicator.html',
    controller: 'LoadIndicatorController'
  };
});

ディレクティブのリンク関数にスコープと要素の引数があるように、これら2つの引数は$ scopeおよび$ elementとしてテストしやすいコントローラーに挿入できます。 。

コントローラーを作成し、それらのコントローラーを単体テストできる場合、これは非常に簡単です。

1
sqlexception

@sqlexceptionへのコメント返信で述べられているように。本当にディレクティブのスコープのハンドルを取得する必要がありますが、これは難しくありません。あなたがしたくないことは、テストを満足させるためにコードを修正することです。

ディレクティブのスコープを取得するには、次のようにコンパイルします。

var element = $compile(<directive's html>).($scope)

ここで_$scope_は$scope = $rootScrope.$new()で宣言されています。 element.scope()を実行することで分離スコープを取得できます

私は最近、これについて短いブログ投稿を書きました リンク関数のテスト

0
britztopher
 it('should get called on a click', inject(function($rootScope, $compile) {
   var scope = $rootScope.$new();
   element = $compile('<div ng-click="doIt()"></div>')(scope);
   scope.$digest();
   expect(scope.$$childHead.doIt()).toBeDefined();
 }));

この$$ childHeadを使用することは、同じ問題の解決策でした。これにより、テストで呼び出されなかった関数をカバーできます。

0