Come forzare Selenium WebDriver a fare clic su un elemento che non è attualmente visibile?


99

Sto usando l'API Java Selenium 2 con FirefoxDriver. Quando compilo un modulo, le caselle di controllo vengono aggiunte alla pagina a seconda degli input del modulo.

Vorrei simulare un clic su quelle caselle di controllo utilizzando Selenium. L'elemento è visibile e utilizzabile in un normale browser, ma il selenio afferma che gli elementi non sono visibili.

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

Posso forzare il selenio a ignorare lo stato non visibile degli elementi? Come posso forzare il selenio a interagire con l'elemento non visibile?


Quale browser utilizzate? Non è possibile interagire con elementi disabilitati o non visibili perché un utente finale non sarebbe in grado di interagire con essi. Dovrai fornire il codice di prova e l'origine della pagina se desideri che provi a diagnosticare il problema.
Ardesco

Risposte:


102

Il selenio determina che un elemento è visibile o meno in base ai seguenti criteri (usa un ispettore DOM per determinare quale CSS si applica al tuo elemento, assicurati di guardare lo stile calcolato):

  • visibilità! = nascosto
  • display! = nessuno (viene verificato anche rispetto a ogni elemento genitore)
  • opacity! = 0 (questo non è controllato per fare clic su un elemento)
  • l'altezza e la larghezza sono entrambe> 0
  • per un input, il tipo di attributo! = nascosto

Il tuo elemento corrisponde a uno di questi criteri. Se non hai la possibilità di cambiare lo stile dell'elemento, ecco come puoi farlo forzatamente con javascript (andando ad assumere WebDriver visto che hai detto API Selenium2):

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

Ma questo non attiverà un evento javascript, se dipendi dall'evento di modifica per quell'input dovrai attivarlo anche tu (molti modi per farlo, più facile da usare qualsiasi libreria javascript sia caricata su quella pagina).

La fonte per il controllo della visibilità -

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

La specifica WebDriver che definisce questo:

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


1
Hai una fonte (o un link canonico) per l'elenco delle condizioni?
mjs

2
Finché puoi leggere Javascript, il metodo bot.dom.isShown è ciò che determina la visibilità: code.google.com/p/selenium/source/browse/trunk/javascript/atoms/…
lukeis

cos'è inputElement qui. Eseguo il codice sottostante WebElement inputElement = driver.findElement (By.xpath (PASSWORD_PATH)); ((JavascriptExecutor) driver) .executeScript ("arguments [0] .checked = true;", inputElement); Ma nessun aiuto inputElement.sendKeys (password);
Deepak Goel

2
@NIleshSharma python ha il metodo execute_script direttamente sull'oggetto driver stesso: driver.execute_script (...)
lukeis

1
Il link sorgente pubblicato da @TunaBum è cambiato in code.google.com/p/selenium/source/browse/javascript/atoms/…
Shepmaster

27

A volte questo significa che ci sono più elementi in una pagina che hanno la stessa proprietà con cui stai cercando di cercare e stai "parlando con quello sbagliato".

Se il tuo elemento non può essere identificato in modo univoco da: id o: name (o: class), potrebbe essere complicato.

A volte la ricerca dell'elemento tramite: xpath sarà di aiuto e in alcuni casi anche questo non è pratico.

In questi casi, potresti dover ottenere tutti gli elementi che corrispondono ai tuoi criteri e fare riferimento a quello giusto dall'indice. È sporco, ma funziona.

Sto usando Selenium / Watir dall'app Ruby on Rails, quindi nel mio caso l'esempio sarebbe:

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

Spero che questo ti aiuti.


l'aggiunta di un ID all'elemento dom lo ha risolto per me
naoru

Ho avuto lo stesso problema e la regolazione dell'XPath in modo che potesse distinguere un elemento unico ha funzionato.
JohnL

Ho avuto lo stesso problema. Chiamata modificata a findElements () per contare le corrispondenze e c'era un altro elemento corrispondente. Grazie!
Ariete

Tanto questo per me. SEMPRE assicurati che i tuoi criteri di selezione siano sufficientemente specifici per l'elemento con cui pensi di interagire. Molte volte ho avuto due elementi in gioco e uno è nascosto e mi dà questo errore.
Chris,

14

Ho riscontrato un problema simile, ma era correlato al fatto che l'elemento non era visibile nella finestra. Ho fatto uno screenshot e mi sono reso conto che la finestra del browser era troppo stretta e l'elemento non poteva essere visto. Ho fatto uno di questi e ha funzionato:

driver.maximize_window()

Vedere: WebDriver.maximize_window ()


7

Oppure puoi usare Selenium Action Class per simulare l'interazione dell'utente, ad esempio

    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();

7

C'è anche un altro caso in cui l'elemento visibile verrà riconosciuto come non visibile:

  • Quando l'elemento viene trasformato in CSS
  • Quando l'elemento padre dell'elemento viene trasformato in CSS

