views:

335

answers:

4

I'm looking for a way to programmatically change navigator.userAgent on the fly. In my failed attempt to get an automated javascript unit tester, I gave up and attempted to begin using fireunit. Immediately, I've slammed into one of the walls of using an actual browser for javascript testing.

Specifically, I need to change navigator.userAgent to simulate a few hundred userAgent strings to ensure proper detection and coverage on a given function. navigator.userAgent is readonly, so I seem stuck! How can I mock navigator.userAgent? User Agent Switcher (plugin) can switch FF's useragent, but can I do it within javascript?

A: 

No, i doubt you can do it within javascript. But with Firefox's User Agent Switcher you can test whatever useragent you want, so why not just use that?

Marius
Did you not see the part where I said "hundreds of user agent strings?"
Stefan Kendall
I don't think you quite understand the purpose of unit testing. "I only have 30 test cases, so why not run through manually each time I make the smallest change?"
Stefan Kendall
Take the User Agent Tester and modify the code to automatically test with all "hundreds of user agent strings". If you know javascript, that should be very simple
Marius
A: 

navigator.userAgent is a read-only string property

really dont think there is any possibility to edit it.

if ever u get to do it plz post the solution its very interesting :D

Lil'Monkey
navigator.userAgent is a getter, not a "read-only string property".
Eli Grey
@Elijah Grey, what's the difference between a getter only and a read-only property at your point of view ?
Cédric Boivin
+5  A: 

Try:

navigator.__defineGetter__('userAgent', function(){
    return 'foo' // customized user agent
});

navigator.userAgent; // 'foo'

Tried it in FF2 and FF3.

Crescent Fresh
Doesn't seem to work in Firefox 3.5 or IE8.
Matthew Manela
@Matthew: see my edit seconds before your comment ;)
Crescent Fresh
I just tried it in 3.5, and it seems to work :)
Stefan Kendall
ty for the solution
Lil'Monkey
A: 

I guess I'd take a dependency injection approach. Instead of:

function myFunction() {
    var userAgent = navigator.userAgent;
    // do stuff with userAgent
}

Maybe do something like:

function myFunction(userAgent) {
    // do stuff with userAgent
}

function getUserAgent() {
    window.userAgentReal = +window.userAgentReal || 0;
    return [ navigator.userAgent ][window.userAgentReal++];
}

function getUserAgentMock() {
    window.nextUserAgentMock = +window.nextUserAgentMock || 0;
    return [
        'test user agent1',
        'test user agent2',
        'test user agent3'
    ][window.nextUserAgentMock++];
}

var userAgent;
while (userAgent = getUserAgent()) {
    myFunction(userAgent);
}

Then you can "mock out" getUserAgent() by doing:

function getUserAgentReal() { // formerly not 'Real'
    // ...
}

function getUserAgent() { // formerly 'Mock'
    // ...
}

This design still isn't completely automated (you have to manually rename the getter to perform your testing), and it adds a bunch of complexity to something as simple as operating on navigator.userAgent, and I'm not sure how you'd actually identify any bugs in myFunction, but I just figured I'd throw it out there to give you some ideas how this might be dealt with.

Maybe the idea of "dependency injection" presented here can somehow be integrated with FireUnit.

Grant Wagner
Sure, could just make navigator.userAgent be getUserAgent, then in the running I could just redefine getUserAgent. So long as my definitions are last, the mock becomes the truth. It makes the actual javascript larger, clunkier, and nastier, though, so I'm trying to avoid that.
Stefan Kendall