Como forçar o Selenium WebDriver a clicar em um elemento que não está visível no momento?

99

Estou usando a API Selenium 2 Java com FirefoxDriver. Quando eu preencho um formulário, caixas de seleção são adicionadas à página, dependendo das entradas de formulários.

Eu gostaria de simular um clique nessas caixas de seleção usando Selenium. Os elementos são visíveis e podem ser usados ​​em um navegador normal, mas o selênio afirma que os elementos não são visíveis.

"Element is not currently visible and so may not be interacted with"

Posso forçar o selênio a ignorar o estado não visível dos elementos? Como posso forçar o Selênio a interagir com o elemento não visível?

Djondal
fonte
Qual navegador você está usando? Você não pode interagir com elementos que estão desabilitados ou invisíveis porque um usuário final não seria capaz de interagir com eles. Você precisará fornecer seu código de teste e fonte da página se quiser que eu tente diagnosticar o problema.
Ardesco

Respostas:

102

O Selenium determina que um elemento é visível ou não pelos seguintes critérios (use um inspetor DOM para determinar o que css se aplica ao seu elemento, certifique-se de olhar para o estilo calculado):

  • visibilidade! = oculto
  • display! = none (também é verificado em relação a cada elemento pai)
  • opacidade! = 0 (não é verificado ao clicar em um elemento)
  • altura e largura são> 0
  • para uma entrada, o tipo de atributo! = oculto

Seu elemento corresponde a um desses critérios. Se você não tem a capacidade de alterar o estilo do elemento, aqui está como você pode fazer isso de maneira forçada com javascript (assumindo WebDriver já que você disse Selenium2 API):

((JavascriptExecutor)driver).executeScript("arguments[0].checked = true;", inputElement);

Mas isso não disparará um evento javascript, se você depender do evento de mudança para essa entrada, terá que dispará-lo também (muitas maneiras de fazer isso, mais fácil usar qualquer biblioteca javascript carregada nessa página).

A fonte para a verificação de visibilidade -

https://github.com/SeleniumHQ/selenium/blob/master/javascript/atoms/dom.js#L577

A especificação WebDriver que define isso -

https://dvcs.w3.org/hg/webdriver/raw-file/tip/webdriver-spec.html#widl-WebElement-isDisplayed-boolean

lukeis
fonte
1
Você tem uma fonte (ou link canônico) para a lista de condições?
mjs
2
Desde que você possa ler Javascript, o método bot.dom.isShown é o que determina a visibilidade: code.google.com/p/selenium/source/browse/trunk/javascript/atoms/…
lukeis
o que é inputElement aqui. Eu executo o código abaixo WebElement inputElement = driver.findElement (By.xpath (PASSWORD_PATH)); (Driver (JavascriptExecutor)) .executeScript ("arguments [0] .checked = true;", inputElement); Mas não há ajuda inputElement.sendKeys (senha);
Deepak Goel
2
@NIleshSharma python tem o método execute_script diretamente no próprio objeto driver: driver.execute_script (...)
lukeis
1
O link da fonte postado por @TunaBum foi alterado para code.google.com/p/selenium/source/browse/javascript/atoms/…
Shepmaster
27

Às vezes, isso significa que há vários elementos em uma página com a mesma propriedade que você está tentando pesquisar e que você está "falando com a pessoa errada".

Se o seu elemento não puder ser identificado exclusivamente por: id ou: name (ou: class), pode ser complicado.

Às vezes, pesquisar o elemento pelo: xpath pode ajudar e, em alguns casos, nem isso é prático.

Nesses casos, pode ser necessário obter todos os elementos que correspondem aos seus critérios e fazer referência ao correto pelo índice. Está sujo, mas funciona.

Estou usando Selenium / Watir do aplicativo Ruby on Rails, então, no meu caso, o exemplo seria:

browser = Watir::Browser.new(:firefox, :profile => "default")       
browser.goto("http://www.google.com/analytics")
# login
browser.divs(:text, "+ New Property").last.click

Espero que isto ajude.

