在javascript中模拟用户代理?

在javascript中模拟用户代理?,javascript,unit-testing,user-agent,Javascript,Unit Testing,User Agent,我正在寻找一种动态地以编程方式更改navigator.userAgent的方法。在我尝试获得自动化javascript单元测试仪失败的过程中,我放弃了,并尝试开始使用fireunit。很快,我就碰到了使用实际浏览器进行javascript测试的障碍之一 具体来说,我需要更改navigator.userAgent来模拟几百个userAgent字符串,以确保对给定函数的正确检测和覆盖。userAgent是只读的,所以我好像被卡住了!如何模拟navigator.userAgent?用户代理切换器(插件

我正在寻找一种动态地以编程方式更改navigator.userAgent的方法。在我尝试获得自动化javascript单元测试仪失败的过程中,我放弃了,并尝试开始使用fireunit。很快,我就碰到了使用实际浏览器进行javascript测试的障碍之一


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

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

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

尝试:

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

navigator.userAgent; // 'foo'

在FF2和FF3中尝试过。

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

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
中的任何bug,但我只是想把它扔出去,让你知道如何处理这件事

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

添加到,重新定义
导航器。userAgent
getter在Safari 5.0.5(在Windows 7和Mac OS X 10.6.7上)中似乎不起作用

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

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

使用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,但可以替换整个navigator对象,正如上面的另一个解决方案所指出的那样。

通过DefineGeter更改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

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

Fresh的回答是正确的。但有一个问题:
\uu defineGetter\uuu
已被弃用:

已弃用 此功能已从Web标准中删除。 虽然一些浏览器可能仍然支持它,但它正在开发过程中 被丢弃。不要在旧项目或新项目中使用它。网页或Web应用程序 使用它可能随时中断

您应该改用
defineProperty

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

navigator.userAgent; // 'foo'

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

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

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

只要记住,在jasmine中完成测试后重置navigator对象,对于那些试图在TypeScript中执行相同操作的人,解决方案如下:

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

navigator.userAgent; // 'foo'
(导航器)[''定义设置]('userAgent',函数(){
返回“foo”;
});
navigator.userAgent;//'富
或者对语言来说是一样的:

(<any>navigator)['__defineGetter__']('language', function(){
    return 'de-DE';
});
(导航器)[“定义设置”(“语言”,函数)(){
返回“de de”;
});

上述答案不适用于PhantomJS+TypeScript。以下代码适用于我:

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

本主题已晚,但对于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

});

本文提供了帮助:

对于这里的用户,因为他们需要在单元测试中更改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);
否则,您可能会遇到
类型错误:无法重新定义属性
错误。

在Chrome Headless上对我有效。

试试这个,它对我有效,没有皮棉问题

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

你没看到我说的“数百个用户代理字符串”吗?我想你不太明白单元测试的目的。“我只有30个测试用例,为什么不在每次进行最小的更改时手动运行?”请使用User Agent Tester并修改代码,以自动测试所有“数百个User Agent字符串”。如果你知道javascript,那就应该非常简单了。这似乎与用户对JS的了解无关。您的回答不包含任何关于海报如何实际实现此结果的有效信息。这与其说是回答,不如说是评论。你看过env.js了吗?()当然,可以将navigator.userAgent设置为getUserAgent,然后在运行中我可以重新定义getUserAgent。只要我的定义是最后的,嘲弄就变成了事实。但是,它使实际的javascript更大、更笨重、更难看,所以我试图避免这种情况。navigator.userAgent是一个getter,而不是一个“只读字符串属性”。@Elijah Grey,在您看来,getter only和只读属性之间有什么区别?这个解决方案可以用来设置iframe的用户代理吗?对我来说很有用。(即在Windows上)
\uu defineGetter\uu
不推荐使用,请改用
defineProperty
。检查我下面的答案。如果使用角度。。我最近创建了一个要点,使只读属性可写(您可以找到一个示例