web-dev-qa-db-fra.com

Comment se moquer de $ window.location.replace dans le test unitaire AngularJS?

J'ai le service suivant:

angular.module("services")
.factory("whatever", function($window) {
  return {
    redirect: function() {
      $window.location.replace("http://www.whatever.com");
    }
  };
});

Comment se moquer de l'objet $window Dans le test unitaire pour éviter de recharger la page lors de l'exécution des tests?

J'ai essayé d'utiliser

spyOn($window.location, 'replace').andReturn(true);

, mais cela n'a pas fonctionné (erreur de "Some of your tests did a full page reload!" toujours) et

$provide.value('$window', {location: {replace: jasmine.createSpy()}})

, mais je recevais une erreur (Error: [ng:areq] Argument 'fn' is not a function, got Object) avec une trace de pile pointant uniquement vers angular propre source, donc ce n'était pas très utile ...

40
szimek

Dans Chrome (n'a pas testé d'autres navigateurs), location.replace est en lecture seule, donc spyOn n'a pas pu le remplacer.

$provide.value devrait marcher. Quelque chose ne va pas quelque part dans votre code.

Voici un test unitaire de travail

describe('whatever', function() {
    var $window, whatever;

    beforeEach(module('services'));

    beforeEach(function() {
      $window = {location: { replace: jasmine.createSpy()} };

      module(function($provide) {
        $provide.value('$window', $window);
      });

      inject(function($injector) {
        whatever = $injector.get('whatever');
      });
    });

    it('replace redirects to http://www.whatever.com', function() {
      whatever.redirect();
      expect($window.location.replace).toHaveBeenCalledWith('http://www.whatever.com');
    });
});
58
LostInComputer

Je vais avec une solution plus simple mais peut-être moins élégante. J'écris un wrapper pour $ window.location, que je peux ensuite simuler. En rapportant cela à votre code, je me moquerais de la fonction any.redirect, plutôt que de se moquer de la fenêtre $ (je suppose ici que votre fonction réelle est plus complexe).

Je me retrouverais donc avec:

angular.module("services")
.factory("whatever", function($window) {
  return {
    do_stuff_that_redirects: function() {
      lots of code;
      this.redirect("http://www.whatever.com");
      maybe_more_code_maybe_not;
    },

    redirect: function(url) {
      $window.location.replace(url);
    }
  };
});

Je peux ensuite directement me moquer de la méthode de redirection, et je peux simplement croire que comme il ne s'agit que d'une seule ligne de code, cela ne peut pas vraiment se tromper.

spyOn(whatever, 'redirect').andCallFake(function(){});
expect(whatever.redirect).toHaveBeenCalledWith('http:/my.expected/url');

Cela suffit pour mes besoins et me permet de valider l'URL appelée.

6
PaulL

Je proposerai une autre approche qui pourrait fonctionner pour vous. J'ai rencontré le même problème lors du test d'unité d'une `` action '' de contrôleur qui redirige finalement l'utilisateur (pleine page, mais vers une page différente dans le plus grand site Web/application). Pour donner un peu de contexte, le contrôleur déclenche une requête AJAX, et si la réponse est OK, il redirigera l'utilisateur vers une page différente via $ window.location.replace ():

$http.post('save', data)
        .success(function(responseData, status, headers, config) {
            if(responseData.redirect) {
                $window.location.replace(responseData.redirect);
            }
        })
        .error(function(responseData, status, headers, config) {
             console.error("ERROR while trying to create the Event!!");
        });

Le test de cette fonction de contrôleur a provoqué le même "Certains de vos tests ont fait un rechargement de page entière!" Erreur. J'ai donc ajouté ce qui suit à la fonction beforeEach () pour la spécification du contrôleur, pour simuler le service $ window:

mockWindow = { location: { replace: function(url) { console.log('redirecting to: ' + url); } } };
eventCtrl = $controller('EventCtrl', { $scope: scope, $window: mockWindow });

Bien sûr, cette solution m'empêche de vérifier (proprement) que la fonction replace a été appelée avec un argument attendu, mais je m'en fiche vraiment pour le moment ... J'espère que ça aide.

4
Shawn Flahave
$location.path('/someNewPath');

$ location.replace (); // ou vous pouvez les chaîner en tant que: $ location.path ('/ someNewPath'). replace ();

0
Kevin Barasa

Je pense que vous voulez utiliser le service $ location , plutôt que d'appeler $window.location. Il y a aussi une page entière expliquant cette fonctionnalité ici: http://docs.angularjs.org/guide/dev_guide.services.$location .

En utilisant cela, il devrait être assez simple d'utiliser une version tronquée du service $ location dans vos tests.

0
calamari