44

Dies ist ein Controller mit einer einreichen Funktion:

$scope.submit = function(){ 

$http.post('/api/project', $scope.project) 
     .success(function(data, status){ 
     $modalInstance.dismiss(true); 
     }) 
     .error(function(data){ 
     console.log(data); 
     }) 
    } 
} 

Das ist mein Test ist

it('should make a post to /api/project on submit and close the modal on success', function() { 
    scope.submit(); 

    $httpBackend.expectPOST('/api/project').respond(200, 'test'); 

    $httpBackend.flush(); 

    expect(modalInstance.dismiss).toHaveBeenCalledWith(true); 
    }); 

Der Fehler ich erhalte, ist:

Error: Unexpected request: GET views/appBar.html 

views/appBar.html ist mein templateUrl:

.state('project', { 
    url: '/', 
    templateUrl:'views/appBar.html', 
    controller: 'ProjectsCtrl' 
    }) 

So irgendwie UI-Router macht meine $ httpBackend Punkt zu diesem statt meiner Aufgabe senden. Ich habe das gleiche Problem in allen meinen Tests mit $ httpBackend.

Gibt es eine Lösung dafür?

+2

Relevante UI-Router Problem # 212 mit einigen Problemumgehungen: https://github.com/angular-ui/ui-router/issues/212#issuecomment-69974072 –

Antwort

48

diesem Kern Nehmen https://gist.github.com/wilsonwc/8358542

angular.module('stateMock',[]); 
angular.module('stateMock').service("$state", function($q){ 
    this.expectedTransitions = []; 
    this.transitionTo = function(stateName){ 
     if(this.expectedTransitions.length > 0){ 
      var expectedState = this.expectedTransitions.shift(); 
      if(expectedState !== stateName){ 
       throw Error("Expected transition to state: " + expectedState + " but transitioned to " + stateName); 
      } 
     }else{ 
      throw Error("No more transitions were expected! Tried to transition to "+ stateName); 
     } 
     console.log("Mock transition to: " + stateName); 
     var deferred = $q.defer(); 
     var promise = deferred.promise; 
     deferred.resolve(); 
     return promise; 
    } 
    this.go = this.transitionTo; 
    this.expectTransitionTo = function(stateName){ 
     this.expectedTransitions.push(stateName); 
    } 

    this.ensureAllTransitionsHappened = function(){ 
     if(this.expectedTransitions.length > 0){ 
      throw Error("Not all transitions happened!"); 
     } 
    } 
}); 

in einer Datei hinzufügen stateMock in Ihrem Test/Mock-Ordner genannt werden, umfassen diese Datei in Ihrem Karma Config, wenn es nicht bereits abgeholt.

Das Setup, bevor Sie Ihren Test sollte dann so etwas aussehen:

beforeEach(module('stateMock')); 

// Initialize the controller and a mock scope 
beforeEach(inject(function ($state //other vars as needed) { 
    state = $state; 
    //initialize other stuff 
} 

Dann in Ihrem Test sollten Sie

state.expectTransitionTo('project'); 
+2

Awesome! Ich habe den Router fast zusammen übersprungen. Gute Arbeit! Sie sollten diese Arbeit mit den Leuten des ui-Routers teilen, damit Leute es besser finden können. – Per

+1

@ user1572526 yeah Super! +1 roswil nur ein riesiger Kopfschmerz ^^ es scheint mir seltsam, nicht nur eine Menge Leute hier zu sehen .... – Whisher

+1

Wow, das muss mit Ui-Router geteilt werden, verbrachte Stunden versucht zu bestimmen, warum kommentieren meine $ urlRouterProvider hat meine Tests repariert. Danke rosswil und für Whisher, dass sie mich hier gezeigt haben !!! – evkline

38

Diese Github Ausgabe über Unit Testing UI Router hinzufügen erklärt ausführlicher, was passiert.

Das Problem ist, dass $httpBackend.flush() eine Sendung auslöst, die dann den anderen Fall der stateProvider auslöst.

Eine einfache Lösung kann das folgende Setup sein, wie von @darinclark in Github Thread oben erwähnt erwähnt. Dies ist gültig, wenn Sie Zustandsübergänge nicht testen müssen. Ansonsten schauen Sie nach @rosswil's answer, die von @Vratislav answer on Github inspiriert ist.

beforeEach(module(function ($urlRouterProvider) { 
    $urlRouterProvider.otherwise(function(){return false;}); 
})); 

EDITED

Dank Chris T dies in den Kommentaren zu berichten, scheint nach v0.2.14? Der beste Weg, dies zu tun ist

beforeEach(module(function($urlRouterProvider) { 
    $urlRouterProvider.deferIntercept(); 
})); 
+11

UI-Router hat jetzt eine '$ urlRouterProvider.deferIntercept()' Funktion. Siehe https://github.com/angular-ui/ui-router/issues/212#issuecomment-69974072 –

+1

Dies ist die schnellste Lösung –

+0

@ChrisT, danke! Deine Lösung hat mir geholfen. – smalone

1

Verschieben Sie Ihre Dienste zu einem eigenen Modul, die keine Abhängigkeit zu ui.router haben. Lassen Sie Ihre Haupt-App von diesem Modul abhängig. Wenn Sie die Hauptanwendung nicht testen, testen Sie das Modul, in dem Ihre Dienste enthalten sind. Der Stateprovider versucht nicht, den Status/Route zu ändern, da dieses Modul nichts über den ui.router weiß. Das hat für mich funktioniert.

3

Wenn Sie Kern keine Dateien hinzufügen mögen, wie es in der richtigen Lösung, sagen Sie einen „wenn“ Zustand zu Ihrem $ ignorieren httpBackend hinzufügen können, um Petitionen von Ansichten wie diese:

$httpBackend.when("GET", function (url) { 
    // This condition works for my needs, but maybe you need to improve it 
    return url.indexOf(".tpl.html") !== -1; 
}).passThrough(); 
+1

Ich habe '.passThrough ist keine Funktion' Fehler, nicht sicher, warum. Das funktionierte für mich: '$ httpBackend.whenGET (/ templates \ /.*/). Antworten ('');' –

+0

Sie können hier die Dokumentation sehen, passThrough ist eine gültige Funktion: https: //docs.angularjs. org/api/ngMockE2E/service/$ httpBackend Ist eine Funktion von requestHandler, die die Antwort der "wann" -Funktion ist. –

+0

Auch ich habe .passThrough ist kein Funktionsfehler. '.respond' funktionierte jedoch gut. –

2

I hab den gleichen fehler deine kommentiert, nach einem anrufdienst fragen sie mich nach der url sonst von ui-route.

Um die sonst ui-Route in der Prüfung das Problem des Anrufs zu lösen ist nicht $ Zustand in beforeach statment injizieren. In meinem Test $ -Zustand nicht sinnvoll, es zu verwenden.