在 Javascript 中模拟 window.location.href
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4792281/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
mocking window.location.href in Javascript
提问by wmitchell
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 的函数进行了一些单元测试——不理想,我宁愿将其传入,但在实现中是不可能的。我只是想知道是否可以在不实际导致我的测试运行程序页面实际转到 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.
我正在将 jasmine 用于我的单元测试框架。
采纳答案by Andris
You need to simulate local context and create your own version of window
and window.location
objects
您需要模拟本地上下文并创建您自己的window
和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/...
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.
如果使用,with
则所有变量(包括window
!)将首先从上下文对象中查看,如果不存在,则从实际上下文中查看。
回答by Kurt Harriger
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 can replace this method whenever you need to return a mocked value:
现在,不要直接在代码中使用 window.location.href ,只需使用它即可。然后,您可以在需要返回模拟值时替换此方法:
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:
如果您想要窗口位置的特定部分,例如查询字符串参数,那么也为此创建辅助方法,并将解析工作排除在主代码之外。一些框架如 jasmine 有测试间谍,不仅可以模拟函数返回所需的值,还可以验证它被调用:
spyOn(mynamespace.util, 'getQueryStringParameterByName').andReturn("desc");
//...
expect(mynamespace.util.getQueryStringParameterByName).toHaveBeenCalledWith("sort");
回答by cburgmer
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 injectionand 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");
围绕访问创建一个函数,在你的生产代码中使用它,并在你的测试中用 Jasmine 存根它:
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");
使用依赖注入并在你的测试中注入一个假的:
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");
回答by Jim Isaacs
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.
有时您可能有一个修改 window.location 的库,并且您希望允许它正常运行但也需要进行测试。如果是这种情况,您可以使用闭包将所需的引用传递给您的库,例如这样。
/* 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.
然后在您的测试中,在包含您的库之前,您可以全局重新定义 self,该库将使用模拟 self 作为视图。
var self = {
location: { href: location.href }
};
In your library, you can also do something like the following, so you may redefine self at any point in the test:
在您的库中,您还可以执行以下操作,以便您可以在测试中的任何时候重新定义 self:
/* in mylib.js */
var mylib = (function(href) {
function go ( href ) {
var view = self || window;
view.location.href = href;
}
return {go: go}
}());
In most if not all modern browsers, self is already a reference to window by default. In platforms that implement the Worker API, within a Worker self is a reference to the global scope. In node.js both self and window are not defined, so if you want you can also do this:
在大多数(如果不是所有)现代浏览器中,默认情况下 self 已经是对 window 的引用。在实现 Worker API 的平台中,Worker self 是对全局范围的引用。在 node.js 中 self 和 window 都没有定义,所以如果你愿意,你也可以这样做:
self || window || global
This may change if node.js really does implement the Worker API.
如果 node.js 真的实现了 Worker API,这可能会改变。
回答by user566245
Below is the approach I have take to mock window.location.href and/or anything else which maybe on a global object.
下面是我用来模拟 window.location.href 和/或其他任何可能在全局对象上的方法。
First, rather than accessing it directly, encapsulate it in a module where the object is kept with a getter and setter. Below is my example. I am using require, but that is not necessary here.
首先,不是直接访问它,而是将它封装在一个模块中,在该模块中对象由 getter 和 setter 保存。下面是我的例子。我正在使用 require,但这在这里不是必需的。
define(["exports"], function(exports){
var win = window;
exports.getWindow = function(){
return win;
};
exports.setWindow = function(x){
win = x;
}
});
Now, where you have normally done in your code something like window.location.href
, now you would do something like:
现在,您通常在代码中完成类似的操作window.location.href
,现在您将执行以下操作:
var window = global_window.getWindow();
var hrefString = window.location.href;
Finally the setup is complete and you can test your code by replacing the window object with a fake object you want to be in its place instead.
最后设置完成,您可以通过用您想要代替的假对象替换 window 对象来测试您的代码。
fakeWindow = {
location: {
href: "http://google.com?x=y"
}
}
w = require("helpers/global_window");
w.setWindow(fakeWindow);
This would change the win
variable in the window module. It was originally set to the global window
object, but it is not set to the fake window object you put in. So now after you replaced it, the code will get your fake window object and its fake href you had put it.
这将更改win
窗口模块中的变量。它最初设置为全局window
对象,但未设置为您放入的假窗口对象。所以现在替换它后,代码将获取您放置的假窗口对象及其假 href。
回答by Tongfa
IMO, this solution is a small improvement of cburgmer's in that it allows you to replace window.location.href with $window.location.href in the source. Granted I'm using Karma and not Jasmine, but I believe this approach would work with either. And I've added a dependency on sinon.
IMO,此解决方案是 cburgmer 的一个小改进,因为它允许您在源代码中用 $window.location.href 替换 window.location.href。当然,我使用的是 Karma 而不是 Jasmine,但我相信这种方法对两者都适用。我已经添加了对 sinon 的依赖。
First a 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; }
Now I can set location.href in code by injecting windowInjectable() as $window like this:
现在我可以通过像这样注入 windowInjectable() 作为 $window 在代码中设置 location.href :
function($window) {
$window.location.href = "http://www.website.com?varName=foo";
}
and mocking it out in a unit test it looks like:
并在单元测试中模拟它看起来像:
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();
The getter / setter syntax goes back to IE 9, and is otherwise widely supported according to https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/set
getter / setter 语法可以追溯到 IE 9,并且根据https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/set得到广泛支持
回答by AngularBoy
This works for me:
这对我有用:
delete window.location;
window.location = Object.create(window);
window.location.href = 'my-url';
回答by Youssef Gamil
You need to fake window.location.href
while being on the same page.
In my case, this snipped worked perfectly:
您需要window.location.href
在同一页面上进行伪造。在我的情况下,这个剪辑工作得很好:
$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