Rolar elemento para exibição com selênio


208

Existe alguma maneira no Selenium 1.x ou 2.x para rolar a janela do navegador para que um elemento específico identificado por um XPath esteja à vista do navegador? Existe um método de foco no Selenium, mas parece não rolar fisicamente a exibição no FireFox. Alguém tem alguma sugestão sobre como fazer isso?

A razão pela qual eu preciso disso é que estou testando o clique de um elemento na página. Infelizmente, o evento parece não funcionar, a menos que o elemento esteja visível. Eu não tenho controle do código que é acionado quando o elemento é clicado, por isso não posso depurar ou fazer modificações nele; portanto, a solução mais fácil é rolar o item para exibição.


Você pode tentar este hacky se nada mais funcionar para você : stackoverflow.com/a/53771434/7093031
YB Causa

Respostas:


215

Já tentei muitas coisas com relação à rolagem, mas o código abaixo forneceu melhores resultados.

Isso rolará até que o elemento esteja em exibição:

WebElement element = driver.findElement(By.id("id_of_element"));
((JavascriptExecutor) driver).executeScript("arguments[0].scrollIntoView(true);", element);
Thread.sleep(500); 

//do anything you want with the element

6
Esta é uma solução interessante para quando você pode ter um elemento position: fixedna sua página e está obscurecendo o elemento que o Selenium deseja clicar. Muitas vezes, esses elementos fixos ficam na parte inferior, portanto, a configuração o scrollIntoView(true)move muito bem para o topo da viewport.
precisa

3
Com base na versão mais recente do selênio (2.53), agora é uma ótima solução auxiliar. O selênio nem sempre está rolando o elemento à vista, então isso definitivamente é útil.
Zoidberg

20
Passe truepara scrollIntoViewse o objeto para o qual você está rolando está abaixo de onde você está atualmente, falsese o objeto para o qual está rolando está acima de onde você está atualmente. Eu tive dificuldade para descobrir isso.
Big Money

2
Por que você precisa de suspensão de thread? executeScript deve ser síncrono
riccardo.tasso

1
@ riccardo.tasso pode ter sido implementado um sono para lidar com o desconhecido do aplicativo de destino. Se houver rolagem dinâmica ou um aplicativo de página única que carrega o próximo bit da página após a rolagem, entre outras possibilidades. Falando por experiência própria, o Selenium freqüentemente quebrou o site da minha empresa porque a ação automatizada ocorreu mais rapidamente do que o Javascript podia concluir e, portanto, passou um modelo de dados incompleto. Alguns lugares podem considerá-lo um bug, mas disseram-me: "Nenhum humano jamais poderia invocar esse cenário, portanto não é um bug real". É a vida.
Solonotix 21/11/19

157

Você pode usar a org.openqa.selenium.interactions.Actionsclasse para ir para um elemento.

Java:

WebElement element = driver.findElement(By.id("my-id"));
Actions actions = new Actions(driver);
actions.moveToElement(element);
actions.perform();

Pitão:

from selenium.webdriver.common.action_chains import ActionChains
ActionChains(driver).move_to_element(driver.sl.find_element_by_id('my-id')).perform()

7
Isso funcionará se o WebElement não estiver na porta de exibição?
virusrocks 4/15

9
@ Dominik: Como o Selenium moverá o mouse para um elemento que está fora da tela? Obviamente, ele deve primeiro rolar o elemento para exibição e depois mover o mouse para ele. Eu testei. Esse código funciona no Firefox Webdriver 2.48, mas existe um erro: quando você tem um iframe em uma página, a rolagem não funciona corretamente no iframe enquanto o elemento.LocationOnScreenOnceScrolledIntoView rola corretamente. (Embora a documentação diz que este comando retorna apenas um local, também rola!)
Elmue

8
Os documentos em seleniumhq.github.io/selenium/docs/api/java/org/openqa/selenium/… agora indicam claramente "Move o mouse para o meio do elemento. O elemento é rolado para exibição e sua localização é calculada usando getBoundingClientRect. "
George Pantazes

5
O código acima é "a maneira oficial" que o Java Selenium deseja que você role um elemento na janela de exibição, no entanto, depois de tentar muitas coisas, a implementação do JS pareceu funcionar mais confiável para mim. Este método em particular.
Kenji Miwa

