web-dev-qa-db-fra.com

UI-router interfère avec $ httpbackend unit test, angular js

Il s'agit d'un contrôleur avec une fonction de soumission:

$scope.submit = function(){   

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

Ceci est mon 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);
  });

L'erreur que j'obtiens est:

Error: Unexpected request: GET views/appBar.html

views/appBar.html est mon templateUrl:

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

Donc, en quelque sorte, ui-router fait mon point $ httpBackend vers cela au lieu de ma fonction de soumission. J'ai le même problème dans tous mes tests en utilisant $ httpBackend.

Y a-t-il une solution à cela?

44
Joe

Prenez cet essentiel 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!");
        }
    }
});

Ajoutez-le à un fichier appelé stateMock dans votre dossier test/mock, incluez ce fichier dans votre configuration karma s'il n'est pas déjà récupéré.

La configuration avant votre test devrait alors ressembler à ceci:

beforeEach(module('stateMock'));

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

Ensuite, dans votre test, vous devez ajouter

state.expectTransitionTo('project');
48
rosswil

Ce problème Github sur nit Testing UI Router explique plus en détail ce qui se passe.

Le problème est que $httpBackend.flush() déclenche une diffusion qui déclenche ensuite le cas contraire de stateProvider.

Une solution simple peut être de faire la configuration suivante, comme mentionné par @darinclark dans le fil Github mentionné ci-dessus. Ceci est valable si vous n'avez pas besoin de tester les transitions d'état. Sinon, jetez un œil à @ réponse de rosswil qui est inspiré par @ réponse de Vratislav sur Github .

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

[~ # ~] modifié [~ # ~]

Merci à Chris T de le signaler dans les commentaires, semble-t-il après la v0.2.14? la meilleure façon de procéder consiste à utiliser

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

Si vous ne voulez pas ajouter de fichiers Gist comme il est dit dans la bonne solution, vous pouvez ajouter une condition "quand" à votre $ httpBackend pour ignorer les pétitions GET de vues comme ceci:

$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
Jose Ignacio Hita

J'ai la même erreur que vous avez commentée, après un appel, ils m'interrogent sur l'url de sinon ui-route.

Pour résoudre le problème de l'appel, la route sinon ui dans testing est ne pas injecter $ state dans beforeach statment. Dans mes tests, $ state n'a pas de sens de l'utiliser.

2
Alex Carod

Déplacez vos services vers leur propre module qui ne dépend pas d'ui.router. que votre application principale dépende de ce module. Lorsque vous testez, ne testez pas l'application principale, testez le module qui contient vos services. Le fournisseur d'état n'essaiera pas de changer d'état/de route car ce module ne sait rien du routeur ui. Cela a fonctionné pour moi.

1
Maccurt