2013-07-02 9 views
19

Wir verwenden Karma zu Unit-Test unserer eckigen Dienste, diese Dienste enthält $ http Aufrufe, so haben wir ein verspottet $ httpbackend an Ort und Stelle, so dass wir die App ohne Server und db ausführen können. das funktioniert gut, ein Service kann $ http ("someurl? Id = 1234") aufrufen und wir bekommen die richtigen Daten zurück.Angular 1.1.5 test versprechen-based service

Aber wenn wir versuchen, die gleiche Sache in Unit-Tests zu tun, können wir es nicht funktioniert, löst das Versprechen bekommen, nie, wenn es um $ http

Der Service:

getAllowedTypes: function (contentId) { 
    var deferred = $q.defer(); 
    $http.get(getChildContentTypesUrl(contentId)) 
     .success(function (data, status, headers, config) { 
      deferred.resolve(data); 
     }). 
     error(function (data, status, headers, config) { 
      deferred.reject('Failed to retreive data for content id ' + contentId); 
     }); 
    return deferred.promise; 
} 

Die verspottete $ httpbackend

$httpBackend 
    .whenGET(mocksUtills.urlRegex('/someurl')) 
    .respond(returnAllowedChildren); //returns a json object and httpstatus:200 

Der Test

it('should return a allowed content type collection given a document id', function(){ 

    var collection; 
    contentTypeResource.getAllowedTypes(1234).then(function(result){ 
     collection = result; 
    }); 

    $rootScope.$digest(); 

    expect(collection.length).toBe(3); 
}); 

aber Sammlung ist nicht definiert, .then() nie aufgerufen.

versuchte so ziemlich alles, was das Versprechen zu erhalten zu lösen, $ rootScope. $ Apply(), $ zu verdauen, $ httpBacke.flush(), aber nichts funktioniert

$ So verspottete httpBackend funktioniert, wenn von Controllern aufgerufen in App, aber nicht, wenn Dienste direkt in Karma-Unit-Tests aufgerufen werden

Antwort

7

Sie sollten nicht zweimal verdauen, da $ httpBackend.flush() Digest selbst aufruft. Sie müssen den Anruf tätigen, rufen Sie Digest auf, um die Anfrage Interzeptoren, die Anruf-Flush zu lösen. Hier

ist ein Arbeits Plnkr: http://plnkr.co/edit/FiYY1jT6dYrDhroRpFG1?p=preview

+1

Kees de Kooter machte in einer anderen Antwort unten einen Kommentar, dass $ rootScope nicht benötigt wird. Ich gab den Plunkr auf und kommentierte alle $ rootScope-Verwendungen. Der Test läuft noch: http://plnkr.co/edit/4ladJi7TAQ4sFdzuGmDr?p=preview – chashi

4

In Ihrem Fall müssen Sie zweimal verdauen, einmal für $ httpBackend, und wieder für Ihre eigenen zurückgestellt.

So:

it('should return a allowed content type collection given a document id', function(){ 

    var collection; 
    contentTypeResource.getAllowedTypes(1234).then(function(result){ 
     collection = result; 
    }); 
    $httpBackend.flush(); 
    $rootScope.$digest(); 

    expect(collection.length).toBe(3); 
}); 
+0

Versuchte .flush() schon, aber bekommt: "Fehler: Keine anstehenden Anforderung zu spülen!" Dies scheint ein allgemeiner Fehler seit 1.1.4 zu sein: https://github.com/angular/angular.js/issues/2431 –

+0

Die Reihenfolge ist hier falsch, Sie müssen $ verdauen, bevor Sie flush. – user553086

4

Sie sind fast da. In Ihrem Fall müssen Sie nur einen Digest-Zyklus erzwingen, bevor Sie das HTTP-Backend leeren. Siehe Beispielcode unten.

it('should return a allowed content type collection given a document id', function(){ 

    var collection; 
    contentTypeResource.getAllowedTypes(1234).then(function(result){ 
     collection = result; 
    }); 

    $rootScope.$digest(); 
    $httpBackend.flush(); 
    expect(collection.length).toBe(3); 
}); 
+0

es ist .flush() Nr. $ Flush() BTW, und nein, funktioniert nicht, erhalten Sie "Keine ausstehende Anfrage zu Flush" Fehler, siehe: https://github.com/angular/angular.js/issues/2431 –

+2

$ rootScope. $ digest() ist IMO nicht erforderlich, wenn Sie einen Dienst isoliert testen. –