Problem
An exception will occur when the driver tries to click a location outside of the viewport. From my experience with Element#click, I’ve never run into the exception for elements outside the viewport. There is clearly some auto-scrolling that occurs before clicking.
When I added Element#obscured?, I believed that if the element was outside of the viewport, it would always be scrolled to the top. However, a Slack discussion suggested that this was not true (or at least has changed).
So what auto-scrolling happens today?
Answer
The scrolling depends on multiple factors:
- Browser being used
- Location of the element being clicked relative to the viewport
- Whether click modifiers (eg :control) are used
The below table summarizes where the element is positioned (within the viewport) after clicking it:
Browser | Click Modifiers | Element Below Viewport | Element In Viewport | Elememnt Above Viewport |
---|---|---|---|---|
Chrome/Edge v95 | Without modifiers | Bottom | Unchanged | Top |
Chrome/Edge v95 | With modifiers | Bottom | Unchanged | Bottom |
Firefox v94 | With modifiers | Bottom | Unchanged | Bottom |
Firefox v94 | With modifiers | Out Of Bounds Error (no scrolling) | Unchanged | Out Of Bounds Error (no scrolling) |
This was observed using the following script (Watir v7.0.0.beta2, Selenium-WebDriver v4.0.0.beta4):
def test_click(browser, link, relative_to, modifier) out_of_bounds = '' begin link.click(*modifier) rescue Selenium::WebDriver::Error::ElementClickInterceptedError # scrolled but covered by floating header/footer rescue Selenium::WebDriver::Error::MoveTargetOutOfBoundsError out_of_bounds = "(MoveTargetOutOfBoundsError)" end puts "after clicking element #{relative_to} viewport: #{out_of_bounds} #{browser.execute_script('return arguments[0].getBoundingClientRect().top;', link)}" end [:chrome, :edge, :firefox].each do |browser_type| browser = Watir::Browser.new browser_type # any tall page where the link isn't in the viewport when scrolled to top or bottom browser.goto 'https://jkotests.wordpress.com/2013/04/10/directions-analogy-for-locator-strategies/' link = browser.link(text: 'Automation') browser.execute_script('arguments[0].removeAttribute("href");', link) # prevent navigation puts "starting: #{browser.execute_script('return arguments[0].getBoundingClientRect().top;', link)}" [[], [:control]].each do |modifier| puts "using #{browser_type} - modifiers #{modifier}" browser.scroll.to(:top) test_click(browser, link, 'below', modifier) link.scroll.to(:center) test_click(browser, link, 'in centre of', modifier) browser.scroll.to(:bottom) test_click(browser, link, 'above', modifier) puts end browser.close puts end
Which had the output:
starting: 1617 using chrome - modifiers [] after clicking element below viewport: 693 after clicking element in centre of viewport: 374 after clicking element above viewport: 0 using chrome - modifiers [:control] after clicking element below viewport: 693 after clicking element in centre of viewport: 374 after clicking element above viewport: 693 starting: 1617 using edge - modifiers [] after clicking element below viewport: 662 after clicking element in centre of viewport: 358 after clicking element above viewport: 0 using edge - modifiers [:control] after clicking element below viewport: 662 after clicking element in centre of viewport: 358 after clicking element above viewport: 662 starting: 1657 using firefox - modifiers [] after clicking element below viewport: 708 after clicking element in centre of viewport: 381 after clicking element above viewport: 708 using firefox - modifiers [:control] after clicking element below viewport: (MoveTargetOutOfBoundsError) 1657 after clicking element in centre of viewport: 381 after clicking element above viewport: (MoveTargetOutOfBoundsError) -1889