2
Não funcionou para mim: - | Em vez disso, usou stackoverflow.com/a/23902068/661414 .
Leukipp

28
JavascriptExecutor js = (JavascriptExecutor) driver;
        js.executeScript("javascript:window.scrollBy(250,350)");

Você pode tentar isso.


1
Obrigado. Eu precisava usar esse método em um caso em que a rolagem automática de um Selenium estava causando outro elemento para obscurecer o elemento em que eu precisava clicar. Consegui rolar uma quantia arbitrária para tornar o elemento visível na janela de visualização, sem ser obscurecido.
Daniel Richnak

Isso só vai funcionar no Firefox, Chrome e IE dont apoiar este método
virusrocks

É por isso que você usa js.ExecuteScript("arguments[0].scrollIntoView(true);" + "window.scrollBy(0,-100);", e);para o IE e Firefox e js.ExecuteScript("arguments[0].scrollIntoViewIfNeeded(true);", e);para o Chrome. Simples.
IamBatman # 9/17

((JavascriptExecutor) driver).executeScript("javascript:window.scrollBy(0,250)");Isso funcionou no Chrome. E a única solução que realmente funcionou para mim. Na mesma situação que o primeiro comentarista, eu tinha um elemento fixo na parte inferior que continuava obscurecendo o elemento que eu precisava clicar.
silver


15

Se você deseja rolar na janela do Firefox usando o driver da web Selenium, uma das maneiras é usar JavaScript no código Java. O código JavaScript para rolar para baixo (na parte inferior da página da web) é o seguinte:

JavascriptExecutor js = (JavascriptExecutor) driver;
js.executeScript("window.scrollTo(0, Math.max(document.documentElement.scrollHeight, document.body.scrollHeight, document.documentElement.clientHeight));");

10

Segmentar qualquer elemento e enviar as teclas para baixo (ou para cima / esquerda / direita) também parece funcionar. Sei que isso é um pouco complicado, mas também não gosto da idéia de usar JavaScript para resolver o problema de rolagem.

Por exemplo:

WebElement.sendKeys(Keys.DOWN);

Isso não é menos invasivo do que usar js e realmente é a coisa mais simples. Achei isso principalmente um problema no IE, em que um clique tenta rolar o elemento para exibição, mas não o faz. A solução é tão elegante quanto usar {PGUP} se for feita com o cenário try / catch / loop adequado.
Jibbs

Você salvou o meu dia! Graças
Jesko R.

No meu caso, a página abaixo foi o que funcionou. Este é um bom truque (vs todos os js hacks).
akostadinov

Obrigado @DevDave! Equivalente em C #:var elem = driver.FindElement(By.Id("element_id")); elem.SendKeys(Keys.PageDown);
Watth

9
webElement = driver.findElement(By.xpath("bla-bla-bla"));
((JavascriptExecutor)driver).executeScript("arguments[0].scrollIntoView();", webElement);

Para mais exemplos, clique aqui . Tudo em russo, mas o código Java é intercultural :)


Posso entender por que existe um -1 para esta solução?
Josephnvu 06/07

Porque ele só funciona no Firefox. Nenhum outro navegador suporta esse método.
Wayne Allen

Se alguém precisar de uma tradução do russo para o documento acima mencionado, terá prazer em ajudar.
Monkrus

8

No Selenium, precisamos da ajuda de um executor JavaScript para rolar para um elemento ou rolar a página:

je.executeScript("arguments[0].scrollIntoView(true);", element);

Na declaração acima, elementestá o elemento exato em que precisamos rolar. Eu tentei o código acima e funcionou para mim.

Tenho um post e um vídeo completos sobre isso:

http://learn-automation.com/how-to-scroll-into-view-in-selenium-webdriver/


@ Mukesh otwani o código acima irá rolar para baixo, mas como abt rolar para cima sem usar nenhum pixel definido nele.
khan

6

Você pode usar este trecho de código para rolar:

C #

var element = Driver.FindElement(By.Id("element-id"));
Actions actions = new Actions(Driver);
actions.MoveToElement(element).Perform();

Aí está


6

Isso funcionou para mim:

IWebElement element = driver.FindElements(getApplicationObject(currentObjectName, currentObjectType, currentObjectUniqueId))[0];
 ((IJavaScriptExecutor)driver).ExecuteScript("arguments[0].scrollIntoView(true);", element);

