Espero que seja só eu, mas o Selenium Webdriver parece um pesadelo completo. No momento, o driver da web do Chrome não pode ser usado e os outros drivers não são confiáveis, ao que parece. Estou lutando contra muitos problemas, mas aqui está um.
Aleatoriamente, meus testes falharão com um
"org.openqa.selenium.StaleElementReferenceException: Element is no longer attached
to the DOM
System info: os.name: 'Windows 7', os.arch: 'amd64',
os.version: '6.1', java.version: '1.6.0_23'"
Estou usando o webdriver versões 2.0b3. Eu já vi isso acontecer com os drivers FF e IE. A única maneira de evitar isso é adicionar uma chamada real Thread.sleep
antes que a exceção ocorra. Essa é uma solução alternativa ruim, portanto, espero que alguém possa apontar um erro da minha parte que melhore tudo isso.
java
selenium-webdriver
webdriver
automated-tests
Ray Nicholus
fonte
fonte
from selenium.common.exceptions import NoSuchElementException
Respostas:
Sim, se você está tendo problemas com o StaleElementReferenceExceptions, é porque seus testes são mal escritos. É uma condição de corrida. Considere o seguinte cenário:
Agora, no ponto em que você está clicando no elemento, a referência do elemento não é mais válida. É quase impossível para o WebDriver adivinhar todos os casos em que isso pode acontecer - por isso, ele levanta as mãos e dá controle a você, que, como autor do teste / aplicativo, deve saber exatamente o que pode ou não acontecer. O que você deseja fazer é esperar explicitamente até que o DOM esteja em um estado em que você saiba que as coisas não vão mudar. Por exemplo, usando um WebDriverWait para aguardar a existência de um elemento específico:
O método presenceOfElementLocated () ficaria assim:
Você está certo sobre o atual driver Chrome ser bastante instável e ficará feliz em saber que o tronco do Selenium possui um driver Chrome reescrito, onde a maior parte da implementação foi feita pelos desenvolvedores do Chromium como parte de sua árvore.
PS. Como alternativa, em vez de esperar explicitamente como no exemplo acima, você pode ativar as esperas implícitas - dessa forma, o WebDriver sempre fará um loop até o tempo limite especificado, aguardando a presença do elemento:
Na minha experiência, porém, esperar explicitamente é sempre mais confiável.
fonte
com.google.common.base.Function<F, T>
fornecido pela Guava .Consegui usar um método como este com algum sucesso:
Sim, ele continua pesquisando o elemento até que não seja mais considerado obsoleto (novo?). Realmente não chega à raiz do problema, mas descobri que o WebDriver pode ser bastante exigente quanto a lançar essa exceção - às vezes eu entendo e às vezes não. Ou pode ser que o DOM realmente esteja mudando.
Portanto, não concordo totalmente com a resposta acima de que isso indica necessariamente um teste mal escrito. Eu o tenho em páginas novas com as quais não interagi de forma alguma. Eu acho que há alguma falha na forma como o DOM é representado ou no que o WebDriver considera obsoleto.
fonte
Às vezes, recebo esse erro quando as atualizações do AJAX estão no meio do caminho. A Capivara parece ser bastante esperta em aguardar alterações no DOM (consulte Por que o wait_until foi removido da Capivara ), mas o tempo de espera padrão de 2 segundos simplesmente não foi suficiente no meu caso. Alterado em _spec_helper.rb_ com por exemplo
fonte
Eu estava enfrentando o mesmo problema hoje e criei uma classe de wrapper, que verifica antes de cada método se a referência do elemento ainda é válida. Minha solução para recuperar o elemento é bastante simples, então eu pensei em compartilhá-lo.
Você vê que eu "localizo" ou salve o elemento em uma variável js global e recupere o elemento, se necessário. Se a página for recarregada, essa referência não funcionará mais. Mas desde que apenas sejam feitas alterações na desgraça, a referência permanece. E isso deve fazer o trabalho na maioria dos casos.
Também evita pesquisar novamente o elemento.
John
fonte
Eu tive o mesmo problema e o meu foi causado por uma versão antiga de selênio. Não consigo atualizar para uma versão mais recente devido ao ambiente de desenvolvimento. O problema é causado por HTMLUnitWebElement.switchFocusToThisIfNeeded (). Quando você navega para uma nova página, pode acontecer que o elemento em que você clicou na página antiga seja o
oldActiveElement
(veja abaixo). O Selenium tenta obter contexto do elemento antigo e falha. É por isso que eles criaram uma tentativa de tentar lançamentos futuros.Código da versão selenium-htmlunit-driver <2.23.0:
Código da versão selenium-htmlunit-driver> = 2.23.0:
Sem atualizar para a versão 2.23.0 ou mais recente, você pode fornecer qualquer elemento no foco da página. Eu apenas usei
element.click()
por exemplo.fonte
Aconteceu comigo ao tentar enviar as teclas para uma caixa de entrada de pesquisa - que possui atualização automática dependendo do que você digita. Como mencionado pelo Eero, isso pode acontecer se o seu elemento atualizar o Ajax enquanto você digita o texto dentro do elemento de entrada. . A solução é enviar um caractere de cada vez e procurar novamente o elemento de entrada . (Ex. Em rubi mostrado abaixo)
fonte
Para adicionar à resposta do @ jarib, criei vários métodos de extensão que ajudam a eliminar a condição de corrida.
Aqui está a minha configuração:
Eu tenho uma classe chamada "Driver.cs". Ele contém uma classe estática cheia de métodos de extensão para o driver e outras funções estáticas úteis.
Para elementos que geralmente preciso recuperar, crio um método de extensão como o seguinte:
Isso permite recuperar esse elemento de qualquer classe de teste com o código:
Agora, se isso resultar em a
StaleElementReferenceException
, eu tenho o seguinte método estático na minha classe de driver:O primeiro parâmetro dessa função é qualquer função que retorna um objeto IWebElement. O segundo parâmetro é um tempo limite em segundos (o código do tempo limite foi copiado do Selenium IDE for FireFox). O código pode ser usado para evitar a exceção do elemento obsoleto da seguinte maneira:
O código acima chamará
driver.SpecificElementToGet().Displayed
até quedriver.SpecificElementToGet()
não haja exceções e.Displayed
avalietrue
e 5 segundos não passaram. Após 5 segundos, o teste falhará.Por outro lado, para esperar que um elemento não esteja presente, você pode usar a seguinte função da mesma maneira:
fonte
Acho que encontrei uma abordagem conveniente para lidar com StaleElementReferenceException. Geralmente, você precisa escrever wrappers para cada método WebElement para tentar novamente as ações, o que é frustrante e gasta muito tempo.
Adicionando este código
antes que cada ação do WebElement possa aumentar a estabilidade de seus testes, mas você ainda poderá obter StaleElementReferenceException de tempos em tempos.
Então é isso que eu criei (usando o AspectJ):
Para habilitar esse aspecto, crie um arquivo
src\main\resources\META-INF\aop-ajc.xml
e graveAdicione isto ao seu
pom.xml
E isso é tudo. Espero que ajude.
fonte
Você pode resolver isso usando a espera explícita para não precisar esperar muito.
Se você buscar todos os elementos com uma propriedade e iterar através dela usando para cada loop, poderá usar wait dentro do loop dessa maneira,
ou para um único elemento, você pode usar o código abaixo,
fonte
No Java 8, você pode usar um método muito simples para isso:
fonte
fonte