Question

J'ai quelques tests unitaires pour une fonction qui utilise la window.location.href - pas l'idéal, je préférerais avoir passé beaucoup cela dans, mais ce ne est pas possible dans la mise en œuvre. Je me demande s'il est possible de se moquer de cette valeur sans faire réellement mon coureur page de test pour aller effectivement à l'URL.

  window.location.href = "http://www.website.com?varName=foo";    
  expect(actions.paramToVar(test_Data)).toEqual("bar"); 

J'utilise le jasmin pour mon cadre de tests unitaires.

Était-ce utile?

La solution

Vous devez simuler le contexte local et créer votre propre version d'objets window et window.location

var localContext = {
    "window":{
        location:{
            href: "http://www.website.com?varName=foo"
        }
    }
}

// simulated context
with(localContext){
    console.log(window.location.href);
    // http://www.website.com?varName=foo
}

//actual context
console.log(window.location.href);
// http://www.actual.page.url/...

Si vous utilisez with toutes les variables (y compris window!) Sera tout d'abord être regardé de l'objet de contexte et sinon présente alors du contexte actuel.

Autres conseils

La meilleure façon de le faire est de créer une fonction d'aide quelque part et Mock:

 var mynamespace = mynamespace || {};
    mynamespace.util = (function() {
      function getWindowLocationHRef() {
          return window.location.href;
      }
      return { 
        getWindowLocationHRef: getWindowLocationHRef
      }
    })();

Maintenant, au lieu d'utiliser window.location.href directement dans votre code simplement utiliser ce lieu. Ensuite, vous pouvez remplacer cette méthode chaque fois que vous devez retourner une valeur moquée:

mynamespace.util.getWindowLocationHRef = function() {
  return "http://mockhost/mockingpath" 
};

Si vous voulez une partie spécifique de l'emplacement de la fenêtre, comme un paramètre de chaîne de requête puis créer des méthodes auxiliaires pour cela aussi et garder l'analyse syntaxique de votre code principal. Certains cadres comme le jasmin ont des espions de test qui ne peut que se moquer de la fonction pour renvoyer les valeurs souhaitées, mais peut aussi vérifier qu'il a été appelé:

spyOn(mynamespace.util, 'getQueryStringParameterByName').andReturn("desc");
//...
expect(mynamespace.util.getQueryStringParameterByName).toHaveBeenCalledWith("sort");

Je propose deux solutions qui ont déjà été fait allusion dans les messages précédents ici:

  • Créer une fonction autour de l'accès, l'utilisation que dans votre code de production, et ce avec Jasmine stub dans vos tests:

    var actions = {
        getCurrentURL: function () {
            return window.location.href;
        },
        paramToVar: function (testData) {
            ...
            var url = getCurrentURL();
            ...
        }
    };
    // Test
    var urlSpy = spyOn(actions, "getCurrentURL").andReturn("http://my/fake?param");
    expect(actions.paramToVar(test_Data)).toEqual("bar");
    
  • Utilisez un injection de dépendance et injecter un faux dans votre test:

    var _actions = function (window) {
        return {
            paramToVar: function (testData) {
                ...
                var url = window.location.href;
                ...
            }
        };
    };
    var actions = _actions(window);
    // Test
    var fakeWindow = {
       location: { href: "http://my/fake?param" }
    };
    var fakeActions = _actions(fakeWindow);
    expect(fakeActions.paramToVar(test_Data)).toEqual("bar");
    

Parfois, vous pouvez avoir une bibliothèque qui modifie window.location et que vous voulez permettre de fonctionner normalement, mais aussi tester. Si tel est le cas, vous pouvez utiliser une fermeture pour passer votre référence souhaitée à votre bibliothèque comme celle-ci.

/* in mylib.js */
(function(view){
    view.location.href = "foo";
}(self || window));