Per verificare se l'elemento con cui non vuoi interagire è trasformato in CSS, su CHROME fai questo:

  1. ispettore aperto
  2. Trova elemento interessante (o più probabilmente il suo elemento genitore, presumibilmente elemento div)
  3. Seleziona la scheda "Calcolato"
  4. se c'è un parametro: webkit-transform: matrix (...) significa che l'elemento è trasformato CSS, e potrebbe non essere riconosciuto dal selenio 2 come elemento visibile


2

Ho avuto lo stesso problema con il selenio 2 in Internet Explorer 9, ma la mia soluzione è davvero strana. Non sono stato in grado di fare clic sugli input all'interno del mio modulo -> ripetizioni di selenio, non sono visibili.

Si è verificato quando la mia forma aveva ombre curve -> http://www.paulund.co.uk/creating-different-css3-box-shadows-effects : nel cemento "Effetto n. 2"

Non ho idea, perché e come questa soluzione di pseudo elementi abbia fermato i test del selenio, ma per me funziona.


2

Non è possibile forzare l'accesso / la modifica di un elemento a cui l'utente normalmente non ha accesso, poiché Selenium è progettato per imitare l'interazione dell'utente.

Se si verifica questo errore, controlla se:

  • l'elemento è visibile nel tuo viewport, prova a massimizzare la finestra corrente che il webdriver sta usando (ad esempio maximize()in node.js , maximize_window()in Python),
  • il tuo elemento non viene visualizzato due volte (sotto lo stesso selettore) e stai selezionando quello sbagliato,
  • se il tuo elemento è nascosto, considera di renderlo visibile,
  • se desideri accedere / modificare il valore dell'elemento nascosto nonostante la limitazione, usa Javascript per quello (ad esempio executeScript()in node.js , execute_script()in Python).

1
Non avevo idea che il selenio fosse progettato per essere così rigoroso. Sembra che non sia davvero uno strumento di automazione in senso generale, più di uno strumento di interazione utente automatizzato. Ha un senso, immagino. Grazie per il chiarimento!
Daniel Lidström

1

Ho appena risolto questo errore durante l'utilizzo di capybara nel progetto ror aggiungendo:

Capybara.ignore_elements = true

a features/support/env.rb.


1

Risolvo questo errore semplicemente aspettando la proprietà di visualizzazione dell'elemento

waitFor() { element.displayed }

Di tutte le risposte in questa pagina, questo è ciò che ha risolto il mio problema con una finestra di dialogo Modale Bootstrap. Grazie @Suat Keskin!
alastairs

1

Entro nell'eccezione ElementNotVisibleException utilizzando il selenio per i test funzionali su un sito django con gliphicons bootstrap come collegamenti nei modelli come:

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

Durante i miei test funzionali, lo stile di bootstrap non viene caricato, quindi provare a fare clic su tali collegamenti genererà ElementNotVisibleException. Riesco a renderli cliccabili semplicemente aggiungendo uno spazio nel tag, in questo modo:

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

1

Ci sono molte buone risposte in questa pagina.

  1. Di solito inizio con maxim.window (), in realtà lo faccio nella fabbrica dei driver o ovunque si inizializzi il driver. Questo è qualcosa fatto per impostazione predefinita, sempre.
  2. Di solito è un elemento di attesa a causa di alcuni ritardi di javascript.

Entrambi sono discussi in vari dettagli sopra. La risposta che non ho visto è stata ScrollToElement. Sembra che tu stia elaborando un elenco di elementi, mentre elaborando stai creando più elementi, caselle di controllo. Ciò può causare lo spostamento degli elementi nell'elenco dalla pagina visibile. A volte puoi vedere l'elemento ad occhio nudo ma non puoi semplicemente cliccarci sopra. Quando si elaborano gli elenchi, a volte è necessario intercettare lo scorrimento.

  • Imposta un punto di interruzione e controlla se l'elemento che stai utilizzando si trova sul bordo della finestra, in alto / in basso a destra / a sinistra. A volte in questo caso non puoi accedervi tramite selenio ma puoi fare clic manualmente con il mouse.

Poiché mi imbatto in questo, ho creato un PageScroll.java e ho inserito i miei script di scorrimento lì. Ecco alcuni dei metodi di questa 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);
    }

vedi Scorri l'elemento nella vista con selenio per ulteriori esempi


0

La risposta accettata ha funzionato per me. Di seguito è riportato un codice per trovare l'elemento genitore che fa pensare a Selenium che non sia visibile.

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'));


0

Per aggiungere il mio granello di sabbia qui: se un elemento risiede dietro un div fisso sarà considerato come non visibile e non potrai cliccarci sopra; questo mi è successo di recente e l'ho risolto eseguendo uno script come consigliato sopra, che fa:

document.evaluate("<xpath locator for element to be clicked>", document, null, XPathResult.ANY_TYPE, null).iterateNext().click()", locator);

Cos'è il localizzatore qui?
Anjana
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.