Após 2 meses encarando o mesmo problema e bebendo muito café, finalmente consegui solucioná-lo, depois de muito desgaste e tentativas em vão, e vou compartilhar o conhecimento convosco!
É o seguinte: trabalho em um projeto web e desenvolvo test cases em Ruby WATIR para a automação de testes de regressão.
E eis que fui incumbido de desenvolver o test case para uma determinada página de cadastro. Entretanto, tal página utiliza um componente de texto do tipo rich-text, que oferece certas funcionalidades de edição de texto, como formatação de fonte, parágrafo, cores de fundo, etc. Utilizamos uma biblioteca free para isto: Whizzywig.
Este componente é utilizado na nossa view como um componente HTML TEXTAREA, mas depois é executado um método em javascript que o transforma em um IFRAME criando uma nova sub-página com todas essas funcionalidades, da seguinte maneira:
<textarea id="descriptionId" name="description">
(...)
</textarea>
<script type="text/javascript">
(...)
makeWhizzyWig("descriptionId", "bold italic underline |
left center right | number bullet indent outdent |
undo redo | color hilite rule");
</script>
Nestas condições, para fazer o WATIR preencher o conteúdo deste componente, não é possível utilizar o seguinte código (considerando @browser como a instância de Watir::Browser):
@browser.text_field(:id, "descriptionId")
Isto ocorre pois componentes rich-text têm a responsabilidade de escrever em HTML (para dar suporte à tais formatações), e para isto eles utilizam um IFRAME, e NÃO É POSSÍVEL PERMITIR AO USUÁRIO ESCREVER DIRETAMENTE NUM IFRAME. A mágica que ele faz para isto é a seguinte: é configurado um listener de teclado no IFRAME, e a cada tecla pressionada, ele programaticamente “digita” esta tecla no IFRAME, ou seja, ele escreve em seu conteúdo utilizando o DOM de sua página. O componente engana tão bem, que até tem o cursor de texto piscando à medida que o usuário “digita”.
Isto pode ser lindo, mas impossibilita nosso querido WATIR a setar o conteúdo deste campo TEXTAREA!
A solução que encontrei é navegar programaticamente até o conteúdo do IFRAME e alterar diretamente lá.
No Internet Explorer, eu naveguei no conteúdo HTML gerado (através do plugin IE Developer Toolbar) e consegui fazer isto sem muito esforço:
@browser.
frame(:id, "whizzydescriptionId").
locate_tagged_element("body", :id, "descriptionId").
innerText = $Description
Isto é possível pois o Internet Explorer é acessado pelo WATIR através da API do Windows.
Agora, no Firefox, a história já é completamente diferente! Pois o mesmo é acessado pelo WATIR através de um plugin chamado JSSH. Esse plugin abre uma sessão em um terminal, e responde a comandos próprios (que permitem mais ou menos utilizar javascript). O FireWatir trabalha enviando comandos via socket ao plugin JSSH do Firefox, que se encarrega de realizar o trabalho sujo com o browser.
Primeiramente, eu tentei utilizar todas as formas possíveis de javascripts para alterar o DOM da página em exibição, mas isto não alterava a página em tempo de execução, mas sim em uma nova página gerada.
Depois de muito quebrar a cabeça, mergulhei na API do JSSH (que tem documentação fraca), abri um terminal e comecei a tentar de tudo, comando por comando, até que uma hora cheguei à solução! E consegui alterar o conteúdo do IFRAME em tempo de execução, manipulando seu DOM!
O código que utilizei foi o seguinte:
@browser.
jssh_socket.send(
"#{FireWatir::Firefox::DOCUMENT_VAR}.
getElementsByTagName('iframe')[0].contentDocument.
body.innerHTML = '" + $Description + "';\n", 0)
@browser.read_socket()
O que ele faz é o seguinte: envia um comando para o JSSH via socket, e depois lê a resposta socket (este comando não tem resposta, mas esta chamada é necessária, é como se fosse um flush).
Para localizar o objeto referente ao browser em execução, utilizamos a constante #{FireWatir::Firefox::DOCUMENT_VAR}. A partir daí entramos na API do JSSH, e navegando por vários atributos, chegamos a poder setar o conteúdo do IFRAME. Ufa!
Espero que isto seja útil a alguém! :)
Quinta-feira, 16 de Abril de 2009 at 19:19
seria se fosse capaz de perceber 10% do que dizes!
Mas parab´nes na mesma! Eu vou ficar por aqui pois já percebi que a minha camioneta não leva tanta areia!!
bom trabalho