Monday, May 20, 2024
128
rated 0 times [  132] [ 4]  / answers: 1 / hits: 16026  / 12 Years ago, thu, august 9, 2012, 12:00:00

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?


More From » unit-testing

 Answers
37

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);

[#83727] Wednesday, August 8, 2012, 12 Years  [reply] [flag answer]
Only authorized users can answer the question. Please sign in first, or register a free account.
ryanulyssesb

Total Points: 91
Total Questions: 105
Total Answers: 102

Location: England
Member since Tue, Sep 8, 2020
4 Years ago
ryanulyssesb questions
Sat, Mar 20, 21, 00:00, 3 Years ago
Mon, Sep 14, 20, 00:00, 4 Years ago
Mon, Mar 9, 20, 00:00, 4 Years ago
Sun, Jul 7, 19, 00:00, 5 Years ago
;