Selenium scroll element in (center) view

When an element is out of sight with selenium and tries to interact with it, selenium will usually scroll the element in the form at first implicitly. This is great, except that it is annoying that it usually places an element, quite simply in sight. I mean, if the item is under the window, it will scroll enough until the item simply borders the edge of the window.

This is usually normal, but when working on a website with borders around it, this will lead to many of these errors.

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

Because usually the border of the web page is above it, but will try to click the element anyway. Is there any way to handle this? Is it possible to automatically move elements to the center of the screen when they are not visible? I think along the lines of decapitation through a ruby.

+8
ruby selenium-webdriver watir-webdriver
source share
5 answers

This should work to scroll to the center of view:

 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); 
+7
source share

Yes, you can automatically scroll the browser so that any element with which we interact falls into the center. I have a working example below written and tested in ruby ​​using selenium-webdriver-2.41.0 and Firefox 28.

Full disclosure. You may need to edit parts of your code a bit for this to work properly. Explanations follow.

 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 

Recommended Use:

Enable automatic centering at the beginning of any code segments where the items are usually off-screen, and then turn it off.

NOTE. This code does not seem to work with chain actions. Example:

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

The scroll fix doesn't seem to update the click position. In the above example, he will click on the element’s preliminary scroll element, generating an incorrect click.

Why move_to ?

I chose move_to because most mouse-based actions use it, and at this point the behavior of the “scroll in view” of Selenium occurs. This particular patch should not work for any mouse interactions that won't call move_to at some level, and I don't expect it to work with any keyboard interactions, but a similar approach should work theoretically if you complete the correct one functions.

Why sleep ?

I'm actually not sure why the sleep command is needed after scrolling through executeScript . With my specific installation, I can remove the sleep command, and it still works. Similar examples from other developers through net net sleep commands with delays from 0.1 to 3 seconds. As a wild guess, I would say that this is done for reasons of cross-compatibility.

What if I don’t want monkey patch?

The ideal solution would be, as you suggested, to change the behavior of selenium “scroll to point of view”, but I believe that this behavior is controlled by code outside the selenium-webdriver gem. I traced the code to Bridge before the trail went cold.

To reject a monkey monkey, the scroll_to_center method works just fine as a standalone method with multiple permutations, where driver is your instance of Selenium::WebDriver::Driver :

  • driver.manage.window.position instead of @bridge.getWindowPosition
  • driver.manage.window.size instead of @bridge.getWindowSize
  • driver.execute_script instead of @bridge.executeScript
+3
source share

You can use the explicit scroll action with javascript here. In this case, you will find the element (this part already works if I understand your question correctly), then scroll to the specified position and then interact with the element.

In java, which will be:

 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
source share

The following code will scroll until the item appears,

 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
source share

You can have target scrolling using the ClientRect.top property of the element. You can see the second example on this post http://www.toolsqa.com/selenium-webdriver/scroll-element-view-selenium-javascript/

0
source share

All Articles