在javascript中嘲笑一个useragent?

时间:2009-08-20 15:34:06

标签: javascript unit-testing user-agent

我正在寻找一种以编程方式动态更改navigator.userAgent的方法。在我尝试获得自动javascript单元测试器失败的尝试中,我放弃并试图开始使用fireunit。我立即猛烈抨击了使用实际浏览器进行javascript测试的一面墙。

具体来说,我需要更改navigator.userAgent来模拟几百个userAgent字符串,以确保对给定函数的正确检测和覆盖。 navigator.userAgent只读,所以我好像卡住了!我怎么能模拟navigator.userAgent?用户代理切换器(插件)可以切换FF的useragent,但是我可以在javascript中执行吗?

15 个答案:

答案 0 :(得分:101)

尝试:

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

navigator.userAgent; // 'foo'

在FF2和FF3中尝试过。

答案 1 :(得分:24)

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

需要创建一个继承自navigator对象的新对象,并定义一个新的userAgent getter来隐藏userAgent中的原始navigator getter:

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

答案 2 :(得分:21)

以下解决方案适用于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');

答案 3 :(得分:7)

使用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 +中运行(并经过测试) 即可。不幸的是,任何平台上的Safari都不允许更改userAgent。

编辑:Safari不允许更改userAgent,但可以替换整个导航器对象,如上面另一个解决方案所述。

答案 4 :(得分:3)

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

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

  

<强>已过时   此功能已从Web标准中删除。   虽然有些浏览器可能仍然支持它,但它正在进行中   被丢弃。不要在旧项目或新项目中使用它。页面或Web应用程序   使用它可能会随时中断。

您应该使用defineProperty代替:

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

navigator.userAgent; // 'foo'

答案 5 :(得分:3)

要更新此线程,defineGetter在Jasmine中不再使用,因为它已被弃用。但是我发现这允许我修改jasmine中的navigator.userAgent的getter:

navigator = {
  get userAgent() {
    return 'agent';
  }
}

console.log(navigator.userAgent); // returns 'agent'

只要记住在jasmine中完成测试后重置导航器对象

答案 6 :(得分:3)

对于那些试图在TypeScript中做同样事情的人来说,解决方案是:

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

navigator.userAgent; // 'foo'

语言也是如此:

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

答案 7 :(得分:1)

我想我会采用依赖注入方法。而不是:

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'
    // ...
}

这种设计仍然没有完全自动化(您必须手动重命名getter以执行测试),并且它增加了一些复杂性,就像在navigator.userAgent上操作一样简单,我不是确定你如何识别myFunction中的任何错误,但我只是想我会把它扔出去给你一些想法如何处理。

也许这里提出的“依赖注入”的想法可以某种方式与FireUnit集成。

答案 8 :(得分:1)

对于这里的用户,因为他们需要在单元测试中更改userAgent值,Tyler Long的解决方案有效,但是如果要还原初始userAgent或多次更改它,则可能需要将属性设置为可配置:

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

// Now in your setup phase:
// Keep the initial value
var initialUserAgent = navigator.userAgent;
setUserAgent('foo');

// In your tearDown:
// Restore the initial value
setUserAgent(initialUserAgent);

否则,您可能会遇到TypeError: Cannot redefine property错误。 在Chrome Headless上为我工作。

答案 9 :(得分:1)

尝试一下,它对我没有毛发问题

Object.defineProperty(global.navigator, 'userAgent', { get: () => 'iPhone' });

答案 10 :(得分:0)

navigator.userAgent是一个只读字符串属性,因此无法对其进行编辑

答案 11 :(得分:0)

以上答案不适用于PhantomJS + TypeScript。下面的代码对我有用:

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

答案 12 :(得分:0)

该主题仅适用于Karma + Jasmin和Typescript,但要设置userAgent属性,可以这样做:

describe('should validate YYYY-MM-dd format only on IE browser', () => {
    // this validator has a specific condition to work only in IE11 and down
    (window as any).navigator.__defineGetter__('userAgent', function () {
      return 'MSIE';
    });

...
// rest of the test

});

本文帮助:https://www.codeproject.com/Tips/1036762/Mocking-userAgent-with-JavaScript

答案 13 :(得分:-1)

通过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 webbrowser控件,您可以通过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

答案 14 :(得分:-2)

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