Zombando de um useragent em javascript?
-
19-09-2019 - |
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?
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:
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?