Jasmine testet AngularJS-Direktiven mit templateUrl


70

Ich schreibe Direktiventests für AngularJS mit Jasmine und verwende templateUrl mit ihnen: https://gist.github.com/tanepiper/62bd10125e8408def5cc

Wenn ich den Test durchführe, wird jedoch der folgende Fehler angezeigt:

Error: Unexpected request: GET views/currency-select.html

Nach dem, was ich in den Dokumenten gelesen habe, dachte ich, ich mache das richtig, aber es scheint nicht so - was fehlt mir hier?

Vielen Dank


Überprüfen Sie meine Antwort hier: stackoverflow.com/questions/15214760/…
Tomas Romero

Antworten:


70

Wenn Sie ngMockE2E oder ngMock verwenden:

Alle HTTP-Anforderungen werden lokal nach den von Ihnen angegebenen Regeln verarbeitet und keine werden an den Server übergeben. Da Vorlagen über HTTP angefordert werden, werden auch sie lokal verarbeitet. Da Sie beim Versuch, eine Verbindung zu Ihrer App herzustellen, nichts angegeben haben, wissen views/currency-select.htmlSie nicht, wie Sie damit umgehen sollen. Sie können ngMockE2E leicht anweisen, Ihre Vorlagenanforderung weiterzuleiten:

$httpBackend.whenGET('views/currency-select.html').passThrough();

Denken Sie daran, dass Sie in Ihren Routing-Pfaden auch reguläre Ausdrücke verwenden können, um alle Vorlagen zu durchlaufen, wenn Sie möchten.

In den Dokumenten wird dies ausführlicher erläutert: http://docs.angularjs.org/api/ngMockE2E.$httpBackend

Andernfalls verwenden Sie Folgendes:

Sie müssen das verwenden, $injectorum auf das neue Backend zuzugreifen. Aus den verknüpften Dokumenten:

var $httpBackend;
beforeEach(inject(function($injector) {
  $httpBackend = $injector.get('$httpBackend');
  $httpBackend.whenGET('views/currency-select.html').respond(200, '');
}));

2
Hmm, ich habe es versucht, aber es scheint, dass passThrough nach dem Injizieren nicht als Funktion verfügbar ist: TypeError: 'undefined' ist keine Funktion (Auswertung von '$ httpBackend.when (' GET ',' views / Währung-select.html '). passThrough ()') Ich habe auch beforeEach (Modul ('ngMockE2E')) aufgenommen; oben in meiner Datei und es geht zurück zum ursprünglichen Fehler
Tane Piper

4
In einem $ httpBackend Mock gibt es keine passThrough () -Methode. Es sagt es direkt in den Dokumenten. docs.angularjs.org/api/ngMock/service/$httpBackend Deshalb erhalten Sie den Fehler, dass die Funktion nicht verfügbar ist. Wenn Sie dies im Frontend und beim In-Unit-Test verspotten möchten, steht Ihnen die PassThrough-Methode zur Verfügung - nur nicht beim Unit-Test ...
Sten Muchow,

3
@StenMuchow Meine Antwort und das Problem von @ tanepiper beziehen sich nicht auf das ngMockModul, sondern auf das ngMockE2EModul, das das unterstützt passThrough(). Normalerweise wird es bei Komponententests nicht verwendet, da für Komponententests keine HTTP-Anforderungen wie Vorlagen erforderlich sein sollten. Falls dies jedoch der Fall ist und der Build sie nicht kompiliert, kann das E2E-Backend verwendet werden.
Josh David Miller

@StenMuchow Die Antwort ist mit der richtigen Seite der Dokumentation verknüpft, aber um zukünftige Verwirrung zu vermeiden, habe ich den Teil entfernt, der Sie verwirrt hat.
Josh David Miller

@JoshDavidMiller ziemlich sicher, dass passThrough () veraltet ist, aber diese Lösung ist immer noch nicht vollständig. Man muss tatsächlich ngHtml2JsPreprocessor verwenden und den Pfad zum Beispielpfad als templateUrl in der Direktive festlegen.
Cameronro

20

Die Karma-Methode besteht darin, die HTML-Vorlage dynamisch in $ templateCache zu laden. Sie können einfach den html2js Karma-Vorprozessor verwenden, wie hier erläutert

Dies läuft darauf hinaus, Ihren Dateien in der Datei conf.js Vorlagen ' .html' sowie Präprozessoren hinzuzufügen = {' .html': 'html2js'};

und verwenden

beforeEach(module('..'));

beforeEach(module('...html', '...html'));

in Ihre js Testdatei


3
Hier ist eine ziemlich gute Erklärung, wie der templateCache-Weg funktioniert: portlandwebworks.com/blog/… . Beachten Sie nur, dass der Blog über eine ziemlich alte Version von Karma spricht. Daher müssten Sie heute ng-html2js anstelle von html2js verwenden, um die Vorlagen zu js vorzuverarbeiten.
Kaitsu

6

Wenn dies ein Komponententest ist, haben Sie keinen Zugriff darauf $httpBackend.passthrough(). Dies ist nur in ngMock2E2 für End-to-End-Tests verfügbar. Ich bin mit den Antworten einverstanden ng-html2js(früher html2js genannt), möchte sie aber erweitern, um hier eine vollständige Lösung bereitzustellen.

Zum Rendern Ihrer Direktive ruft Angular $http.get()Ihre Vorlage ab templateUrl. Da dies ein Unit-Test ist und angular-mocksgeladen wird, wird angular-mocksder Aufruf von abgefangen $http.get()und Sie erhalten den Unexpected request: GETFehler. Sie können versuchen, Wege zu finden, um dies zu umgehen, aber es ist viel einfacher, nur Winkel zu verwenden $templateCache, um Ihre Vorlagen vorzuladen. Auf diese Weise $http.get()wird nicht einmal ein Problem sein.

