2

How can I get the geb webdriver to move to an element on the page that may not be in the view of the browser. The element exists on the page and is displayed but there may be a possibility that the element will appear on the bottom of the page and the browser would need to scroll down in order to bring the element into view.

import geb.Page
class myPage extends Page {
  static url = "mypage.xhtml"
  static at = {title == "myPage"}
  static content = {
    someElement = {$("#bottomOfPage")}
    anotherElement = {$(".someClass",5)}
  }

  void clickElement(){
    //possibility to fail because element may not be displayed in browsers view
    //if not in view, scroll to element, then click
    someElement.click()
  }
}

Using this page as an example, If an element is not in view on the page and possibly at the very bottom, how can I tell the webdriver to bring the element into view? I have some complicated tests that are failing when the page contents are not in view. In some cases, the driver will move to the element even if it's not in view. But I would like to explicitly tell the driver to move to an element if its not in view for the cases that it does not move on its own.

The selenium library does have a moveToElement() function but it only accepts objects of the WebElement class. Using geb, when creating page classes, all elements that are used in my tests are declared in the content section and thus are of the SimplePageContent class. SimplePageContent cannot be casted to a WebElement either. moveToElement(By.id("bottomOfPage")) does work but is not ideal because I do not want hard coded values. Id much rather pass the page content object itself if possible.

WontonJon
  • 413
  • 5
  • 14
  • I think you have to add a method moveToElement in your page object classes. The method will use JavaScriptExecutor to execute JS to scroll down to the position of object. See HOW TO scroll up/down at [this post](http://stackoverflow.com/questions/12293158/page-scroll-up-or-down-in-selenium-webdriver-selenium-2-using-java) – Buaban Apr 09 '16 at 03:18

2 Answers2

3

From my experience I can say that if you ask WebDriver to click on an element that is not currently in view it will first scroll to that element and then click on it. So you're either hitting some kind of bug if it does not happen or the fact that the element is not in view is not what's causing your element not to be clicked.

If you still want to move to the element explicitly using Actions.moveToElement() then you can easily turn objects returned from your content definition using the fact that they implement Navigator which comes with a firstElement() which you should use if you want to get the first WebElement of a multi element Navigator or singleElement() when your Navigator has exactly one WebElement.

There is also a simpler way, which won't require extracting WebElements from your Navigators - use an interact {} block:

interact {
    moveToElement(someElement)
}
erdi
  • 6,944
  • 18
  • 28
  • hmm I just made a quick test to try clicking an element that was out of view and you're correct. It will scroll to the element and click. I should have made an example in my question about inputting a value into a text field as well. I looked back at my code and when the a textbox is not in view, it will not enter a value and thus fail the test. I had looked into using interact{} but I always get "cannot resolve symbol 'moveToElement'". Is there something that needs to be imported? – WontonJon Apr 11 '16 at 13:14
  • Again, the fact that the textbox is not in view should not prevent the text to be input into it. Is there anything special about the textbox? Are you sure that the value is not put into the textbox? Wrt your question about interact - what is the full stacktrace you're getting? How are you using it? In a test, page or module? – erdi Apr 11 '16 at 15:22
  • I get no stack trace errors. the elements are just input fields that are text boxes. My test fills out a form. The textboxes that are visible in the browser window do receive values but its the textboxes that are not in the browser view that are not getting filled. Even when using breakpoints it shows that they do fill. it's as if theyre getting skipped over. I ended up creating a helper function using the Actions.moveToElement() method to explicitly move to the stubborn textboxes, and that did work. It's really strange lol. For now this is a reasonable solution. – WontonJon Apr 11 '16 at 16:31
0

According to documentation, moveToElement: Moves the mouse to the middle of the element. The element is scrolled into view and its location is calculated using getClientRects.

However from my experience, this may throw a org.openqa.selenium.interactions.MoveTargetOutOfBoundsException when the element is not within the viewport to begin with.

The only solution I could find is to scroll to the element manually with JavaScript. Here are some variants that all achieve the same thing:

// variant 1
int nextButtonY = buttonNavigator.singleElement().location.y
js."window.scrollTo({ left: 0, top: $nextButtonY behavior: 'instant' })"

// variant 2
((JavascriptExecutor) driver).executeScript('arguments[0].scrollIntoView({ behavior: "instant" });', buttonNavigator.singleElement())

// variant 3
js.exec(buttonNavigator.singleElement(), 'arguments[0].scrollIntoView({ behavior: "instant" });')
EzPizza
  • 979
  • 1
  • 13
  • 22