wake-up-neo.com

So testen Sie das Verhalten in der Verknüpfungsfunktion einer Direktive

In einigen meiner Direktiven füge ich Funktionen hinzu, um die für die Direktive spezifische Logik zu behandeln. Zum Beispiel:

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

Wie kann ich diese Funktion testen? Ich habe gegoogelt, wie man eine Direktive testet, aber die Dinge, die ich gefunden habe waren mehr über das Testen von Änderungen an dem Element. Ich kann meine Anweisung sicherlich vor jedem meiner Tests kompilieren, aber das würde meinen Geltungsbereich jedes Mal auslöschen. Ich möchte die Funktion testen, da sich Eigenschaften in meinem Geltungsbereich ändern.

Gibt es eine Möglichkeit, das von der Direktive-Definition zurückgegebene Objekt in Erfahrung zu bringen? Dann könnte ich einfach die Link-Funktion direkt aufrufen und das Verhalten jeder der im Geltungsbereich definierten Funktionen testen. Gibt es einen besseren Weg, dies alles zu tun?

Ich verwende Jasmine, um meine Tests auszuführen, und ich möchte meine Bereichseinstellungen in den describe-Funktionen vornehmen, sodass ich mehrere it-Funktionen für dieselben Bereichsdaten verwenden kann.

45
dnc253

Anstatt die Verknüpfungsfunktion selbst zu testen, würden Sie die Ergebnisse der Direktive programmgesteuert testen. Was Sie tun würden, ist, die Direktive in eine Zeichenfolge zu schreiben und $compile zu verwenden, um die Winkelverarbeitung durchzuführen. Dann testen Sie die Ausgabe, um sicherzustellen, dass alles richtig verdrahtet ist.

Angulars Quelle ist voller guter Beispiele, wie das geht ... zum Beispiel Angulars Test der ngRepeat-Direktive

Sie können sehen, was sie tun, indem Sie die Direktive einrichten. Ändern Sie den Gültigkeitsbereich (in diesem Fall $rootScope), stellen Sie sicher, dass er $digested ist, und testen Sie dann das ausgegebene DOM, um sicherzustellen, dass alles richtig verdrahtet ist. Sie können auch testen, was sich im Geltungsbereich befindet, wenn die Direktive dies ändert.

Der Test für ngClick ist auch ziemlich interessant, weil er den Test einer Browser-Interaktion und deren Auswirkungen auf den Umfang zeigt.

Der Vollständigkeit halber sei hier ein Auszug aus den ngClick-Tests aufgeführt, die meiner Meinung nach eine ziemlich gute Prüfung einer Anweisung auf den Punkt bringen:

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

Im Fall Ihrer scope.doStuff-Funktion würde ich also nicht testen, was tut, sondern auch, was auch immer davon betroffen ist, und dies hat Auswirkungen auf DOM-Elemente.

44
Ben Lesh

Ich habe dieses Problem etwas anders gelöst.

Wenn Ihre Direktive über eine sehr einfache Link-Funktion verfügt und Sie nicht das dritte Argument (attrs) benötigen, entfernen Sie einfach die Link-Funktion und weisen Sie der Direktive stattdessen ein controller zu. 

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

genau wie Sie die Argumente für Gültigkeitsbereich und Element in einer Link-Funktion einer Direktive haben, können diese beiden Argumente als $ scope und $ element in einen einfach zu testenden Controller eingefügt werden.

Wenn Sie in der Lage sind, Controller zu erstellen und diese Controller zu testen, ist dies sehr einfach.

1
sqlexception

Bei Bedarf ist es möglich, die Link-Methode einer Direktive direkt zu testen. Siehe den Unit-Tester des Winkeleismoduls: "Testen einer Direktive-Konfiguration".

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

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

In Ihrem Fall können Sie einen Verweis auf das Bereichsobjekt beibehalten, das Sie an die Link-Methode der Direktive übergeben, und Sie können die doStuff-Funktion direkt in diesem Bereich testen.

1
bverbist

Wie in einem Kommentar angegeben, antworten Sie auf @sqlexception. Sie müssen nur wirklich den Geltungsbereich der Richtlinie in den Griff bekommen, was nicht schwer zu tun ist. Was Sie nicht tun möchten, ist, Ihren Code zu ändern, um Ihre Tests zu erfüllen, da es umgekehrt sein sollte.

Um den Geltungsbereich der Richtlinie zu ermitteln, kompilieren Sie einfach wie folgt:

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

dabei wird $scope mit $scope = $rootScrope.$new() deklariert. Jetzt können wir den Isolate-Bereich durch Ausführen von element.scope() erhalten.

Ich habe kürzlich einen kurzen Blog-Beitrag darüber geschrieben, der hier zu finden ist Testen einer Linking-Funktion mit einem Plunker, um zu helfen:

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();
 }));

Die Verwendung dieses $$ childHead war für mich die Lösung des gleichen Problems. Damit kann ich Funktionen abdecken, die in meinen Tests nicht aufgerufen wurden.

0