Estamos na web 2.0 indo para web 3.0, sites usando e abusando de javascript e xhtml para fazer coisas que antes (e coloca antes nisso.. porque esse discurso esta ficando batido) só eram possíveis usando flash ou applets em javascript sujos e mal codificados.

O grande ideia por trás “ajax” é que ele modifica o comportamento dos objetos da tela em “tempo real” através de requisições http que não são visíveis aos usuários. Para entender melhor como funciona, você pode instalar o firebug do firefox, deixar o modo console aberto de uma página que utiliza bastante funcionalidades em ajax e você verá a quantidade de requisições feitas sem que a página seja recarregada por completo.

Por que estou falando tudo isso? Muitos de vocês já devem estar “carecas” de saber porém esquecem na hora de automatizar uma aplicação que usa ajax.

Outra coisa que é preciso ter em mente que ajax é javascript e javascript é carregado e executado na tela do usuário, não é igual C#, Java, PHP ou ASP (eca), onde o servidor que hospeda a página interpreta as tags da linguagem, processa o conteúdo e retorna valores para o usuário que esta acessando. Tags com códigos em Javascript podem ficar no meio do HTML e é carregado de acordo com sua posição no código ( a famosa macarronada da tia gorda de segundo grau que você só vê nos aniversários ou quando alguém morre…rs).

O manual de boas praticas diz que você deve concentrar suas funções javascript em arquivos separados e adicioná-los a página principal através de includes nos cabeçalhos das páginas, mas isso não é o que todos fazem.  Existe muito programador que faz gambiara no código e coloca <script> no meio do código ou até mesmo no final dele e quando você vai ver, é referente a uma funcionalidade de cabeçalho. Na pratica isso não causa problemas para os usuários que estão acessando a site, no máximo 1 segundo esperando para carregar mas para automatizar, faz TODA a diferença.

1 segundo é o tempo que o Selenium procura e “clica” no objeto e logo procura a próxima etapa e se ela depender de uma requisição ajax e o javascript referente for o último a ser carregado na tela, seu código VAI FALHAR e você não vai saber porque (bom.. agora você já sabe :D )

Mas não fique desesperado! Existe soluções para tratar esse tipo de caso, algumas bem simples e funcionais (que eu vou citar) outras um pouco mais complicadas (que eu somente vou linkar.. thanks lucas ;)

Primeiro vamos para o comando base para isso. Pode parecer “chover” no molhado mas isso resolve a grande maioria dos seus problemas.

Código:

selenium.waitForPageToLoad("30000");

a função “waitForPageToLoad” deve vir após um click para carregar alguma pagina e é vital para que seu teste não quebre por besteira.
Antes de passar para a próxima requisição, ele vai esperar o tempo determinado no parâmetro da função para grande parte da pagina carregar ou vai dar “timeout”.

Código:

for (int second = 0;; second++) {
 if (second >= 60) fail("timeout");
 try { if (selenium.isElementPresent("Objeto")) break; } catch (Exception e) {}
 Thread.sleep(1000);
 }

A função “isElementPresent” é mais especifica, ela já verifica exatamente o objeto que você quer esperar antes de continuar seus testes.  Usando somente o selenium IDE, o “fonte” é mais simples, o a função “waitForElementPresent”  já resolve o problema.
Como isso não foi traduzido em uma função java (mas se você quiser, pode criar uma você mesmo :D ), você deve criar um loop que verifica a cada segundo se o elemento buscado já se encontra carregado (não se assuste,  usando o waitForElementPresent no ide e mudando o formato para java, ele já monta essa logica para você).

Agora vamos para a sessão POG, programação orientada a gato, gambiara ou as famosas alternativas operacionais…rs
Pode acontecer que mesmo usando esses métodos, o selenium não encontre o elemento, mas você debugando sozinho consegue encontrar.
Lembra aquele problema que citei no inicio do post? O elemento “xyz” esta carregado, mas o javascript que que altera a funcionalidade dele esta no final da pagina e sendo assim.. seu teste vai falhar.

O que você pode fazer é colocar uma validação do último elemento da tela.. ou seja… só prossegue o teste se o último objeto da tela for carregado.

Também procure saber se o selenium IDE buscou / salvou o elemento correto usado no função ajax.  Pode ser que a função onclick para carregar algo esteja na “div” e não na imagem como você pensou que fosse, ou vise e versa…rs
No exemplo abaixo do painel de controle da locaweb não existe problema, pois clicando na imagem você já estará clicando no <span> que contem a função “onClick”, mas é um bom exemplo para se ter cuidado.

Painel Locaweb

Função em Ajax para abrir as propriedades de uma hospedagem, perceba que a função onclick se encontra na tag

A outra forma de não ter problemas com ajax é um pouco mais complicada.  Ela consiste em saber qual include que a página carrega e para fazer isso, injeta uma código javascript para poder verificar se já carregou o include desejado. Para acessar esse pequeno tutorial, clique aqui (quando eu tiver tempo eu traduzo e explico melhor a solução)

[Update] Conversando com o dr. knorr (sim, aquele mesmo) , ele apresentou uma solução que parece complicada mas é muito mais bonita e elegante

Código:

selenium.waitForCondition("var x = selenium.browserbot.findElementOrNull('id=NomeElemento'); x != null;", "50000");  // By Knorr

OU

waitForCondition("selenium.browserbot.getCurrentWindow().document.
getElementById('btn_forward')",10000)  // By Dan Fabulich

Basicamente, o selenium fica em standby esperando uma condição que neste caso é um inject de javascript na página. A função waitForCondition tem como parâmetros uma expressão (que no geral deve retornar true) e o timeout caso ele não encontre nada.

Espero que tenham compreendido.

Até a próxima.