在JavaScript中嘲笑useragent?

我正在寻找一种方法来编程方式更改navigator.userAgent上飞。 在我失败的尝试获得一个自动化的JavaScriptunit testing,我放弃了,并试图开始使用fireunit。 马上,我抨击了使用真正的浏览器进行javascripttesting的一面墙壁。

具体来说,我需要更改navigator.userAgent来模拟几百个userAgentstring,以确保对给定函数进行正确的检测和覆盖。 navigator.userAgent是只读的,所以我似乎卡住了! 我怎样才能模拟navigator.userAgent? 用户代理切换器(插件)可以切换FF的useragent,但我可以在JavaScript内做到这一点?

尝试:

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

尝试在FF2和FF3。

添加到Crescent Fresh的解决scheme中 ,重新定义navigator.userAgent getter似乎在Safari 5.0.5(在Windows 7和Mac OS X 10.6.7)上不起作用。

需要创build一个从navigator对象inheritance的新对象,并定义一个新的userAgent getter来隐藏navigator的原始userAgent getter:

 var __originalNavigator = navigator; navigator = new Object(); navigator.__proto__ = __originalNavigator; navigator.__defineGetter__('userAgent', function () { return 'Custom'; }); 

以下解决scheme适用于Chrome,Firefox,Safari,IE9 +以及iframe:

 function setUserAgent(window, userAgent) { if (window.navigator.userAgent != userAgent) { var userAgentProp = { get: function () { return userAgent; } }; try { Object.defineProperty(window.navigator, 'userAgent', userAgentProp); } catch (e) { window.navigator = Object.create(navigator, { userAgent: userAgentProp }); } } } 

例子:

 setUserAgent(window, 'new user agent'); setUserAgent(document.querySelector('iframe').contentWindow, 'new user agent'); 

使用Object.defineProperty应该添加更多的浏览器混合:

 if (navigator.__defineGetter__) { navigator.__defineGetter__("userAgent", function () { return "ua"; }); } else if (Object.defineProperty) { Object.defineProperty(navigator, "userAgent", { get: function () { return "ua"; } }); } 

这个代码应该在Firefox 1.5 +Chrome 6+Opera 10.5+IE9 +上运行 (并经过testing)。 不幸的是,Safari在任何平台上都不允许更改userAgent。

编辑:Safari不允许更改userAgent,但可以replace整个导航器对象,如上面的另一个解决scheme中指出的那样。

为了更新这个线程,defineGetter在Jasmine中不再起作用,因为它已经被弃用了。 但是,我发现这使我可以修改茉莉花的navigator.userAgent getter:

 navigator = { get userAgent() { return 'agent'; } } console.log(navigator.userAgent); // returns 'agent' 

只要记得在茉莉花testing完成后重置导航器对象

Crescent Fresh的答案是正确的。 但有一个问题: __defineGetter__已弃用:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/definedGetter

已弃用此function已从Web标准中删除。 尽pipe一些浏览器可能仍然支持它,但它正在被丢弃。 不要在旧的或新的项目中使用它。 使用它的页面或Web应用程序可能会随时中断。

你应该使用defineProperty来代替:

 Object.defineProperty(navigator, "userAgent", { get: function () { return "foo"; // customized user agent } }); navigator.userAgent; // 'foo' 

我想我会采取dependency injection的方法。 代替:

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

也许做一些事情:

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

然后你可以通过下面的方法“模拟” getUserAgent()

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

这个devise仍然不是完全自动化的(你必须手动重命名getter来执行你的testing),而且它增加了一些复杂性,就像在navigator.userAgent操作一样简单,我不知道你是怎么做的实际上找出了myFunction任何错误,但是我只是想把它扔到那里给你一些想法如何处理。

也许这里介绍的“dependency injection”的概念可以以某种方式与FireUnit集成。

对于那些试图在TypeScript中做同样的事情的解决scheme:

 (<any>navigator)['__defineGetter__']('userAgent', function(){ return 'foo'; }); navigator.userAgent; // 'foo' 

或者语言同样的东西:

 (<any>navigator)['__defineGetter__']('language', function(){ return 'de-DE'; }); 

navigator.userAgent是一个只读的string属性,所以不能编辑它

以上的答案不适用于PhantomJS + TypeScript。 下面的代码为我工作:

 var __originalNavigator = navigator; (window as any).navigator = new Object(); navigator["__proto__"] = __originalNavigator["__proto__"]; navigator["__defineGetter__"]('userAgent', function () { return 'Custom'; }); 

不,我怀疑你可以在JavaScript内做到这一点。 但是使用Firefox的用户代理切换器,你可以testing你想要的任何useragent,那么为什么不使用它呢?

通过defineGetter在Firefox和Opera上更改navigator.userAgent

 navigator.__defineGetter__('userAgent', function(){ return( "iPhone 5" ); }); alert( navigator.userAgent ); //iPhone 5 

在IE和Opera上通过对象实例更改navigator.userAgent

 var navigator = new Object; navigator.userAgent = 'iPhone 5'; alert( navigator.userAgent ); //iPhone5 

好的是,如果你使用IE浏览器控制,你可以通过execScript双重欺骗HTTP请求和JavaScript navigator.userAgent

 WebBrowser1.Navigate "http://example.com", , , , "User-Agent: iPhone 5" & vbCrLf WebBrowser1.Document.parentWindow.execScript ("var navigator=new Object;navigator.userAgent='iPhone 5';") WebBrowser1.Document.parentWindow.execScript ("alert(navigator.userAgent);") 'iPhone 5