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

javascript, query-string, qunit, unit-testing

Solution

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

Rewrite your code

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

- 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 `window` with a local `window`.

Use the `with` statement

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.

// 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 `search` property suffers from the same symptoms as the `hash` property - namely sometimes including the question mark and sometimes not. But you might want to consider using

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

instead of

window.location.substr(1);

Problem

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): ``` 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.search` to 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 without making any changes to the `someUtilityFunction` function?

Original source

Related problems