Override Default Properties with JavaScript
Unit testing with client side JavaScript is something you don't do until you're made to. Of course unit testing is important but let's be honest: most people are just happy that their code works, right? Anyways, fast forward to a world where unit testing is normal and we have a problem to solve: overriding native browser property values for the sake of unit testing. The following is an easy strategy for overriding default browser property values!
The JavaScript
You can't successfully override all properties with a simple statement; let's use navigator.userAgent
for example:
console.log(navigator.userAgent); // >> Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36 // Try to set that value -- will be unsuccessful navigator.userAgent = 'Walshbot'; console.log(navigator.userAgent); // >> Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36
Overriding the navigator.userAgent
can be useful for the purposes of unit and functional testing, so how can we successfully change that value? With Object.defineProperty
:
// Store the original value var originalUserAgent = navigator.userAgent; // Override! Object.defineProperty(navigator, 'userAgent', { get: function() { return 'WalshBot'; } }); // (Run your tests here) // Set the value back to original Object.defineProperty(navigator, 'userAgent', { get: function() { return originalUserAgent; } });
Within the snippet above, we save the original Object.defineProperty
value, override it briefly, then set the value back to the original. Object.defineProperty
is very useful, especially when you consider that the second argument is a function -- you can execute any logic within that function to return the proper value at the time it's requested!
Why not this:
It’s standard and seems to work fine.
Useful but it should be treated carefully, because what would it happen if the test fails and we don’t reassign the original value?
Interesting as this can be used to invoke functions without any
()
.Here I am counting the number of times a property is requested;
Hi,
__defineGetter__
is deprecated.Another way: IE9+
Doesn’t seem to work cross-domain, only seems to work in frames with local content.