5

O Selenium 2 tenta rolar para o elemento e depois clicar nele. Isso ocorre porque o Selenium 2 não interage com um elemento, a menos que ele pense que é visível.

A rolagem para o elemento acontece implicitamente, então você só precisa encontrar o item e trabalhar com ele.


19
Como isso é uma resposta para a pergunta?
Reinierpost

57
não parece estar funcionando assim para mim. Estou recebendo 'elemento não clicáveis' erros para os elementos que estão fora de vista
DevDave

5
@DevDave Estou com o mesmo problema, exceto no meu caso, o selênio não executa a ação de clique no elemento e não há exceções. Eu não tinha o problema antes e não sei o que causou isso.
Zeinab Abbasimazar

5
A rolagem implícita varia entre os navegadores. Eu tenho um teste de um elemento em um menu pop-up parcialmente na página. Com a gema Ruby, selenium_webdriver 2.43, encontro o navegador chromium 37 (e acredito que o Internet Explorer) de fato rola o item de menu e clica nele. Mas o Firefox 32 parece não rolar e falha com "O elemento não está visível no momento e, portanto, não pode ser interagido".
Skierpage

9
Esta resposta está errada. De acordo com a especificação do Selenium 2.0, WebElement.click()o elemento deve estar visível para clicar nele. Não rolará em seu nome.
Gili

5

Use o driver para enviar chaves como a tecla pagedownou downarrowpara exibir o elemento. Sei que é uma solução muito simples e pode não ser aplicável em todos os casos.


1
Isso não faz sentido. Pode ser necessário enviar uma dúzia de páginas para baixo em uma página grande. É lento e não confiável.
Elmue

2
Sim. Concordo. Mas eu disse "não aplicável em todos os casos"
Ganesh S

Encontrar alguns conhecidos elementna página visível e enviar o PageDown element.SendKeys(Keys.PageDown);funcionou para mim.
Gokul

Aconselho usar a tecla Alt para não rolar a página e usar a cláusula try / except (Python) para manipular erros que podem ocorrer ao tentar enviar chaves para alguns elementos.
Alex K.

4

Pela minha experiência, o Selenium Webdriver não rola automaticamente para um elemento ao clicar quando há mais de uma seção rolável na página (o que é bastante comum).

Estou usando Ruby e, para meu AUT, tive que aplicar um patch ao método de clique da seguinte maneira;

class Element

      #
      # Alias the original click method to use later on
      #
      alias_method :base_click, :click

      # Override the base click method to scroll into view if the element is not visible
      # and then retry click
      #
      def click
        begin
          base_click
        rescue Selenium::WebDriver::Error::ElementNotVisibleError
          location_once_scrolled_into_view
          base_click
        end
      end

O método 'location_once_scrolled_into_view' é um método existente na classe WebElement.

Aprecio que você pode não estar usando Ruby, mas isso deve lhe dar algumas idéias.


Declarei o acima em module Capybara :: module Nodee precisava ligar em native.location_once_scrolled_into_viewvez de apenas location_once_scrolled_into_view. Também salvei ::Selenium::WebDriver::Error::UnknownError, que é o que estou recebendo frequentemente no Firefox 44.0.2. Mas acho que essa solução não é flexível o suficiente e, finalmente, faço as <Element>.native.location_once_scrolled_into_viewchamadas no próprio teste de aceitação, seguido imediatamente page.execute_script('window.scrollByPages(-1)')quando necessário.
Al Chou

Watir tem o método Element#scroll_into_viewque delega para o Selenium location_once_scrolled_into_view. Mas ambos não fazem nada diferente do comportamento padrão do Seleniums, de modo que os elementos de transbordamento ainda podem obstruir o que quer que tentemos clicar.
akostadinov

3

O script Ruby para rolar um elemento para exibição é o seguinte.

$driver.execute_script("arguments[0].scrollIntoView(true);", element)
sleep(3)
element.click

2

Às vezes, também enfrentava o problema de rolar com o Selenium. Então, eu usei o javaScriptExecuter para conseguir isso.

Para rolar para baixo:

WebDriver driver = new ChromeDriver();
JavascriptExecutor js = (JavascriptExecutor)driver;
js.executeScript("window.scrollBy(0, 250)", "");

Ou também

