I have a Web application with a scroll-able menu on the left hand side. My code is pretty simple:
WebElement elementToScrollTo = driver.findElement(By.xpath(locator));
((JavascriptExecutor) driver).executeScript("arguments[0].scrollIntoView();", elementToScrollTo);
locator is the link to the web element/menu item I want to click. The problem is in Chrome, the first line throws a NoSuchElementException. So obviously I cannot scroll to something that cannot be found in the first place.
However, what's weird is that in IE everything works perfectly. The element can be found and the menu scrolls. After which I use the element (i.e. click on it).
I cannot scroll the entire browser window as I only need the menu panel on the left hand side to scroll.
I have the latest Chrome (60.0.3112.78 (Official Build) (64-bit)) and chromedriver 2.30.
Note: I've actually figured out the problem. The reason it cannot find it is because it doesn't scroll to the parent of the menu item, the level 2 element. so the second line (scrolling) doesn't do anything in Chrome and because of that the driver will not find the menu item on level 3 (the child of level 2). So maybe scrolling doesn't work in Chrome?
It might be problem with the HTML elements located within a frame. To deal with such elements you need switch the frames first.
Can you try this command:
driver.switchTo().frame()
Also, try to use implicitWait if the above one doesn't work. Maybe, your element is taking time to load and therefore web driver fails to locate it.
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
Related
I have an application created in ReactJS which also contains some EXTJS/jsp iframes inside it. Now when I try to click some anchor tag element (Hyperlink) using selenium click method it wasn't working. After some investigations, I found that the click is performed slightly above the element boundary. The selenium is able to identify the element using xpath but is unable to click the link correctly. Also tried using the action but it didn't work. Using offset is not an option as it relies too much on the screens resolution.
Any help is highly appreciated.
maybe you can set the width and height of the page to become larger. Some elements overlaps if the page does not support smaller screens.
If your locator is inside the IFrame, you will need to do a switch to that IFrame and then perform the click action, and after you need to switch out from that IFrame:
driver.switchTo().frame("your_iframe_name");
driver.findElement(By.xpath("your_locator")).click();
After use one of these to switch back:
driver.switchTo().parentFrame();
driver.switchTo().defaultContent();
Also, there is another way to click on a element located inside an IFrame, by executing a js script.
JavascriptExecutor executor = (JavascriptExecutor)driver;
executor.executeScript("arguments[0].click();", driver.findElement(By.xpath("your_locator"));
I am using Selenium to run tests on a page with multiple drop-down menus (specifically a pop-up page which allows you to select some options then close it). I am able to click on some of these menus totally fine; however, some of them throw an ElementNotInteractable exception with the message "element could not be scrolled into view", even though the menus are right beside each other. I am very confused as to why one menu works and the other does not even though they appear to be the same. The three things I have tried in order to click on the menu are:
a) Regular Selenium clicking :
driver.findElement(By.xpath("//select[#foo='bar']").click();
This is what works with the other menus, except I navigate directly to the "option" tag and click on it (don't need to click the drop down first)
b)Javascript executor
JavascriptExecutor executor = (JavascriptExecutor)driver;
executor.executeScript("arguments[0].click();", element);
When I use this, no exceptions are thrown; however, the menu remains empty, which leads me to believe it is not being clicked on.
c)Actions
Actions builder = new Actions(driver);
builder.moveToElement(menu).click(menu);
builder.perform();
For some reason when I use this, the whole pop-up window with the drop down menus on it closes. :/ (I have double checked that it is not the close button being clicked)
I'm not sure if this is relevant, but Selenium has no problem finding the elements, it is just when I try to click them that it complains.
To summarise, my questions are:
1) What could make the menus different such that one is clickable and one is not?
2) How can I click on the second menu and choose an option?
Edit: I tried the solution found in the similar problem; unfortunately it does not work. The solution was to add an explicit wait since the element may not have completely loaded, this only leads to a timeout.
Using JavascriptExecutor is a workaround to interact with non interactable elements. I think it should never be used in selenium tests because it makes the test do things a real user wouldn't be able to do in a real life scenario.
The most plausible cause is that you are interacting with the wrong element, try to debug to identify the element returned by the used selector.
You can use chrome dev tools in debug mode :
1- Put a breakpoint at the exception line,
2- Use $x("//select[#foo='bar']") in the chrome console to get the element.
To select a value, you can use the org.openqa.selenium.support.ui.Select object :
new Select(element).selectByValue(value);
Using Selenium w/ Java bindings and ChromeDriver 2.3 with the latest browser installed
I'm currently stumped after more than enough time trying to find a solution. I'm currently trying to drag and drop an element to another element. The only catch is the element target I need to move to is only visible once I move the source element. Any advice?
So here a screenshot of the source element that I click and hold, and then dragging it exposes the two options that I can drop too:
Element that is the source
So as I hold down the mouse and drag just a small portion, the drop targets become visible, per the screenshot below:
Targets visible once mouse is dragged with source
Here is the latest code snippet I've tried that I believe should make this happen, but yet nothing happens and continues into the Thread.sleep(), which was only put in for observation purposes. These are assuming healthy instances of WebDriverWait and WebDriver:
driverWait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//div[#class='user-info ng-binding'][text()='Sample Text']")));
driverWait.until(ExpectedConditions.elementToBeClickable(By.xpath("//div[#class='user-info ng-binding'][text()='Sample Text']")));
source = driver.findElement(By.xpath("//div[#class='user-info ng-binding'][text()='Sample Text']"));
//move to element, click and hold, and then move it to expose the available options
actions.moveToElement(source).clickAndHold().pause(Duration.ofSeconds(1)).moveByOffset(10, 10).pause(Duration.ofSeconds(1)).build().perform();
Thread.sleep(10000);
So the idea behind this is to just click and hold the source, move it a little to display the targets, and then find the targets, and use the actions.release() to move the target onto the source, but when I debug it it does nothing on the element to the element and goes straight to the Thread.sleep(). I've read about plenty of bugs. Any advice would be greatly appreciated.
I know this is an old question but I was looking for a solution but in the end I just made the hidden area visible. I know this isn't ideal but seems to work.
JavascriptExecutor js = (JavascriptExecutor) driver;
js.executeScript("arguments[0].setAttribute('style', 'display:block')", targetElement);
I can't able to click 'Board' link for the 'dropdown-toggle' window using selenium webdriver.
I have tried
cssSelector="a.accordion-toggle" (or) linkText="Board".
But it is not working.
SO, kindly give me a solution for how can I locating 'Board' webelement.
Please refer the screenshot.
Thanks,
Vairamuthu.
I think the problem is visibility of that element. Maybe you're trying to click it when the dropdown 'Academic Year' is collapsed and link 'Board' is invisible in the browser.
I see two possible solutions:
Click 'Academic Year' (or scroll mouse on it if it works this way) before clicking 'Board'
Use click with JavaScript:
driver.executeScript("arguments[0].click();", element);
Where "driver" - RemoteWebDriver object, "element" - RemoteWebElement
Note that the second solution won't work if the element for 'Board' link is absent in the page source when dropdown is collapsed.
I'm trying to click on an element on a page; the element is clearly visible on screen. There is a toaster that might pop up, so I'm trying to write a defense: if the toaster is on screen, close the toaster first, then continue clicking through to the next page. I am using PageFactory, so I have an element to contain the toaster and one for the close button for the toaster. My "deal with toaster" method is as follows:
if (driver.findElements(By.cssSelector("#toaster")).size() > 0
&& toaster.isDisplayed()) {
toasterClose.click();
}
When I do this in chrome, however, I'm getting org.openqa.selenium.WebDriverException: unknown error: Element is not clickable at point (994, 758)
Pausing the test execution, I cannot see the toaster on the screen. I figure the devs must be hiding it by making it render in a far away, unscrollable location. So as a stopgap measure, I added a condition that if the x coordinate was greater than 800, don't click. With that in place, I get:
org.openqa.selenium.WebDriverException: unknown error: Element is not clickable at point (547, 725). Other element would receive the click: <div id="toaster">...</div>
What's going on? How can the toaster not be clickable but would somehow receive the click anyway? Firefox can handle the test just fine, with or without the 800 pixel workaround; it's only Chrome having this issue.
For Clarification: The goal of the test is NOT to click the toaster. The goal is to click another element on the page. The test reported that a toaster was in the way, so I attempted to write a step to close the toaster if it is displayed. I have not seen this toaster, so I'm not exactly sure what it is, but chrome keeps reporting that it's in the way. All our toasters site-wide use a basic template that includes a close button so the user can close the toaster, which is what I'm trying to click. Firefox never has this issue and does not report the existence of any toasters.
I'm calling it a toaster because that's what our site calls it, because that's what it's called in whatever framework we got it from (jQuery UI? Backbone?). If I pause execution, I cannot see any toasters at this point in the test, but jQuery tells me it exists and is visible. However, the element found with jQuery has just the default pieces of our toaster setup: a div, an empty div where the message should be, and the close button. Clearly it's not meant to be rendered at this time, but Chrome thinks it's in the way.
I'm assuming by "toaster" you mean some sort of javascript modal popup with a close button.
Identifying the correct problem
You're testing the existence and visibility of the #toaster element, but not the toasterClose element that you're clicking. There's no guarantee that just because one element exists and is displayed, another is as well. From the error, it appears that the #toaster element overlaps the toasterClose element, making it unclickable.
Troubleshooting clickability
Once you've properly selected toasterClose, manually use devtools and inspect to see why it's unclickable. Is it visible and unobstructed? Is the toasterClose element something of zero height/width? Is there dynamic JavaScript modifying the page post-load? Is it actually positioned in view of the page? (I've had elements render visibly at the edge of the window only to be obstructed by the browser's scroll bars.1)
Alternative
You should also see if you really need to use this toasterClose element. How does would a human close this popup? Would they press Escape? Would they click outside the popup window, on the overlay element? Do they do something else that triggers some sort of closeModal() javascript function? You can also do any of these things using Selenium.
Last Resort
One thing you can always do to remove such a popup is to run your own javascript to modify the DOM and remove the offending element(s) altogether:
driver.execute_script(<<-javascript)
var toaster = document.getElementById("toaster");
toaster.parentNode.removeChild(toaster);
var overlay = document.getElementById("modal_overlay");
overlay.parentNode.removeChild(overlay);
javascript
Future/Additional
If this is a regular issue for you, I would suggest wrapping this code in try/catches and a retry mechanism to make it resilient to javascript dynamically loaded elements.
1 Update
Just to elaborate on the scrollbar issue I had, because it turned out that it was a very similar problem to yours.
Here, the "I'm Feeling Lucky" button is out of view. If Selenium tries to click on it, first it will attempt to scroll it into view.
Here's an example of what Selenium would attempt to do. Notice how the button is now "in view".
However, Chrome on OSX is styled in such a way that the scrollbars are normally hidden. The moment that Selenium issues the scroll command, the scrollbars appear and the following click command fails to reach the button.
The solution was to use javascript to scroll the window manually:
page.execute_script(<<-javascript)
document.getElementById("gbqfsb").scrollIntoView(true);
// or if that doesn't work:
window.scrollTo(0, document.getElementById("gbqfsb").getBoundingClientRect().top);
javascript
Try the following code. Should work:
if (driver.findElements(By.cssSelector("#toaster")).size() > 0
&& toaster.isDisplayed()) {
Actions builder = new Actions(driver);
builder.moveToElement(toasterClose).moveByOffset(2,2).click().build().perform();
}
Can you close toaster using escape key from keyboard manually.
If you can than use following:
Actions action = new Actions(driver);
action.sendKeys(Keys.ESCAPE).build().perform();
It seems the toaster was partially rendered and fixed to the DOM just below the bottom edge of the screen, using position:fixed to stop it from showing up until it's ready to be populated with data and animated onto the screen. When chrome tried to click on links that were below the bottom edge of the screen, it predicted that it'd hit the toaster and didn't actually bother scrolling.
After some googling, I added the following utility function:
public static void ScrollElementIntoView(WebDriver driver, WebElement element) {
((JavascriptExecutor) driver).executeScript("arguments[0].scrollIntoView(true);", element);
}
Then I call this method before clicking any link on that page, and voila, no more toaster problems!