Was ist ein guter Weg, um isolierte Bereiche in AngularJS zu testen?
Direktiven-Snippet
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);
});
}
Ich möchte sicherstellen, dass die Richtlinie auf Änderungen wartet - dies funktioniert nicht mit einem isolierten Bereich:
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));
});
UPDATE: Ich habe es zum Laufen gebracht, indem ich überprüft habe, ob die erwarteten Beobachter zum untergeordneten Bereich hinzugefügt wurden, aber es ist sehr spröde und verwendet die Accessoren wahrscheinlich auf undokumentierte Weise (auch bekannt als Änderungen vorbehalten!).
//this is super brittle, is there a better way!?
elm = compile(validHTML)(scope);
expect(elm.scope().$$watchers[0].exp).toBe('name');
UPDATE 2:
Wie gesagt, das ist spröde! Die Idee funktioniert immer noch, aber in neueren Versionen von AngularJS hat sich der Accessor von geändert scope()
zu isolateScope()
:
//this is STILL super brittle, is there a better way!?
elm = compile(validHTML)(scope);
expect(elm.isolateScope().$$watchers[0].exp).toBe('name');
Antworten:
Siehe Winkelelement-API-Dokumente . Wenn Sie element.scope () verwenden, erhalten Sie den Bereich des Elements, den Sie in der Eigenschaft scope Ihrer Direktive definiert haben. Wenn Sie element.isolateScope () verwenden, erhalten Sie den gesamten isolierten Bereich. Wenn Ihre Direktive beispielsweise ungefähr so aussieht:
Dann wird der Aufruf von element.scope () in Ihrem Test zurückgegeben
Wenn Sie jedoch element.isolateScope () aufrufen, erhalten Sie
Dies gilt ab Winkel 1.2.2 oder 1.2.3, nicht genau sicher. In früheren Versionen hatten Sie nur element.scope ().
quelle
element.isolateScope()
kehrt zurückundefined
. Undelement.scope()
gibt einen Bereich zurück, der nicht alle Inhalte enthält, die ich in meinen Bereich aufgenommen habe.element.children().isolateScope()
Sie können
var isolateScope = myDirectiveElement.scope()
den isolierten Bereich abrufen.Sie müssen nicht wirklich testen, dass $ watch aufgerufen wurde. Das ist mehr das Testen von AngularJs als das Testen Ihrer App. Aber ich denke, es ist nur ein Beispiel für die Frage.
quelle
greet
Funktion aufzudecken und das auszuspionieren und zu überprüfen, ob das aufgerufen wird - nicht die $ watch.isolateScope
Variable erstellen ? Siehe Angs Kommentar zu diesem Egghead-Video ( Egghead.io/lessons/angularjs-unit-testing-directive-scope ): Ab Angular 1.2 musselement.isolateScope()
anstelle vonelement.scope()
code.angularjs.org/1.2Verschieben Sie die Logik auf einen separaten Controller, dh:
und testen Sie letzteres wie jeden Controller - übergeben Sie das Bereichsobjekt direkt ( ein Beispiel finden Sie im Abschnitt Controller hier ).
Wenn Sie in Ihrem Test $ watch auslösen müssen, gehen Sie wie folgt vor:
quelle
Ich bin mir nicht sicher, ob es mit isoliertem Umfang möglich ist (obwohl ich hoffe, dass mich jemand als falsch erweist). Der Isolationsbereich, der in der Direktive erstellt wird, ist isoliert, sodass sich die $ watch-Methode in der Direktive von dem Bereich unterscheidet, den Sie im Komponententest ausspionieren. Wenn Sie scope: {} in scope: true ändern, erbt der Direktivenbereich prototypisch und Ihre Tests sollten bestanden werden.
Ich denke, dies ist nicht die idealste Lösung, da manchmal (häufig) das Isolieren des Bereichs eine gute Sache ist.
quelle