当一个元素与selenium不在视图中并且试图与它进行交互时,selenium通常会隐式地将元素滚动到视图中。这很好,除了令人讨厌的是它通常将元素放入视图中。我的意思是,如果元素位于窗口下方,它将向下滚动,直到元素刚好接近窗口边缘。
通常这很好,但是当在一个有边框的网站上工作时,这将导致许多这类错误
Selenium::WebDriver::Error::UnknownError:
unknown error: Element is not clickable at point (438, 747). Other element would receive the click: <body>...</body>
因为通常网页的边框位于其上方,但无论如何都会尝试单击该元素。无论如何处理这个?也许在视线外时自动将元素移动到屏幕中心?我正在考虑通过红宝石进行猴子修补。
答案 0 :(得分:20)
这应该可以将元素滚动到视图中心:
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);
答案 1 :(得分:3)
是的,可以自动滚动浏览器,使我们交互的任何元素都在窗口中居中。我在下面有一个工作示例,使用selenium-webdriver-2.41.0和Firefox 28在ruby中编写和测试。
完全披露:您可能需要编辑部分代码稍微才能使其正常运行。解释如下。
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现有的&#34;滚动到视图&#34;在此步骤中发生行为。这个特定的补丁不适用于任何不在某个级别调用move_to
的鼠标交互,我也不希望它适用于任何键盘交互,但理论上类似的方法应该有效,如果你包装正确的功能。
为什么sleep
?
我真的不确定为什么在通过sleep
滚动后需要executeScript
命令。通过我的特定设置,我可以删除sleep
命令,它仍然有效。 Similar examples来自other developers的{{3}}网络包含sleep
命令,延迟时间范围为0.1到3秒。作为一个疯狂的猜测,我会说这是出于交叉兼容的原因。
如果我不想修补猴子怎么办?
如你所说,理想的解决方案是改变Selenium&#34;滚动到视图&#34;行为,但我相信这种行为是由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
答案 2 :(得分: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) + ");");
答案 3 :(得分:-1)
以下代码将滚动,直到元素在视图中,
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