javascript 是否可以为 qUnit 测试模拟 window.location 对象?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11891502/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-26 14:40:54  来源:igfitidea点击:

Is it possible to mock the window.location object for a qUnit test?

javascriptunit-testingquery-stringqunit

提问by jbabey

Let's say I have a utility function that, for simplicity's sake (the real thing is complicated and irrelevant), returns the current window's querystring.

假设我有一个实用函数,为了简单起见(实际情况很复杂且无关紧要),它返回当前窗口的查询字符串。

var someUtilityFunction = () {
    return window.location.search.substring(1);
};

Now I want to unit test this function in qUnit (not sure if the testing harness is relevant or not):

现在我想在 qUnit 中对这个函数进行单元测试(不确定测试工具是否相关):

test('#1 someUtilityFunction works', function () {
    // setup
    var oldQS = window.location.search;
    window.location.search = '?key1=value1&key2=value2&key3=value3';

    var expectedOutput = 'key1=value1&key2=value2&key3=value3';

    // test
    equals(someUtilityFunction(),
        expectedOutput,
        'someUtilityFunction works as expected.');

    // teardown
    window.location.search = oldQS;
});

The problem here is that setting the window.location.searchto a different querystring is causing the page to reload, essentially entering an infinite request loop. Is there any way to mock out the window.location object withoutmaking any changes to the someUtilityFunctionfunction?

这里的问题是将 设置window.location.search为不同的查询字符串会导致页面重新加载,实质上进入了无限请求循环。有没有办法模拟 window.location 对象而不someUtilityFunction函数进行任何更改?

回答by Torsten Walter

We run into the same problem a few days ago. Mainly there are 2 approaches:

几天前我们遇到了同样的问题。主要有2种做法:

Rewrite your code

重写你的代码

This might not be the best (if any) solution, but consider passing the windowobject to your function to make mocking easier. Even better, use a closure and encapsulate your code. This has a few more advantages:

这可能不是最好的(如果有的话)解决方案,但请考虑将window对象传递给您的函数以使模拟更容易。更好的是,使用闭包并封装您的代码。这还有几个优点:

  • You can shadow global vars
  • You can use private local vars
  • You can avoid naming collisions
  • The shadowing makes mocking really easy, just pass in something else
  • 您可以隐藏全局变量
  • 您可以使用私有本地变量
  • 您可以避免命名冲突
  • 阴影使模拟变得非常容易,只需传入其他内容即可

Wrap your code

包装你的代码

You can wrap all your code inside a function which mocks the window object into a local variable. You have basically two possibilities there as well:

您可以将所有代码包装在一个函数中,该函数将窗口对象模拟为局部变量。您基本上也有两种可能性:

Suppose this is the mock:

假设这是模拟:

var customWindow = {
    location: {
        search: "",
        hash: ""
    }
};

Use a closure

使用闭包

var someUtilityFunction;

(function(window) {
    // window is now shadowed by your local variable
    someUtilityFunction = () {
        return window.location.search.substring(1);
    };
})(customWindow);

This shadows the global windowwith a local window.

这会window用本地window.

Use the withstatement

使用with语句

Although I am usually strongly against with, it could really solve a lot of problems here. Since it basically remaps your scope, you can very easily mock your environment.

虽然我通常强烈反对with,但它在这里确实可以解决很多问题。由于它基本上重新映射了您的范围,因此您可以非常轻松地模拟您的环境。

// first some more preparation for our mock
customWindow.window = customWindow;

with(customWindow) {

    // this still creates the var in the global scope
    var someUtilityFunction = () {
        // window is a property of customWindow
        return window.location.search.substring(1);
    };

    // since customWindow is our scope now
    // this will work also
    someUtilityFunction = () {
        // location is a property of customWindow too
        return location.search.substring(1);
    };

}

By the way: I don't know if the searchproperty suffers from the same symptoms as the hashproperty - namely sometimes including the question mark and sometimes not. But you might want to consider using

顺便说一句:我不知道该search物业是否与该物业有相同的症状hash- 即有时包括问号,有时不包括。但你可能想考虑使用

window.location.search.replace(/^\?/, "");

instead of

代替

window.location.substr(1);

回答by Sam Schneider

I've had some success using window.history.pushState. See this StackOverflow answer. For each unit test, I call a function setQueryString('var=something')which I then implement like this:

我在使用window.history.pushState. 请参阅此 StackOverflow 答案。对于每个单元测试,我调用一个函数setQueryString('var=something'),然后像这样实现:

function setQueryString(queryString) {
  window.history.pushState({}, '', '?' + queryString);
}

You'll need to clear the query string with the afterEachmethod of QUnit.module, otherwise you're query string will be set to the value of the final test, and you'll get weird results.

您需要使用afterEachQUnit.module的方法清除查询字符串,否则您的查询字符串将被设置为最终测试的值,并且您会得到奇怪的结果。