Pergunta

Eu estou procurando uma maneira de mudar programaticamente navigator.userAgent na mosca. Na minha tentativa fracassada de obter um testador unidade javascript automatizado, eu desisti e tentou começar a usar fireunit. Imediatamente, eu já bateu em uma das paredes do uso de um navegador real para o teste javascript.

Especificamente, eu preciso mudar navigator.userAgent para simular algumas centenas de cordas useragent assegurar a detecção e cobertura adequada em uma determinada função. navigator.userAgent é somente leitura, então eu parecem preso! Como posso zombar navigator.userAgent? User Agent Switcher (plug-in) pode alternar useragent de FF, mas posso fazê-lo dentro javascript?

Foi útil?

Solução

Tente:

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

navigator.userAgent; // 'foo'

Tentou fazê-lo em FF2 e FF3.

Outras dicas

Adicionando para de Crescent Fresh solução , redefinindo o getter navigator.userAgent não parece trabalho no Safari 5.0.5 (no Windows 7 e Mac OS X 10.6.7).

necessidade de criar um novo objeto que herda o objeto navigator e definir um novo getter userAgent para esconder o getter userAgent original navigator:

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

A solução a seguir funciona no Chrome, Firefox, Safari, IE9 + e também com iframes:

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

Exemplos:

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

Usando Object.defineProperty deve adicionar mais alguns navegadores para a mistura:

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

Este código deve funcionar (e foi testado) em Firefox 1.5 + , Chrome 6 + , Opera 10.5 + e IE9 + . Infelizmente Safari em qualquer plataforma não permite mudar o userAgent.

Edit:. Safari não permite mudar o userAgent, mas pode-se substituir a toda navegador objeto, como fora apontado em outra solução acima

A resposta de Crescent Fresh está correto. Mas há um problema: __defineGetter__ está obsoleta:

https: //developer.mozilla. org / en-US / docs / web / JavaScript / Referência / Global_Objects / objeto / defineGetter

Deprecated Esse recurso foi removido dos padrões da Web. Embora alguns navegadores ainda podem apoiá-lo, é no processo de ser descartado. Não usá-lo em projetos novos ou antigos. Páginas ou aplicativos da Web usá-lo pode quebrar a qualquer momento.

Você deve usar defineProperty vez:

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

navigator.userAgent; // 'foo'

Para atualizar esta discussão, defineGetter não funciona mais em Jasmine, uma vez que foi substituído. No entanto eu achei isso me permite modificar o getter para navigator.userAgent no jasmim:

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

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

Apenas lembre-se redefinir o objeto de navegação, uma vez que são teste feito no jasmim

Para aqueles que tentam fazer a mesma coisa à máquina aqui está a solução:

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

navigator.userAgent; // 'foo'

Ou mesmo para o idioma:

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

Eu acho que eu tomaria uma abordagem injeção de dependência. Em vez de:

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

Talvez fazer algo como:

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

Depois, você pode "zombar de" getUserAgent() fazendo:

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

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

Este projeto ainda não está completamente automatizado (você tem que renomear manualmente o getter para realizar o seu teste), e acrescenta um monte de complexidade para algo tão simples quanto operando em navigator.userAgent, e eu não sei como você' d realmente identificar eventuais erros em myFunction, mas eu só percebi que eu jogá-lo fora lá para lhe dar algumas idéias de como isso pode ser tratada.

Talvez a idéia de "injeção de dependência" aqui apresentado pode de alguma forma ser integrado com FireUnit.

Para aqueles aqui, porque eles precisam para alterar o valor userAgent em testes de unidade, obras de solução de Tyler Long, mas se você deseja restaurar o userAgent inicial ou alterá-lo mais de uma vez, você provavelmente terá que definir a propriedade como configurável:

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

Caso contrário, você pode correr em um erro de TypeError: Cannot redefine property. Obras para me no Chrome sem cabeça.

navigator.userAgent é uma propriedade string somente de leitura, por isso não é possível editá-lo

respostas acima não estavam trabalhando para PhantomJS + texto datilografado. Abaixo código funcionou para mim:

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

Tarde para este tema, mas para Carma + Jasmin e Typescript e quiser definir a propriedade userAgent isso vai fazê-lo:

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

});

Este artigo ajudou: https://www.codeproject.com / Dicas / 1036762 / Mocking-userAgent-com-JavaScript

Alterar navigator.userAgent no Firefox e Opera via defineGetter

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

alert( navigator.userAgent ); //iPhone 5

Alterar navigator.userAgent no IE e Opera via instância do objeto

var navigator = new Object; 
navigator.userAgent = 'iPhone 5';

alert( navigator.userAgent ); //iPhone5

Boa coisa é, se você trabalha em controle webbrowser IE, você pode dobrar paródia tanto solicitação HTTP e JavaScript navigator.userAgent via execScript

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

Não, eu duvido que você pode fazê-lo dentro de javascript. Mas com usuário do Firefox Agent Switcher você pode testar tudo o que useragent você quer, então por que não usar isso?

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top