js.executeScript("scroll(0, 250);");

Para rolar para cima:

js.executeScript("window.scrollBy(0,-250)", "");

Ou,

js.executeScript("scroll(0, -250);");

2

Se você acha que outras respostas foram muito hacky, essa também é, mas não há injeção de JavaScript envolvida.

Quando o botão está fora da tela, ele quebra e rola até ele; tente novamente ... ¯ \ _ (ツ) _ / ¯

try
{
    element.Click();
}
catch {
    element.Click();
}

2

Esta é uma solução repetida com JavaScript, mas com um elemento em espera adicionado.

Caso contrário, ElementNotVisibleExceptionpoderá aparecer se alguma ação no elemento estiver sendo realizada.

this.executeJavaScriptFunction("arguments[0].scrollIntoView(true);", elementToBeViewable);
WebDriverWait wait = new WebDriverWait(getDriver(), 5);
wait.until(ExpectedConditions.visibilityOf(elementToBeViewable));

?? <- o que significa?
Choi

1

Eu usei esse caminho para rolar o elemento e clique em:

List<WebElement> image = state.getDriver().findElements(By.xpath("//*[contains(@src,'image/plus_btn.jpg')]"));

for (WebElement clickimg : image)
{
  ((JavascriptExecutor) state.getDriver()).executeScript("arguments[0].scrollIntoView(false);", clickimg);
  clickimg.click();
}

No meu caso, scrollIntoView(false)funcionou, mas scrollIntoView(true)não funcionou . Qualquer um pode funcionar , depende do seu cenário.
rsenna 16/09

Meu caso é o oposto - obras verdadeiras, falhas falsas, mas apenas na medida do clique. Ele rola corretamente para falso, e é o que eu prefiro, mas por qualquer motivo o Selenium ainda não pode vê-lo por clique. Usar pergaminhos verdadeiros é muito alto, mas pelo menos funciona.
Bill Hileman

As teclas de envio do usuário entram em vez de clicar sempre que possível - isso evita problemas se o navegador não estiver com 100% de zoom.
Zunair

1
def scrollToElement(element: WebElement) = {
  val location = element.getLocation
  driver.asInstanceOf[JavascriptExecutor].executeScript(s"window.scrollTo(${location.getX},${location.getY});")
}

1

Convém visitar a página Elementos da Web de rolagem e a página da Web - Selenium WebDriver usando Javascript :

public static void main(String[] args) throws Exception {

    // TODO Auto-generated method stub
    FirefoxDriver ff = new FirefoxDriver();
    ff.get("http://toolsqa.com");
    Thread.sleep(5000);
    ff.executeScript("document.getElementById('text-8').scrollIntoView(true);");
}

@AbhishekBedi Lembro-me de que também é suportado no Chrome. Algum problema específico que você possa ter enfrentado?
virusrocks

1

Na maior parte da situação para rolar esse código funcionará.

WebElement element = driver.findElement(By.xpath("xpath_Of_Element"));                 
js.executeScript("arguments[0].click();",element);

1

JAVA

Tente rolar para o elemento utilizar x yposition e use JavascriptExecutorcom este argumento:"window.scrollBy(x, y)" .

Após a importação:

import org.openqa.selenium.WebElement;
import org.openqa.selenium.JavascriptExecutor;

Primeiro você precisa obter x yo elemento de localização.

//initialize element
WebElement element = driver.findElement(By.id("..."));

//get position
int x = element.getLocation().getX();
int y = element.getLocation().getY();

//scroll to x y 
JavascriptExecutor js = (JavascriptExecutor) driver;
js.executeScript("window.scrollBy(" +x +", " +y +")");


0

O comportamento padrão do Selenium é fazer a rolagem para que o elemento mal seja visualizado na parte superior da janela de visualização. Além disso, nem todos os navegadores têm exatamente o mesmo comportamento. Isso é muito insatisfatório. Se você gravar vídeos dos testes do seu navegador, como eu, o que você deseja é que o elemento role para exibição e seja centralizado verticalmente .

Aqui está minha solução para Java:

public List<String> getBoundedRectangleOfElement(WebElement we)
{
    JavascriptExecutor je = (JavascriptExecutor) driver;
    List<String> bounds = (ArrayList<String>) je.executeScript(
            "var rect = arguments[0].getBoundingClientRect();" +
                    "return [ '' + parseInt(rect.left), '' + parseInt(rect.top), '' + parseInt(rect.width), '' + parseInt(rect.height) ]", we);
    System.out.println("top: " + bounds.get(1));
    return bounds;
}

E então, para rolar, você chama assim:

public void scrollToElementAndCenterVertically(WebElement we)
{
    List<String> bounds = getBoundedRectangleOfElement(we);
    Long totalInnerPageHeight = getViewPortHeight(driver);
    JavascriptExecutor je = (JavascriptExecutor) driver;
    je.executeScript("window.scrollTo(0, " + (Integer.parseInt(bounds.get(1)) - (totalInnerPageHeight/2)) + ");");
    je.executeScript("arguments[0].style.outline = \"thick solid #0000FF\";", we);
}

função getViewPortHeight está faltando ... Em uma suposição que está a tomar a altura do elemento de destino
Shubham Jain

0

Aqui está como eu faço isso com o PHP webDriver for Selenium. Funciona para servidor independente Selenium 2.39.0 + https://github.com/Element-34/php-webdriver + Firefox 25.0

$element=$session->welement("xpath", "//input[@value='my val']");
$element->click();
$element=$session->welement("xpath", "//input[@value='ma val2']");
$element->location_in_view(); // < -- this is the candy
$element->click();

Nota: Eu uso uma versão personalizada do element34 PHP-webdriver. Mas não há nenhuma mudança no núcleo. Eu apenas uso meu "bem-estar" em vez de "elemento". Mas isso não influencia o caso em questão. O autor do driver diz "permitir que quase todas as chamadas de API sejam uma transformação direta do que é definido no próprio protocolo WebDriver". Portanto, você não deve ter problemas com outras linguagens de programação.

Apenas clicar não funcionará na minha configuração. Ele fará uma rolagem em vez de clicar, então tive que clicar duas vezes sem chamar "location_in_view ()".

Nota: Este método funciona para elementos que podem ser visualizados, como uma entrada do botão de tipo.

Dê uma olhada em: http://code.google.com/p/selenium/wiki/JsonWireProtocol#/session/:sessionId/element/:id/location

A descrição para JsonWireProtocol # sugere o uso de location + moveto, porque location_in_view é um método interno.


0

Algo que funcionou para mim foi usar o método Browser.MoveMouseToElement em um elemento na parte inferior da janela do navegador. Milagrosamente, ele funcionou no Internet Explorer, Firefox e Chrome.

Eu escolhi isso sobre a técnica de injeção de JavaScript apenas porque parecia menos invasiva.


Qual linguagem de programação é essa?
akostadinov

0

Venho testando com componentes do ADF e você precisa ter um comando separado para rolar se o carregamento lento for usado. Se o objeto não estiver carregado e você tentar encontrá-lo usando o Selenium, o Selenium lançará uma exceção de elemento não encontrado.


0

Se nada funcionar, tente isso antes de clicar em:

public void mouseHoverJScript(WebElement HoverElement) {

    String mouseOverScript = "if(document.createEvent){var evObj = document.createEvent('MouseEvents');evObj.initEvent('mouseover', true, false); arguments[0].dispatchEvent(evObj);} else if(document.createEventObject) { arguments[0].fireEvent('onmouseover');}";
    ((JavascriptExecutor) driver).executeScript(mouseOverScript, HoverElement);
}

0

Em Java, podemos rolar usando JavaScript, como no código a seguir:

driver.getEval("var elm = window.document.getElementById('scrollDiv'); if (elm.scrollHeight > elm.clientHeight){elm.scrollTop = elm.scrollHeight;}");

Você pode atribuir um valor desejado à variável "elm.scrollTop".


0

Uma solução é:

public void javascriptclick(String element)
{
    WebElement webElement = driver.findElement(By.xpath(element));
    JavascriptExecutor js = (JavascriptExecutor) driver;

    js.executeScript("arguments[0].click();", webElement);
    System.out.println("javascriptclick" + " " + element);
}

0

Este código está funcionando para mim:

JavascriptExecutor js = (JavascriptExecutor) driver;
js.executeScript("javascript:window.scrollBy(250, 350)");

Funciona para mim. A implementação do Dart WebDriver ainda não possui ações.
Günter Zöchbauer
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.