ranktrackerpro
fonte
adicionar um id ao elemento dom corrigiu para mim
naoru
Eu tive o mesmo problema e ajustar o XPath para que pudesse distinguir um elemento único funcionou.
JohnL
Eu tive o mesmo problema. Alterada a chamada para findElements () para contar correspondências e havia mais um elemento correspondente. Obrigado!
Áries
Muito isso para mim. SEMPRE certifique-se de que seus critérios de seleção sejam específicos o suficiente para o elemento com o qual você pensa que está interagindo. Muitas vezes tive dois elementos em jogo e um está escondido e me dá esse erro.
Chris
14

Eu tive um problema semelhante, mas estava relacionado ao elemento não ser visível na janela de visualização. Eu fiz uma captura de tela e percebi que a janela do navegador era muito estreita e o elemento não podia ser visto. Eu fiz um desses e funcionou:

driver.maximize_window()

Veja: WebDriver.maximize_window ()

mynameistechno
fonte
7

Ou você pode usar a classe de ação Selenium para simular a interação do usuário - por exemplo

    WebDriver = new FirefoxDriver();

    WebElement menu = driver.findElement(By.xpath("")); // the triger event element

    Actions build = new Actions(driver); // heare you state ActionBuider
    build.moveToElement(menu).build().perform(); // Here you perform hover mouse over the needed elemnt to triger the visibility of the hidden
    WebElement m2m= driver.findElement(By.xpath(""));//the previous non visible element
    m2m.click();
fil mihaylov
fonte
7

Há também outro caso em que o elemento visível será reconhecido como não visível:

  • Quando o elemento é transformado em CSS
  • Quando o elemento pai do elemento é transformado em CSS

Para verificar se o elemento com o qual você não deseja interagir foi transformado em CSS, no CHROME faça o seguinte:

  1. inspetor aberto
  2. Encontre um elemento interessante (ou mais provavelmente seu elemento pai, supostamente elemento div)
  3. Selecione a guia 'Computado'
  4. se houver um parâmetro: webkit-transform: matrix (...) isso significa que o elemento é transformado em CSS e pode não ser reconhecido pelo selênio 2 como um elemento visível
justnpT
fonte
5

A invisibilidade também pode ser devido ao momento em que o elemento deve aparecer lentamente. Forçar o navegador a esperar um pouco pode ajudar nesse caso.

Veja, por exemplo, a questão em deixar o WebDriver esperar até que um elemento esteja presente .

avandeursen
fonte
2

Tive o mesmo problema com o selênio 2 no internet explorer 9, mas minha correção é realmente estranha. Não consegui clicar nas entradas dentro do meu formulário -> repetições de selênio, elas não estão visíveis.

Ocorreu quando minha forma tinha sombras curvas -> http://www.paulund.co.uk/creating-different-css3-box-shadows-effects : no concreto "Efeito nº 2"

Não tenho ideia, por que e como essa solução de pseudoelemento interrompeu os testes de selênio, mas funciona para mim.

Agoreddah
fonte
2

Você não pode forçar o acesso / alteração do elemento ao qual o usuário normalmente não tem acesso, pois o Selenium foi projetado para imitar a interação do usuário.

Se esse erro acontecer, verifique se:

  • elemento é visível em sua janela de visualização, tente maximizar a janela atual que o webdriver está usando (por exemplo, maximize()em node.js , maximize_window()em Python),
  • seu elemento não está aparecendo duas vezes (no mesmo seletor) e você está selecionando o errado,
  • se o seu elemento estiver oculto, considere torná-lo visível,
  • se quiser acessar / alterar o valor do elemento oculto, apesar da limitação, use Javascript para isso (por exemplo, executeScript()em node.js , execute_script()em Python).
Kenorb
fonte
1
Eu não tinha ideia de que o Selenium foi projetado para ser tão rígido. Parece que não é realmente uma ferramenta de automação no sentido geral, então, mais uma ferramenta automatizada de interação do usuário. Faz algum sentido, eu acho. Obrigado por esclarecer!
Daniel Lidström
1

Acabei de resolver esse erro ao usar capivara no projeto ror adicionando:

Capybara.ignore_elements = true

a features/support/env.rb.

Zernel
fonte
1

Acabei de resolver esse erro esperando a propriedade de exibição do elemento

