Is there any way in either Selenium 1.x or 2.x to scroll the browser window so that a particular element identified by an XPath is in view of the browser? There is a focus method in Selenium, but it does not seem to physically scroll the view in FireFox. Does anyone have any suggestions on how to do this?
The reason I need this is I'm testing the click of an element on the page. Unfortunately the event doesn't seem to work unless the element is visible. I don't have control of the code that fires when the element is clicked, so I can't debug or make modifications to it, so, easiest solution is to scroll the item into view.
38 Answers 38
Have tried many things with respect to scroll, but the below code has provided better results.
This will scroll until the element is in view:
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
12 Comments
position: fixed
on your page and it is obscuring the element Selenium wants to click. Quite often these fixed elements go at the bottom, so setting scrollIntoView(true)
moves it nicely to the top of the viewport.true
to scrollIntoView
if the object you're scrolling to is beneath where you currently are, false
if the object you're scrolling to is above where you currently are. I had a hard time figuring that out.You can use the org.openqa.selenium.interactions.Actions
class to move to an element.
Java:
WebElement element = driver.findElement(By.id("my-id"));
Actions actions = new Actions(driver);
actions.moveToElement(element);
actions.perform();
Python:
from selenium.webdriver.common.action_chains import ActionChains
ActionChains(driver).move_to_element(driver.sl.find_element_by_id('my-id')).perform()
14 Comments
JavascriptExecutor js = (JavascriptExecutor) driver;
js.executeScript("javascript:window.scrollBy(250,350)");
You may want to try this.
6 Comments
js.ExecuteScript("arguments[0].scrollIntoView(true);" + "window.scrollBy(0,-100);", e);
for IE and Firefox and js.ExecuteScript("arguments[0].scrollIntoViewIfNeeded(true);", e);
for Chrome. Simple.((JavascriptExecutor) driver).executeScript("javascript:window.scrollBy(0,250)");
This worked in Chrome. And the only solution that actually worked for me. Same situation as the first commenter, I had a fixed element at the bottom that kept obscuring the element I needed to click.If you want to scroll on the Firefox window using the Selenium webdriver, one of the ways is to use JavaScript in the Java code. The JavaScript code to scroll down (to bottom of the web page) is as follows:
JavascriptExecutor js = (JavascriptExecutor) driver;
js.executeScript("window.scrollTo(0, Math.max(document.documentElement.scrollHeight, document.body.scrollHeight, document.documentElement.clientHeight));");
Comments
Targeting any element and sending down keys (or up/left/right) seems to work also. I know this is a bit of a hack, but I'm not really into the idea of using JavaScript to solve the scrolling problem either.
For example:
WebElement.sendKeys(Keys.DOWN);
3 Comments
var elem = driver.FindElement(By.Id("element_id")); elem.SendKeys(Keys.PageDown);
In Selenium we need to take the help of a JavaScript executor to scroll to an element or scroll the page:
je.executeScript("arguments[0].scrollIntoView(true);", element);
In the above statement element
is the exact element where we need to scroll. I tried the above code, and it worked for me.
I have a complete post and video on this:
http://learn-automation.com/how-to-scroll-into-view-in-selenium-webdriver/
2 Comments
scrollIntoView
is asynchronous. It simply pushes a scroll update to a queue and exits before the scrolling completes. I used something similar in a script of mine and noticed that every once in a while, calls to click() that occurred immediately afterward would fail because the elements were still moving around on the page after the executeScript()
returned.webElement = driver.findElement(By.xpath("bla-bla-bla"));
((JavascriptExecutor)driver).executeScript("arguments[0].scrollIntoView();", webElement);
For more examples, go here. All in Russian, but Java code is cross-cultural :)
3 Comments
I found that the bounding rect of my element was not correct, leading to the browser scrolling well off the screen. However, the following code works rather well for me:
private void scrollToElement(WebElement webElement) throws Exception {
((JavascriptExecutor)webDriver).executeScript("arguments[0].scrollIntoViewIfNeeded()", webElement);
Thread.sleep(500);
}
2 Comments
This worked for me:
IWebElement element = driver.FindElements(getApplicationObject(currentObjectName, currentObjectType, currentObjectUniqueId))[0];
((IJavaScriptExecutor)driver).ExecuteScript("arguments[0].scrollIntoView(true);", element);
Comments
You can use this code snippet to scroll:
C#
var element = Driver.FindElement(By.Id("element-id"));
Actions actions = new Actions(Driver);
actions.MoveToElement(element).Perform();
There you have it
Comments
I am not sure if the question is still relevant but after referring to scrollIntoView documentation from https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView.
The easiest solution would be
executor.executeScript("arguments[0].scrollIntoView({block: \"center\",inline: \"center\",behavior: \"smooth\"});",element);
This scrolls the element into center of the page.
2 Comments
Use the driver to send keys like the pagedown or downarrow key to bring the element into view. I know it's too simple a solution and might not be applicable in all cases.
4 Comments
element
in the viewable page and sending PageDown element.SendKeys(Keys.PageDown);
worked for me.From my experience, Selenium Webdriver doesn't auto scroll to an element on click when there are more than one scrollable section on the page (which is quite common).
I am using Ruby, and for my AUT, I had to monkey patch the click method as follows;
class Element
#
# Alias the original click method to use later on
#
alias_method :base_click, :click
# Override the base click method to scroll into view if the element is not visible
# and then retry click
#
def click
begin
base_click
rescue Selenium::WebDriver::Error::ElementNotVisibleError
location_once_scrolled_into_view
base_click
end
end
The 'location_once_scrolled_into_view' method is an existing method on WebElement class.
I apreciate you may not be using Ruby but it should give you some ideas.
2 Comments
module Capybara :: module Node
, and I needed to call native.location_once_scrolled_into_view
instead of just location_once_scrolled_into_view
. I also rescued ::Selenium::WebDriver::Error::UnknownError
, which is what I'm getting often in Firefox 44.0.2. But I find this solution not to be flexible enough and ultimately put the <Element>.native.location_once_scrolled_into_view
calls in the acceptance test itself, followed immediately by page.execute_script('window.scrollByPages(-1)')
where needed.Element#scroll_into_view
which delegates to Selenium's location_once_scrolled_into_view
. But both do nothing different from Seleniums default behavior so overflow elements still can obstruct whatever we try to click.This is a repeated solution with JavaScript, but with an added waiting for element.
Otherwise ElementNotVisibleException
may appear if some action on the element is being done.
this.executeJavaScriptFunction("arguments[0].scrollIntoView(true);", elementToBeViewable);
WebDriverWait wait = new WebDriverWait(getDriver(), 5);
wait.until(ExpectedConditions.visibilityOf(elementToBeViewable));
1 Comment
The Ruby script for scrolling an element into view is as below.
$driver.execute_script("arguments[0].scrollIntoView(true);", element)
sleep(3)
element.click
Comments
Sometimes I also faced the problem of scrolling with Selenium. So I used javaScriptExecuter to achieve this.
For scrolling down:
WebDriver driver = new ChromeDriver();
JavascriptExecutor js = (JavascriptExecutor)driver;
js.executeScript("window.scrollBy(0, 250)", "");
Or, also
js.executeScript("scroll(0, 250);");
For scrolling up:
js.executeScript("window.scrollBy(0,-250)", "");
Or,
js.executeScript("scroll(0, -250);");
Comments
Selenium 2 tries to scroll to the element and then click on it. This is because Selenium 2 will not interact with an element unless it thinks that it is visible.
Scrolling to the element happens implicitly so you just need to find the item and then work with it.
12 Comments
WebElement.click()
requires the element to be visible in order to click on it. It will not scroll on your behalf.Something that worked for me was to use the Browser.MoveMouseToElement method on an element at the bottom of the browser window. Miraculously it worked in Internet Explorer, Firefox, and Chrome.
I chose this over the JavaScript injection technique just because it felt less hacky.
1 Comment
You may want to visit page Scroll Web elements and Web page- Selenium WebDriver using Javascript :
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
FirefoxDriver ff = new FirefoxDriver();
ff.get("http://toolsqa.com");
Thread.sleep(5000);
ff.executeScript("document.getElementById('text-8').scrollIntoView(true);");
}
1 Comment
If you think other answers were too hacky, this one is too, but there is no JavaScript injection involved.
When the button is off the screen, it breaks and scrolls to it, so retry it... ̄\_(ツ)_/ ̄
try
{
element.Click();
}
catch {
element.Click();
}
1 Comment
Javascript
The solustion is simple:
const element = await driver.findElement(...)
await driver.executeScript("arguments[0].scrollIntoView(true);", element)
await driver.sleep(500);
Comments
I have used this way for scrolling the element and click:
List<WebElement> image = state.getDriver().findElements(By.xpath("//*[contains(@src,'image/plus_btn.jpg')]"));
for (WebElement clickimg : image)
{
((JavascriptExecutor) state.getDriver()).executeScript("arguments[0].scrollIntoView(false);", clickimg);
clickimg.click();
}
3 Comments
scrollIntoView(false)
worked, but scrollIntoView(true)
didn't. Either can work, it depends on your scenario.def scrollToElement(element: WebElement) = {
val location = element.getLocation
driver.asInstanceOf[JavascriptExecutor].executeScript(s"window.scrollTo(${location.getX},${location.getY});")
}
Comments
In most of the situation for scrolling this code will work.
WebElement element = driver.findElement(By.xpath("xpath_Of_Element"));
js.executeScript("arguments[0].click();",element);
Comments
JAVA
Try scroll to element utilize x y
position, and use JavascriptExecutor
with this is argument: "window.scrollBy(x, y)"
.
Following import:
import org.openqa.selenium.WebElement;
import org.openqa.selenium.JavascriptExecutor;
First you need get x y
location the element.
//initialize element
WebElement element = driver.findElement(By.id("..."));
//get position
int x = element.getLocation().getX();
int y = element.getLocation().getY();
//scroll to x y
JavascriptExecutor js = (JavascriptExecutor) driver;
js.executeScript("window.scrollBy(" +x +", " +y +")");
Comments
While I hesitate to add yet another answer to a question that already has 30, there are some very subtle things that go on with browser scrolling and Selenium. The crux of the issue is that scrollIntoView
is asynchronous: it simply pushes a scroll update request onto a queue of some kind and then exits before the scrolling actually occurs. So it may be easy to scroll to a specific element, but it is difficult to ensure that scrolling has actually completed before moving on so that you can ensure future calls (like click()
) won't "miss" their elements and fail due to the elements still moving around on the page. This is true even when smooth scroll-behavior
is turned off.
Option 1:
Simply use the common solution mentioned by others, but make sure to add some arbitrary wait afterward:
((JavascriptExecutor) driver).executeScript("arguments[0].scrollIntoView(true);", element);
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
Adding a wait afterward will give the scrolling time to complete after executeScript
returns, but there is no good way to determine how long to wait. If scrolling is not something your script does very often, then set it to something way longer than what you think is needed a forget about it.
Option 2:
If you hate using arbitrary waits to gloss over problems (or if you need this operation to take as little time as possible), then use a more complicated script with executeAsyncScript
to ensure scrolling completes before the Selenium script moves on.
The script below uses the 'scrollend' event to detect when scrolling has stopped. However, this is not straight forward because (and this is where it gets complicated) we may need to wait for multiple 'scrollend' events because:
- each ancestor of the element may have a scrollbar, and
- each one of them may or may not need to be scrolled in order to scroll the element into view, and
- each ancestor that gets scrolled in order to bring the element into view will generate its own scrollend event (but only if it actually needed to be scrolled during the process)
So, the number of scrollend events we need to wait for is anywhere between 0 and X, where X is the number of ancestor elements with visible scrollbars.
The script below solves this issue by starting at "element" and walking up the hierarchy looking for any ancestor elements that have a scrollbar (vertical or horizontal). For each one, it scrolls that container by a single pixel, just to make sure each scrollable ancestor element has a pending scroll update. It also keeps a count of the number of scrollable ancestor elements it encountered, so that we know exactly how many scrollend events to expect.
Then element.scrollIntoView() is called, which may or may not add more pending scroll updates in order to scroll the element into view. However, these updates will simply be additional updates for the scrollable ancestor elements that our script already programmatically scrolled by one pixel. This means that the element.scrollIntoView()
call will not cause the expected number of scrollend events to increase.
After calling element.scrollIntoView()
, the script simply needs to wait for the expected number of scrollend events to occur, and then signal the end of the script.
const element = arguments[0];
// keep track of the function to call to signal the script is complete
const scriptDone = arguments[arguments.length - 1];
let scrollableElementCount = 0;
const nonScrollableStyles = ['visible', 'hidden'];
let currentElement = element;
while(currentElement.parentElement && currentElement != currentElement.parentElement) {
currentElement = currentElement.parentElement;
// check to see if currentElement is scrollable in either the X or Y direction
const style = getComputedStyle(currentElement);
if(currentElement.clientHeight > 0 && currentElement.clientHeight < currentElement.scrollHeight && ! nonScrollableStyles.includes(style.overflowY)) {
// current element is scrollable in the Y direction - scroll it by one pixel
currentElement.scrollTop = (currentElement.scrollTop == 0) ? 1 : currentElement.scrollTop - 1;
scrollableElementCount++;
} else if(currentElement.clientWidth > 0 && currentElement.clientWidth < currentElement.scrollWidth && ! nonScrollableStyles.includes(style.overflowX)) {
// current element is scrollable in the X direction - scroll it by one pixel
currentElement.scrollLeft = (currentElement.scrollLeft == 0) ? 1 : currentElement.scrollLeft - 1;
scrollableElementCount++;
}
}
if(scrollableElementCount > 0) {
// add a scrollEndHandler to ensure one "scrollend" event is received for each scrollable element that is an ancestor of the target element
const scrollEndHandler = function () {
scrollableElementCount--;
if(scrollableElementCount == 0) {
element.ownerDocument.removeEventListener('scrollend', scrollEndHandler, true);
// all of the "scrollend" events are now accounted for
scriptDone();
}
};
element.ownerDocument.addEventListener('scrollend', scrollEndHandler, true);
// finally call scrollIntoView and wait for the scrollEndHandler to account for all the expected "scrollend" events
element.scrollIntoView(true);
} else {
// no need to call scrollIntoView, since there are no scrollbars present anywhere on the page
scriptDone();
}
Take that JavaScript, get it into a Java String and call executeAsyncScript
String scrollScript = """
<multi-line Java String - insert JavaScript from above here!>
""";
((JavascriptExecutor) driver).executeAsyncScript(scrollScript, element);
Comments
I've been doing testing with ADF components and you have to have a separate command for scrolling if lazy loading is used. If the object is not loaded and you attempt to find it using Selenium, Selenium will throw an element-not-found exception.
Comments
A solution is:
public void javascriptclick(String element)
{
WebElement webElement = driver.findElement(By.xpath(element));
JavascriptExecutor js = (JavascriptExecutor) driver;
js.executeScript("arguments[0].click();", webElement);
System.out.println("javascriptclick" + " " + element);
}
Comments
This code is working for me:
JavascriptExecutor js = (JavascriptExecutor) driver;
js.executeScript("javascript:window.scrollBy(250, 350)");
1 Comment
Selenium can scroll to some element in the scrollbar automatically for some simple UI, but for lazy-load UI, scrollToElement is still needed.
This is my implementation in Java with JavascriptExecutor. You can find more details in Satix source code: http://www.binpress.com/app/satix-seleniumbased-automation-testing-in-xml/1958
public static void perform(WebDriver driver, String Element, String ElementBy, By by) throws Exception {
try {
//long start_time = System.currentTimeMillis();
StringBuilder js = new StringBuilder();
String browser = "firefox";
if (ElementBy.equals("id")) {
js.append("var b = document.getElementById(\"" +
Element + "\");");
} else if (ElementBy.equals("xpath")) {
if (!"IE".equals(browser)) {
js.append("var b = document.evaluate(\"" +
Element +
"\", document, null, XPathResult.ANY_TYPE, null).iterateNext();");
} else {
throw new Exception("Action error: xpath is not supported in scrollToElement Action in IE");
}
} else if (ElementBy.equals("cssSelector")) {
js.append("var b = document.querySelector(\"" +
Element + "\");");
} else {
throw new Exception("Scroll Action error");
}
String getScrollHeightScript = js.toString() + "var o = new Array(); o.push(b.scrollHeight); return o;";
js.append("b.scrollTop = b.scrollTop + b.clientHeight;");
js.append("var tmp = b.scrollTop + b.clientHeight;");
js.append("var o = new Array(); o.push(tmp); return o;");
int tries = 1;
String scrollTop = "0";
while (tries > 0) {
try {
String scrollHeight = ((JavascriptExecutor) driver).executeScript(getScrollHeightScript).toString();
if (scrollTop.equals(scrollHeight)) {
break;
} else if (driver.findElement(by).isDisplayed()) {
break;
}
Object o = ((JavascriptExecutor) driver).executeScript(js.toString());
scrollTop = o.toString();
Thread.sleep(interval);
tries++;
} catch (Exception e) {
throw new Exception("Action error:" +
" javascript execute error : " + e.getMessage() + ", javascript : " + js.toString());
}
}
} catch (Exception e) {
try {
ScreenshotCapturerUtil.saveScreenShot(driver, CLASSNAME);
} catch (IOException e1) {
throw new Exception("Save screenshot error!", e1);
}
throw e;
}
}
JavascriptExecutor js = (JavascriptExecutor) driver; js.executeScript("window.scrollBy(0,250)", "");
Actions action = new Actions(driver); action.moveToElement(element).perform();
WebElement element = driver.findElement(By.<locator>)); element.sendKeys(Keys.DOWN);