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?