Ich habe folgenden Service:

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

Wie verspotte ich ein $window Objekt im Komponententest, um ein erneutes Laden der Seite beim Ausführen von Tests zu verhindern?

Ich habe versucht mit

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

, aber es hat nicht funktioniert (immer noch "Some of your tests did a full page reload!" Fehler) und

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

, aber ich habe einen Fehler (Error: [ng:areq] Argument 'fn' is not a function, got Object) erhalten, bei dem die Stapelverfolgung nur auf die eckige eigene Quelle zeigt, daher war dies nicht sehr hilfreich ...

40
szimek 28 Nov. 2013 im 00:21

5 Antworten

Beste Antwort

In Chrome (in anderen Browsern nicht getestet) ist location.replace schreibgeschützt, sodass spyOn es nicht ersetzen konnte.

$provide.value sollte funktionieren. Irgendwo in Ihrem Code muss etwas falsch sein.

Hier ist ein Arbeitstest

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 2 Jän. 2014 im 15:28

Ich gehe mit einer einfacheren, aber vielleicht weniger eleganten Lösung. Ich schreibe einen Wrapper für $ window.location, den ich dann verspotten kann. Wenn ich das mit Ihrem Code in Verbindung bringe, würde ich die Funktion Whatever.redirect verspotten, anstatt $ window zu verspotten (ich gehe hier davon aus, dass Ihre eigentliche Funktion komplexer ist).

Also würde ich enden mit:

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);
    }
  };
});

Ich kann dann die Umleitungsmethode direkt verspotten und einfach darauf vertrauen, dass es nicht wirklich schief gehen kann, da es sich nur um eine Codezeile handelt.

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

Dies ist für meine Zwecke ausreichend und ermöglicht es mir, die aufgerufene URL zu überprüfen.

6
PaulL 13 Apr. 2014 im 09:40

Ich denke, Sie möchten den $ location -Dienst verwenden, anstatt {{ X0}}. Es gibt auch eine ganze Seite, die diese Funktion hier erklärt: http://docs.angularjs.org /guide/dev_guide.services.$location.

Auf diese Weise sollte es ziemlich einfach sein, in Ihren Tests eine gestoppelte Version des $ location-Dienstes zu verwenden.

0
calamari 27 Nov. 2013 im 20:34

Ich werde einen anderen Ansatz anbieten, der für Sie funktionieren könnte. Ich hatte das gleiche Problem beim Testen einer Controller-Aktion, die den Benutzer letztendlich umleitet (Laden der gesamten Seite, jedoch auf eine andere Seite in der größeren Website / Anwendung). Um einen Kontext zu geben, löst der Controller eine AJAX-Anforderung aus. Wenn die Antwort in Ordnung ist, leitet er den Benutzer über $ window.location.replace () auf eine andere Seite um:

$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!!");
        });

Der Test für diese Controller-Funktion verursachte dasselbe "Einige Ihrer Tests haben ein vollständiges Neuladen der Seite durchgeführt!" Error. Daher habe ich der Funktion beforeEach () für die Controller-Spezifikation Folgendes hinzugefügt, um den $ window-Dienst zu verspotten:

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

Natürlich hindert mich diese Lösung daran, (sauber) zu überprüfen, ob die Ersetzungsfunktion mit einem erwarteten Argument aufgerufen wurde, aber das interessiert mich momentan nicht wirklich ... Ich hoffe, das hilft.

4
Shawn Flahave 4 Aug. 2014 im 16:10
$location.path('/someNewPath');

$ location.replace (); // oder Sie können diese verketten als: $ location.path ('/ someNewPath'). replace ();

0
Kevin Barasa 6 Apr. 2017 im 06:08