Das ist es, was der Präprozessor ng-html2js für Sie tut. Um es zum Laufen zu bringen, installieren Sie es zuerst:

$ npm install karma-ng-html2js-preprocessor --save-dev

Konfigurieren Sie es dann, indem Sie die folgenden Felder in Ihrem hinzufügen / aktualisieren karma.conf.js

{
    files: [
      //
      // all your other files
      //

      //your htmp templates, assuming they're all under the templates dir
      'templates/**/*.html'
    ],

    preprocessors: {
        //
        // your other preprocessors
        //

        //
        // tell karma to use the ng-html2js preprocessor
        "templates/**/*.html": "ng-html2js"
    },

    ngHtml2JsPreprocessor: {
        //
        // Make up a module name to contain your templates.
        // We will use this name in the jasmine test code.
        // For advanced configs, see https://github.com/karma-runner/karma-ng-html2js-preprocessor
        moduleName: 'test-templates',
    }
}

Verwenden test-templatesSie schließlich in Ihrem Testcode das Modul, das Sie gerade erstellt haben. Fügen Sie test-templatesdem Modulaufruf, den Sie normalerweise ausführen beforeEach, einfach Folgendes hinzu :

beforeEach(module('myapp', 'test-templates'));

Von hier an sollte es glatt sein. Weitere Informationen zu diesem und anderen Testszenarien für Richtlinien finden Sie in diesem Beitrag


5

Sie könnten vielleicht das $templatecachevom Injektor bekommen und dann so etwas tun

$templateCache.put("views/currency-select.html","<div.....>");

Wo anstelle von <div.....>Ihnen würde Ihre Vorlage platzieren.

Danach richten Sie Ihre Direktive ein und es sollte gut funktionieren!


6
Ich habe etwas Ähnliches mit $ httpBackend gemacht und $ httpBackend.when ('GET', 'views / Currency-Select.html') ausgeführt = "selected_currency"> </ select> '); - aber es besiegt DRY irgendwie - Ich möchte, dass es meine Vorlagen lädt und sie nicht erneut im Code wiederholen muss.
Tane Piper

Nicht gut für lange HTML-Vorlagen, aber es bringt mich vorbei, wo ich seit ein paar Stunden festgefahren bin! Vielen Dank!
Brant

4

Wenn dies immer noch nicht funktioniert, verwenden Sie Fiddler, um den Inhalt der vom htmltojs-Prozessor dynamisch generierten js-Datei anzuzeigen und den Pfad der Vorlagendatei zu überprüfen.

Es sollte so etwas sein

angular.module('app/templates/yourtemplate.html', []).run(function($templateCache) {
  $templateCache.put('app/templates/yourtemplate.html', 

In meinem Fall war es nicht dasselbe wie in meiner tatsächlichen Richtlinie, die das Problem verursachte.

Die TemplateURL an allen Orten genau gleich zu haben, hat mich durchgebracht.


1
Die unterschiedlichen Dateipfade verursachten diesen Fehler für mich
Nicholas Murray

4

Konvertieren Sie einen Kommentar wie gewünscht in eine Antwort.


Für die Leute, die die Antwort von @ Lior in Yeoman- Apps nutzen möchten :

Manchmal ng-html2jsstimmen die Art und Weise, wie auf die Vorlagen in der Karma-Konfiguration verwiesen wird, und folglich - die Namen der von produzierten Module nicht mit den templateUrlin Direktivendefinitionen als s angegebenen Werten überein .
Sie müssen die generierten Modulnamen an templateUrls anpassen .
Diese könnten hilfreich sein:


2

Dies ist ein Beispiel für das Testen von Direktiven, die teilweise als templateUrl verwenden

describe('with directive', function(){
  var scope,
    compile,
    element;

  beforeEach(module('myApp'));//myApp module

  beforeEach(inject(function($rootScope, $compile, $templateCache){
   scope = $rootScope.$new();
   compile = $compile;

   $templateCache.put('view/url.html',
     '<ul><li>{{ foo }}</li>' +
     '<li>{{ bar }}</li>' +
     '<li>{{ baz }}</li>' +
     '</ul>');
   scope.template = {
     url: 'view/url.html'
    };

   scope.foo = 'foo';
   scope.bar = 'bar';
   scope.baz = 'baz';
   scope.$digest();

   element = compile(angular.element(
    '<section>' +
      '<div ng-include="template.url" with="{foo : foo, bar : bar, baz : baz}"></div>' +
      '<div ng-include="template.url" with=""></div>' +
    '</section>'
     ))(scope);
   scope.$digest();

 }));

  it('should copy scope parameters to ngInclude partial', function(){
    var isolateScope = element.find('div').eq(0).scope();
    expect(isolateScope.foo).toBeDefined();
    expect(isolateScope.bar).toBeDefined();
    expect(isolateScope.baz).toBeDefined();
  })
});

0

Wenn Sie das Jasmin-Maven-Plugin zusammen mit RequireJS verwenden, können Sie das Text-Plugin verwenden , um den Vorlageninhalt in eine Variable zu laden und ihn dann in den Vorlagen-Cache zu legen.


define(['angular', 'text!path/to/template.html', 'angular-route', 'angular-mocks'], function(ng, directiveTemplate) {
    "use strict";

    describe('Directive TestSuite', function () {

        beforeEach(inject(function( $templateCache) {
            $templateCache.put("path/to/template.html", directiveTemplate);
        }));

    });
});
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.