Search code examples
seleniumgeb

How to scroll into view when dealing with an "internal" scroll bar


I apologize if this question is somewhat ambiguous. I have noticed that with Geb elements won't be scrolled into view if said element is off the page and needs to be scrolled to using an "internal" scroll bar

by "internal" scroll bar I am referring to scroll bars that are nested within a given webpage, detached from the global webpage's scroll bar.

When I attempt to grab an element that is off the page due to this internal scroll bar, geb returns a null object (geb couldn't find the element on the page)

I have done a few different hacks that manually scroll these internal scroll bars, but I was wondering if Geb provided any funcionalty to handling these nested scrollbars.

Here is a code snippet to show how I handle finding a given row:

class TabledModule extends Module {
    static content = {
        headers {$(By.xpath("//lane-group-header"))}
        table {$(By.xpath("//div[@class=',y-class']"))}
    }

    Navigator getAllRows(){
        return table.children()
    }

    Navigator getRow(String text){
        return table.children().find{it.text().contains(text)}
    }

    Navigator getRow(int index){
        return table.children()[index]
    }
}

from my script:

getAllRows() //returns 50 which it should (only 20 are displayed)
def row = getRow(45) //returns a navigator as it should
row.click() //successfully clicks the correct row
def row2 = getRow("someString") //returns null when the row is off the page this is the problem and I'm wondering now if it is a bug, since getting the row by index seems to work fine.

For this module only about 20 of the 50 rows are shown to show the other rows you have to scroll through a nested scroll bar to get to them. the row I want to access is found lower on the list so it requires scrolling to access it.

what's interesting is that getAllRows().size() returns the correct number of rows: 50, but when I call getRow for a row that's off the page, it returns null. If the same row is found at the top of the list then it works. it only returns null if it needs to be scrolled to.


Solution

  • So I found out what my issue was. If I grab an element off screen with index instead of string. Geb is able to grab the navigator and is able to click on said navigator, but if the element is off the screen, then GEB is unable to get text on the element. to fix this I implemented this method.

    Navigator getRow(String text){
        JavascriptExecutor jse = (JavascriptExecutor)browser.driver
        for(int x = 0; x<getAllRows().size();x++){
            def row = getRow(x)
            WebElement element = row.firstElement()
            jse.executeScript("arguments[0].scrollIntoView(true);", element);
            if(row.text().contains(text)){
                return row
            }
        }
        return null
    }