2013-11-23 3241 views
8

当一个元素与硒不在一起时,一个人试图与它交互时,硒通常会首先隐式地将元素滚动到视图中。这很好,除了令人讨厌的是它通常将元素放入视图中。我的意思是,如果元素在窗口下面,它将向下滚动,直到元素刚好接近窗口的边缘。selenium滚动元素到(视图的中心)视图

通常这是好的,但在网站上工作时,与它周围的边框,这将导致大量此类错误

Selenium::WebDriver::Error::UnknownError: 
     unknown error: Element is not clickable at point (438, 747). Other element would receive the click: <body>...</body> 

因为平时网页的边框是超过它的,但无论如何都会尝试点击该元素。无论如何处理这个?也许会自动移动元素到屏幕的中心,当看不见?我正在考虑通过ruby来修补猴子。

回答

7

这应该为了工作,以滚动的元素插入的视图中心:

WebElement element = driver.findElement(By.xxx("xxxx")); 

String scrollElementIntoMiddle = "var viewPortHeight = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);" 
              + "var elementTop = arguments[0].getBoundingClientRect().top;" 
              + "window.scrollBy(0, elementTop-(viewPortHeight/2));"; 

((JavascriptExecutor) driver).executeScript(scrollElementIntoMiddle, element); 
+0

谢谢。这个比scrollIntoView好 – bugCracker

0

您可以在这里通过javascript使用显式滚动操作。在这种情况下,您会发现元素(如果我正确理解您的问题,则此部分已经工作),然后将窗口滚动到指定的位置,然后与元素进行交互。

在java中,这将是:

WebElement element = driver.findElement(By.id("tabs")).findElement(By.className("youarehere")); 
Point p = element.getLocation(); 
((JavascriptExecutor) driver).executeScript("window.scroll(" + p.getX() + "," + (p.getY() + 200) + ");"); 
0

下面的代码将滚动,直到元素在视图,

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 
+0

这是一个很好的建议,但后来我不得不为我排在接触的每一个元素做到这一点。我正在寻找一种适用于整个会话的方法 – mango

3

是的,它可以自动滚动浏览器,使我们与之交互的任何元素都在窗口中居中。我有以下工作示例,书面和使用硒的webdriver-2.41.0和Firefox 28

完全披露在红宝石测试:您可能需要编辑代码略有的部分得到这个正常工作。接下来的解释。

Selenium::WebDriver::Mouse.class_eval do 
    # Since automatic centering of elements can be time-expensive, we disable 
    # this behavior by default and allow it to be enabled as-needed. 
    self.class_variable_set(:@@keep_elements_centered, false) 

    def self.keep_elements_centered=(enable) 
    self.class_variable_set(:@@keep_elements_centered, enable) 
    end 

    def self.keep_elements_centered 
    self.class_variable_get(:@@keep_elements_centered) 
    end 

    # Uses javascript to attempt to scroll the desired element as close to the 
    # center of the window as possible. Does nothing if the element is already 
    # more-or-less centered. 
    def scroll_to_center(element) 
    element_scrolled_center_x = element.location_once_scrolled_into_view.x + element.size.width/2 
    element_scrolled_center_y = element.location_once_scrolled_into_view.y + element.size.height/2 

    window_pos = @bridge.getWindowPosition 
    window_size = @bridge.getWindowSize 
    window_center_x = window_pos[:x] + window_size[:width]/2 
    window_center_y = window_pos[:y] + window_size[:height]/2 

    scroll_x = element_scrolled_center_x - window_center_x 
    scroll_y = element_scrolled_center_y - window_center_y 

    return if scroll_x.abs < window_size[:width]/4 && scroll_y.abs < window_size[:height]/4 

    @bridge.executeScript("window.scrollBy(#{scroll_x}, #{scroll_y})", ""); 
    sleep(0.5) 
    end 

    # Create a new reference to the existing function so we can re-use it. 
    alias_method :base_move_to, :move_to 

    # After Selenium does its own mouse motion and scrolling, do ours. 
    def move_to(element, right_by = nil, down_by = nil) 
    base_move_to(element, right_by, down_by) 
    scroll_to_center(element) if self.class.keep_elements_centered 
    end 
end 

推荐用法:

在任何的代码段上,其中元件是通常离屏的开始启用自动定心,则之后将其禁用。

注意:此代码似乎不适用于链式操作。例如:

driver.action.move_to(element).click.perform 

滚动修复似乎不更新click位置。在上面的例子中,它会点击元素的预滚动位置,产生错误点击。

为什么move_to

我选择了move_to,因为大多数基于鼠标的操作都使用它,并且在此步骤中会出现Selenium现有的“滚动到视图”行为。这个特定的补丁不适用于任何在某个级别上不会调用move_to的鼠标交互,也不期望它可以与任何键盘交互一起工作,但理论上,如果您包装正确的函数,类似的方法也应该起作用。

为什么sleep

我不确定为什么在通过executeScript滚动后需要sleep命令。通过我的特殊设置,我可以删除sleep命令,它仍然有效。 Similar examplesother developers'网络包括sleep命令延迟范围从0.1到3秒。作为一个疯狂的猜测,我会说这是为了交叉兼容性的原因。

如果我不想猴子补丁怎么办?

正如你所建议的那样,理想的解决方案是改变Selenium的“滚动到视图”行为,但我相信这种行为是由selenium-webdriver gem以外的代码控制的。在路径变冷之前,我一直追溯到Bridge

对于猴子补丁厌恶的scroll_to_center法正常工作,与一些换人的独立方法,其中driver是您Selenium::WebDriver::Driver例如:

  • driver.manage.window.position而不是 @bridge.getWindowPosition
  • driver.manage.window.size,而不是 @bridge.getWindowSize
  • driver.execute_script而不是 @bridge.executeScript