waitFor() { element.displayed }
Suat Keskin
fonte
De todas as respostas nesta página, foi isso que corrigiu meu problema com uma caixa de diálogo Bootstrap modal. Obrigado @Suat Keskin!
Alastairs,
1

Eu entro na exceção ElementNotVisibleException usando selenium para testes funcionais em um site django com glifos de bootstrap como links em modelos como:

<a href="{% url 'item-add' %}"><span class="glyphicon glyphicon-plus text-danger"></span></a>

Durante meus testes funcionais, o estilo de bootstrap não é carregado, então tentar clicar em tais links levantará ElementNotVisibleException. Consigo torná-los clicáveis apenas adicionando um espaço na tag, assim:

<a href="{% url 'item-add' %}"><span class="glyphicon glyphicon-plus text-danger">&nbsp;</span></a>
Jean Pierre Huart
fonte
1

Existem muitas respostas boas nesta página.

  1. Normalmente começo com maximize.window (), na verdade faço isso na fábrica do driver ou onde quer que você inicialize seu driver. Isso é algo feito por padrão - sempre.
  2. Geralmente é uma espera pelo elemento devido a algum atraso do javascript.

Ambos são discutidos em vários detalhes acima. A resposta que não vi foi ScrollToElement. Parece que você está processando uma lista de elementos, enquanto processa você está criando mais elementos, caixas de seleção. Isso pode fazer com que os elementos da sua lista saiam da página visível. Às vezes, você pode ver o elemento a olho nu, mas simplesmente não consegue clicar nele. Ao processar listas, às vezes é necessário interromper a rolagem.

  • Defina um ponto de interrupção e verifique se o elemento que você está usando está na borda da janela, superior / inferior direito / esquerdo. Às vezes, quando este é o caso, você não pode acessá-lo via selênio, mas pode clicar manualmente com o mouse.

Como eu encontrei isso, criei um PageScroll.java e coloquei meus scripts de rolagem lá. Aqui estão alguns dos métodos desta classe:

public static void scrollToTop(WebDriver driver) {
      ((JavascriptExecutor) driver)
        .executeScript("window.scrollTo(0,0)");
    }

    public static void scrollToBottom(WebDriver driver) {
      ((JavascriptExecutor) driver)
        .executeScript("window.scrollTo(0, document.body.scrollHeight)");
    }

    public static void scrollToElementTop(WebDriver driver, WebElement element) {
      ((JavascriptExecutor) driver).executeScript(
        "arguments[0].scrollIntoView(true);", element);
    }

    public static void scrollToElementBottom(WebDriver driver, WebElement element) {
      ((JavascriptExecutor) driver).executeScript(
        "arguments[0].scrollIntoView(false);", element);
    }

veja Scroll Element into View with Selenium para mais exemplos

mancocapac
fonte
0

A resposta aceita funcionou para mim. Abaixo está um código para encontrar o elemento pai que está fazendo o Selenium pensar que não está visível.

function getStyles(element){
	
	computedStyle = window.getComputedStyle(element);

	if(computedStyle.opacity === 0
	|| computedStyle.display === "none"
	|| computedStyle.visibility === "hidden"
	|| (computedStyle.height < 0 && computedStyle.height < 0)
	|| element.type === "hidden") {
		console.log("Found an element that Selenium will consider to not be visible")
		console.log(element);
		console.log("opacity: " + computedStyle.opacity);
		console.log("display: " + computedStyle.display);
		console.log("visibility: " + computedStyle.visibility);
		console.log("height: " + computedStyle.height);
		console.log("width: " + computedStyle.width);
	}

	if(element.parentElement){
		getStyles(element.parentElement);
	}
}

getStyles(document.getElementById('REPLACE WITH THE ID OF THE ELEMENT YOU THINK IS VISIBLE BUT SELENIUM CAN NOT FIND'));

starmer
fonte
0

Para adicionar meu grão de areia aqui: se um elemento residir atrás de um div fixo, ele será considerado não visível e você não poderá clicar nele; isso aconteceu comigo recentemente e resolvi executando um script como recomendado acima, que faz:

document.evaluate("<xpath locator for element to be clicked>", document, null, XPathResult.ANY_TYPE, null).iterateNext().click()", locator);
Fernando gabrieli
fonte
O que é o localizador aqui?
Anjana