mocking window.location.href in Javascript

匿名 (未验证) 提交于 2019-12-03 08:33:39

问题:

I have some unit tests for a function that makes use of the window.location.href -- not ideal I would far rather have passed this in but its not possible in the implementation. I'm just wondering if its possible to mock this value without actually causing my test runner page to actually go to the URL.

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

I'm using jasmine for my unit testing framework.

回答1:

You need to simulate local context and create your own version of window and window.location objects

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/...

If you use with then all variables (including window!) will firstly be looked from the context object and if not present then from the actual context.



回答2:

The best way to do this is to create a helper function somewhere and then mock that:

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

Now instead of using window.location.href directly in your code simply use this instead. Then you replacing this method whenever you need to return a mocked value:

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

If you want a specific part of the window location such as a query string parameter then create helper methods for that too and keep the parsing out of your main code. Some frameworks such as jasmine have test spies that can not only mock the function to return desired values, but can also verified it was called:

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


回答3:

I would propose two solutions which have already been hinted at in previous posts here:

  • Create a function around the access, use that in your production code, and stub this with Jasmine in your 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");
  • Use a dependency injection and inject a fake in your 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");


回答4:

Sometimes you may have a library that modifies window.location and you want to allow for it to function normally but also be tested. If this is the case, you can use a closure to pass your desired reference to your library such as this.

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

Then in your test, before including your library, you can redefine self globally, and the library will use the mock self as the view.

var self = {    location:        
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!