Ensuite, dans votre test, avant d'inclure votre bibliothèque, vous pouvez redéfinir l'auto dans le monde, et la bibliothèque utilisera l'auto maquette comme la vue.

var self = {
   location: { href: location.href }
};

Dans votre bibliothèque, vous pouvez aussi faire quelque chose comme ce qui suit, vous pouvez donc redéfinir soi à tout moment dans le test:

/* in mylib.js */
var mylib = (function(href) {
    function go ( href ) {
       var view = self || window;
       view.location.href = href;
    }
    return {go: go}
}());

Dans la plupart des cas ne sont pas tous les navigateurs modernes, l'auto est déjà une référence à la fenêtre par défaut. Dans les plates-formes qui mettent en œuvre l'API des travailleurs, au sein d'un travailleur autonome est une référence à la portée mondiale. En Node.js les deux soi et la fenêtre ne sont pas définies, donc si vous voulez, vous pouvez aussi faire ceci:

self || window || global

Cela peut changer si Node.js ne vraiment mettre en œuvre l'API des travailleurs.

Voici l'approche que je prendre pour window.location.href maquette et / ou toute autre chose qui peut-être sur un objet global.

D'abord, au lieu d'accéder directement, encapsule dans un module où l'objet est maintenu avec un getter et setter. Ci-dessous mon exemple. J'utilise nécessaires, mais ce n'est pas nécessaire ici.

define(["exports"], function(exports){

  var win = window;

  exports.getWindow = function(){
    return win;
  };

  exports.setWindow = function(x){
    win = x;
  }

});

Maintenant, vous avez normalement où fait dans votre code quelque chose comme window.location.href, maintenant, vous feriez quelque chose comme:

var window = global_window.getWindow();
var hrefString = window.location.href;

Enfin, la configuration est terminée et vous pouvez tester votre code en remplaçant l'objet de la fenêtre avec un objet faux que vous voulez être à sa place à la place.

fakeWindow = {
  location: {
    href: "http://google.com?x=y"
  }
}
w = require("helpers/global_window");
w.setWindow(fakeWindow);

Cela changerait la variable win dans le module de fenêtre. Il a été mis à l'objet global window, mais il n'est pas réglé sur l'objet de la fenêtre de faux que vous mettez dans. Alors maintenant, après avoir remplacé, le code sera obtenir votre objet fenêtre faux et son faux href vous l'avez dit.

OMI, cette solution est une petite amélioration de son cburgmer en ce qu'il vous permet de remplacer window.location.href avec $ window.location.href dans la source. Accordé J'utilise Karma et non Jasmine, mais je crois que cette approche fonctionnerait avec les deux. Et j'ai ajouté une dépendance sinon.

D'abord un service / singleton:

function setHref(theHref) {
    window.location.href = theHref;
}
function getHref(theHref) {
    return window.location.href;
}

var $$window = {
        location: {
            setHref: setHref,
            getHref: getHref,
            get href() {
                return this.getHref();
            },
            set href(v) {
                this.setHref(v);
            }
        }
    };
function windowInjectable() {  return $$window; }

Maintenant, je peux configurer location.href dans le code en injectant windowInjectable () comme $ fenêtre comme ceci:

function($window) {
  $window.location.href = "http://www.website.com?varName=foo";
}

et moqueur il dans un test unitaire, il ressemble à:

sinon.stub($window.location, 'setHref');  // this prevents the true window.location.href from being hit.
expect($window.location.setHref.args[0][0]).to.contain('varName=foo');
$window.location.setHref.restore();

La syntaxe de lecture / définition remonte à IE 9, et il est par ailleurs largement soutenue selon https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/set

Vous devez window.location.href de faux tout en étant sur la même page. Dans mon cas, ce Snipped a parfaitement fonctionné:

$window.history.push(null, null, 'http://server/#/YOUR_ROUTE');
$location.$$absUrl = $window.location.href;
$location.replace();

// now, $location.path() will return YOUR_ROUTE even if there's no such route
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top