web-dev-qa-db-de.com

UI-Router interferiert mit $ httpbackend unit test, angular js

Dies ist ein Controller mit einer Submit-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

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, den ich erhalte, ist:

Error: Unexpected request: GET views/appBar.html

views/appBar.html ist meine templateUrl:

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

Irgendwie macht der UI-Router meinen $ httpBackend-Punkt darauf anstatt auf meine Submit-Funktion. Ich habe das gleiche Problem in allen meinen Tests mit $ httpBackend.

Gibt es eine Lösung dafür?

44
Joe

Nehmen Sie dieses Gist 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!");
        }
    }
});

Fügen Sie es zu einer Datei namens stateMock in Ihrem Test/Mock-Ordner hinzu. Fügen Sie diese Datei in Ihre Karma-Konfiguration ein, falls sie noch nicht erfasst wurde.

Das Setup vor dem Test sollte dann ungefähr so ​​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 sollten Sie in Ihrem Test hinzufügen

state.expectTransitionTo('project');
48
rosswil

In dieser Github-Ausgabe zu nit Testing UI Router wird ausführlicher erklärt, was passiert.

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

Eine einfache Lösung kann sein, das folgende Setup durchzuführen, wie von @darinclark im oben erwähnten Github-Thread erwähnt. Dies gilt, wenn Sie keine Statusübergänge testen müssen. Ansonsten schauen Sie sich @ rosswils Antwort an, das von @ Vratislav Antwort auf Github inspiriert ist.

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

[~ # ~] bearbeitet [~ # ~]

Danke an Chris T, dies in den Kommentaren zu melden, scheint nach v0.2.14? Der beste Weg, dies zu tun, ist zu verwenden

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

Wenn Sie keine Gist-Dateien hinzufügen möchten, wie in der richtigen Lösung angegeben, können Sie Ihrem $ httpBackend eine "when" -Bedingung hinzufügen, um GET-Petitionen für Ansichten wie diese zu ignorieren:

$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();
3

Ich habe den gleichen Fehler kommentiert wie Sie, nach einem Anruf beim Service fragen sie mich nach der URL von sonst ui-route.

Um das Problem des Aufrufs zu lösen, lautet die ansonsten in ui-route enthaltene Anweisung nicht $ state injizieren in beforeeach. In meinem Testzustand hat $ keinen Sinn es zu benutzen.

2
Alex Carod

Verschieben Sie Ihre Dienste in ein eigenes Modul, das nicht von ui.router abhängig ist. Habe deine Haupt-App von diesem Modul abhängig gemacht. Wenn Sie die Haupt-App nicht testen, testen Sie das Modul, in dem sich Ihre Dienste befinden. Der Zustandsanbieter versucht nicht, den Zustand/die Route zu ändern, da dieses Modul nichts über den ui.router weiß. Das hat bei mir funktioniert.

1
Maccurt