I am trying to crawl data from agoda.com. I want to filter all the reviews by language, english. When I do a count based on the selector, I get 1, however, when I try to click or wait for the element to be visible, the program throws the element not visible exception after the timeout.
This is the code I am trying so far
String url = "https://www.agoda.com/en-sg/resorts-world-sentosa-hard-rock-hotel/hotel/singapore-sg.html";
driver.get(url);
try {
for (WebElement element: driver.findElements(By.xpath("//*[starts-with(#id, 'language-')]"))) {
if (element.getTagName().equalsIgnoreCase("input")) {
if (element.findElement(By.xpath("..")).getText().equalsIgnoreCase("english")) {
wait.until(ExpectedConditions.visibilityOf(element));
element.click();
break;
}
}
}
}catch(Exception e){
System.out.println(e.getMessage());
}
Where am I going wrong?
Please try to use following code:
// To find and click on required check-box
WebElement element = driver.findElement(By.xpath("//div[input[starts-with(#id, 'language-')]/span[text()='English']]"));
Actions actions = new Actions(driver);
actions.moveToElement(element);
actions.click();
actions.perform();
It's not possible to be sure from here what's wrong, especially without the actual copy-paste from the exception, but one cause for that is an element present but not currently visible. It might be suppressed or out of the viewport. If you open the page in a browser such as Chrome that supports a "developer" mode, you can view the element attributes to confirm or refute that.
Side notes:
• Post complete information about your problem with your question. What is the exact exception, its message, and a few lines of the stack trace?
• If possible, post the details of the web element from your "developer" view of it.
• Don't catch Exception, catch specific exceptions.
• Copy and paste code fragments rather than retyping them. If your actual code called printlkn then you have deeper problems.
Related
I have a problem using Ecplise. When I use a command to do something that drives me into another page. For example if I do commands that do not require to change the page it works fine. But when I do one that changes the page, it works, but after that it stops and I get that error. So, there is a portion of the code. After the third command which implies going to another page, the next 2 commands don't work.
driver.get("https://mathaus.ro");
driver.manage().window().maximize();
driver.findElement(By.id("Constructii10NavNode")).click();
driver.findElement(By.id("changeLocationReference")).click();
driver.findElement(By.className("close-modal")).click();
I think you need Explicit waits :
Code :
driver.manage().window().maximize();
driver.get("https://mathaus.ro");
WebDriverWait wait = new WebDriverWait(driver, 10);
wait.until(ExpectedConditions.elementToBeClickable(By.id("Constructii10NavNode"))).click();
Thread.sleep(3000);
wait.until(ExpectedConditions.elementToBeClickable(By.id("changeLocationReference"))).click();
Thread.sleep(3000);
wait.until(ExpectedConditions.elementToBeClickable(By.cssSelector("div.close-modal"))).click();
Thread.sleep(3000);
PS : Thread.sleep(3000); is just for visualization purpose. You can remove that. It's not really required
My Xpath is correct & no iFrame and I can locate element in Chrome console but my program still fails. I have used explicit wait also.
no such element: Unable to locate element: {"method":"xpath","selector":"//*[contains(#ng-click,'authenticationCtrl.onSubmitMage()')]"}
i tested my xpath with Try xpath and it works but when i compile my code i still recieve the error
the page Object :
package com.orange.pageObject;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.CacheLookup;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;
public class MageReferentiel {
WebDriver webdriver;
public MageReferentiel(WebDriver rwebDriver) {
webdriver = rwebDriver;
PageFactory.initElements(webdriver, this);
}
#FindBy(xpath = "//*[contains(#ng-click,'authenticationCtrl.onSubmitMage()')]")
#CacheLookup
WebElement connexion;
public void clickConnexion() {
connexion.click();
}
The step definition :
#When("l utilisateur choisi le referentiel")
public void l_utilisateur_choisi_le_referentiel() throws Exception {
mr.clickConnexion();
Thread.sleep(3000);
}
im looking to click in button
thanks
I agree with #Prophet, it could be because of some JS call the button, //*[contains(#ng-click,'authenticationCtrl.onSubmitMage()')] changing it's state to some other state. so what we can do about is that, to try with different locator.
such as :
//button[#translate ='LOGIN']
and see if that works, even if it doesn't try changing it to css.
Since ng elements are going very well with Protractor (Angular), better to use in Protractor in that case, so it suppose to be something like element(by.click('authenticationCtrl.onSubmitMage').click();
I guess the ng-click attribute value is dynamically updated on the page, so when you trying to access that element this element is changed, not having it's initial state.
Instead of locator you are using try this XPath:
//button[contains(text(),'Connexion')]
or this
//button[#translate='LOGIN']
The second element with this locator will be
(//button[#translate='LOGIN'])[2]
Looks like the element is not rendering on time. Try using explicit wait. Following gif shows how it is done using Cucumber:
https://nocodebdd.live/waitime-cucumber
Same been implemented using NoCodeBDD:
https://nocodebdd.live/waittime-nocodebdd
Disclaimer: I am the founder of NoCodeBDD so BDD automation can be achieved in minutes and without code. Through NoCodeBDD you could automate majority of the scenarios and it allows you to write your own code if there are edge cases. Would love to get some feedback on the product from the community. Basic version (https://www.nocodebdd.com/download) is free to use.
The default wait strategy in selenium is just that the page is loaded.
You've got an angular page so after your page is loaded there is a short delay while the JS runs and the element is finally ready in the DOM - this delay is causing your script to fail.
Check out the selenium docs here for wait strategies .
Your options are:
An explicit wait - This needs to be set per element you need to sync on.
I note you say you've used an explicit wait - but where? - It's not present in the code you shared and it might be that you've used the wrong expected condition.
Try something like this:
WebElement button = new WebDriverWait(rwebDriver, Duration.ofSeconds(10))
.until(ExpectedConditions.elementToBeClickable(By.xpath("//*[contains(#ng-click,'authenticationCtrl.onSubmitMage()')]")));
button.click();
Use an implicit wait - you only use this once when you initialise driver and it will wait the specified amount of time for all element interaction.
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
There are other reasons that selenium returns a NoSuchElement but synchronisation is the most common one. Give the wait a go and let me know if it is still giving you trouble.
Through discussion in the comments, the trouble is an iframe
If you google it - there are lots of answers out there.
With frames, you need to identify it, switch to it, do your action(s) then switch back:
//find and switch - update the By.
driver.switchTo().frame(driver.findElement(By.id("your frame id")));
//actions go here
//back to normal
driver.switchTo().defaultContent();
I have this funny bug happening to me today. I've been using Selenium for years already and never had an issue navigating to URL (via driver.navigate().to(url)) however today I'm attempting to navigate to a specific URL and I find that after executing the program several times it sometimes just stays on the original page without navigating to new page.
The funny thing is that this only happens about 50% of the time and it only happens when navigating to a specific URL at a specific part of the program (in other parts of program I have no issue navigating to this url).
Is it possible that some element on the current page is preventing driver.navigate().to(url) from executing?
I've looked at this and this question but both seem to have issues with navigating altogether. In my case, it sometimes works and sometimes doesn't (even when the exact same url is being used).
Also I'm not getting any specific errors (so I don't have much more info to post). The program just moves on as if the statement didn't exist.
I'll be happy to provide additional details if necessary.
Code:
shoppingCartURL.navToShoppingCart(driver);
String[] XPath = { "//*[contains (#value,'Delete')]" };
List<WebElement> elementList = webElementX.getElementListByXPath(driver, XPath);
System.out.println("Deleting " + elementList.size() + " element(s) from shopping cart");
for (int elementListCounter = 0; elementListCounter < elementList.size(); elementListCounter++) {
WebElement singleElement = elementList.get(elementListCounter);
try {
singleElement.click();
} catch (Exception e) {
System.out.println("Exception occurred (StaleElementReferenceException)");
}
}
if (conditionX == false) {
productPage.navToProductPage(driver, product); // this method is not always executed, program continues to execute productPage.performActionOnPage(driver); without navigating to 'product page'
productPage.performActionOnPage(driver);
}
public void navToProductPage(WebDriver driver, String product)
{
String URL = "https://www.example.com/product/" + product;
System.out.println("Navigating to " + URL); // always prints the correct url (but still doesn't always navigate to url as mentioned in question)
driver.navigate().to(URL);
}
Update:
I noticed ref=cart-ajax-error in redirect url (after deleting items from cart). Apparently, the site is using AJAX to refresh page after deleting items from cart. Might this conflict with my attempt to navigate to another page? In other words, perhaps Selenium is getting two different messages at the same time.. refresh page and navigate to new page.. so it remains on the current page?
If this is true, what can be done to resolve this issue?
Thanks!
When it sometimes happens and sometimes not it's nearly always a matter of timing.
Add an explicit wait to your code after navigating to the URL:
WebDriverWait wait = new WebDriverWait(driver, 20);
wait.until(ExpectedConditions.urlToBe(URL));
I am getting an error while running my selenium tests
Exception in thread "main"
org.openqa.selenium.StaleElementReferenceException: stale element
reference: element is not attached to the page document
(Session info: chrome=63.0.3239.84)
(Driver info: chromedriver=2.34.522932 (
4140ab217e1ca1bec0c4b4d1b148f3361eb3a03e),platform=Mac OS X 10.12.6
x86_64) (WARNING: The server did not provide any stacktrace
information)
Command duration or timeout: 0 milliseconds
For documentation on this error, please visit:
http://seleniumhq.org/exceptions/stale_element_reference.html
01T19:05:14.666Z'.
Here is the code
List<WebElement> category =
driver.findElements(By.className("a2s-skill-block"));
for(int i = 0;i<category.size();i++) {
category.get(i).click();
Thread.sleep(7000);
driver.navigate().back();
// WebElement skills1 = driver.findElement(By.id("iApps"));
//skills1.click();
Thread.sleep(15000);
}
I went through similar thread posts on this question and tried a lot of solutions mentioned by fellow members but somehow the wait and Expected COnditions don't seem to work.Any other direction of thought is really appreciated.
These are the options I tried
Increased the wait time through Thread.sleep() method
Introduced wait and Expected Conditions
WebDriverWait wait = new WebDriverWait(driver, 150);
wait.until(ExpectedConditions.
presenceOfAllElementsLocatedBy(By.className("text-heading")));
You should spend some time reading about and understanding what a StaleElementReferenceException is. It is important to understand what causes it and what to do to avoid it.
In this case, you are scraping the page and loading category with elements off of Page 1. You then click some link that takes you to page 2. At that point, all the references in category are stale but an exception isn't thrown yet because you haven't accessed any of the variables yet. You then use .back() to return to Page 1 and attempt to do something with category and get the exception.
To avoid this, you need to rescrape the elements into category on Page 1 after you use .back() from another page. One way is what I've written below. The page is scraped at the bottom of each loop.
List<WebElement> category = driver.findElements(By.className("a2s-skill-block"));
for (int i = 0; i < category.size(); i++)
{
category.get(i).click();
// sleeps are a bad practice, use WebDriverWait instead
driver.navigate().back();
driver.findElement(By.id("iApps")).click();
// sleeps are a bad practice, use WebDriverWait instead
category = driver.findElements(By.className("a2s-skill-block"));
}
You find out all category on the page before for loop. When you click something inside loop to enter another page, Actually the 'Stale Element Refrence' had been triggered, regrardless of you back to the last page finally.
Below conditions will trigger 'Stale Element Refrence'
Condition 1
Use the found element when you enter the page last time and you leave the page at least one time (even you back again).
You can think as when you enter a page Selenium will assign a reference to the page inside Selenium, Even you entered the same page, but Selenium can't know they are same so it will assign an new reference.
You can only use found element which page reference is same as current page you are on.
Condition 2
Stay on the page(not leave it), but your script triggered the HTML DOM Node of the found elements change/reattach/delete. for example some attribute of the DOM Node changed or the DOM Node removed and added back again desipte all atttibutes not change.
Thus any change/move on the DOM Node of found elements will trigger 'Stale Element Refrence'. You can think Condition 1 is just another way of change/move DOM Node.
To fix you issue, you should read out an attribute of all category which can be used to identify the category later in the loop.
Below code assume each category has unique text:
List<WebElement> category =
driver.findElements(By.className("a2s-skill-block"));
List<String> categoryTexts = new ArrayList<String>();
for(WebElement it: category) {
categoryTexts.add(it.getText());
}
for(int i = 0;i<category.size();i++) {
driver.findElement(By.xpath("//*[text()='"+categoryTexts.get(i)+"']")).click();
Thread.sleep(7000);
driver.navigate().back();
Thread.sleep(15000);
In the below code i cannot send password keys in the password field, i tried clicking the field, clearing the field and sending the keys. But now working in any of the method. But its working if i debug and test
public class TestMail {
protected static WebDriver driver;
protected static String result;
#BeforeClass
public static void setup() {
System.setProperty("webdriver.gecko.driver","D:\\geckodriver.exe");
driver = new FirefoxDriver();
driver.manage().timeouts().implicitlyWait(60, TimeUnit.SECONDS);
}
#Test
void Testcase1() {
driver.get("http://mail.google.com");
WebElement loginfield = driver.findElement(By.name("Email"));
if(loginfield.isDisplayed()){
loginfield.sendKeys("ragesh#gmail.in");
}
else{
WebElement newloginfield = driver.findElemnt(By.cssSelector("#identifierId"));
newloginfield.sendKeys("ragesh#gmail.in");
// System.out.println("This is new login");
}
driver.findElement(By.name("signIn")).click();
// driver.findElement(By.cssSelector(".RveJvd")).click();
driver.manage().timeouts().implicitlyWait(15, TimeUnit.SECONDS);
// WebElement pwd = driver.findElement(By.name("Passwd"));
WebElement pwd = driver.findElement(By.cssSelector("#Passwd"));
pwd.click();
pwd.clear();
// pwd.sendKeys("123");
if(pwd.isEnabled()){
pwd.sendKeys("123");
}
else{
System.out.println("Not Enabled");
}
Try setting an implicit wait of maybe 10 seconds.
gmail.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
Or set an explicit wait. An explicit waits is code you define to wait for a certain condition to occur before proceeding further in the code. In your case, it is the visibility of the password input field. (Thanks to ainlolcat's comment)
WebDriver gmail= new ChromeDriver();
gmail.get("https://www.gmail.co.in");
gmail.findElement(By.id("Email")).sendKeys("abcd");
gmail.findElement(By.id("next")).click();
WebDriverWait wait = new WebDriverWait(gmail, 10);
WebElement element = wait.until(
ExpectedConditions.visibilityOfElementLocated(By.id("Passwd")));
gmail.findElement(By.id("Passwd")).sendKeys("xyz");
Explanation: The reason selenium can't find the element is because the id of the password input field is initially Passwd-hidden. After you click on the "Next" button, Google first verifies the email address entered and then shows the password input field (by changing the id from Passwd-hidden to Passwd). So, when the password field is still hidden (i.e. Google is still verifying the email id), your webdriver starts searching for the password input field with id Passwd which is still hidden. And hence, an exception is thrown.
"element not interactable" error can mean two things :
a. Element has not properly rendered:
Solution for this is just to use implicit /explicit wait
Implicit wait :
driver.manage().timeouts().implicitlyWait(50, TimeUnit.SECONDS);
Explicit wait :
WebDriverWait wait=new WebDriverWait(driver, 20);
element1 = wait.until(ExpectedConditions.elementToBeClickable(By.className("fa-stack-1x")));
b. Element has rendered but it is not in the visible part of the screen:
Solution is just to scroll till the element. Based on the version of Selenium it can be handled in different ways but I will provide a solution that works in all versions :
JavascriptExecutor executor = (JavascriptExecutor) driver;
executor.executeScript("arguments[0].scrollIntoView(true);", element1);
Suppose all this fails then another way is to again make use of Javascript executor as following :
executor.executeScript("arguments[0].click();", element1);
If you still can't click , then it could again mean two things :
1. Iframe
Check the DOM to see if the element you are inspecting lives in any frame. If that is true then you would need to switch to this frame before attempting any operation.
driver.switchTo().frame("a077aa5e"); //switching the frame by ID
System.out.println("********We are switching to the iframe*******");
driver.findElement(By.xpath("html/body/a/img")).click();
2. New tab
If a new tab has opened up and the element exists on it then you again need to code something like below to switch to it before attempting operation.
String parent = driver.getWindowHandle();
driver.findElement(By.partialLinkText("Continue")).click();
Set<String> s = driver.getWindowHandles();
// Now iterate using Iterator
Iterator<String> I1 = s.iterator();
while (I1.hasNext()) {
String child_window = I1.next();
if (!parent.equals(child_window)) {
driver.switchTo().window(child_window);
element1.click()
}
Please try selecting the password field like this.
WebDriverWait wait = new WebDriverWait(driver, 10);
WebElement passwordElement = wait.until(ExpectedConditions.elementToBeClickable(By.cssSelector("#Passwd")));
passwordElement.click();
passwordElement.clear();
passwordElement.sendKeys("123");
you may also try full xpath, I had a similar issue where I had to click on an element which has a property javascript onclick function. the full xpath method worked and no interactable exception was thrown.
In my case the element that generated the Exception was a button belonging to a form. I replaced
WebElement btnLogin = driver.findElement(By.cssSelector("button"));
btnLogin.click();
with
btnLogin.submit();
My environment was chromedriver windows 10
In my case, I'm using python-selenium.
I have two instructions. The second instruction wasn't able to execute.
I put a time.sleep(1) between two instructions and I'm done.
If you want you can change the sleep amount according to your need.
I had the same problem and then figured out the cause. I was trying to type in a span tag instead of an input tag. My XPath was written with a span tag, which was a wrong thing to do. I reviewed the Html for the element and found the problem. All I then did was to find the input tag which happens to be a child element. You can only type in an input field if your XPath is created with an input tagname
I'm going to hedge this answer with this: I know it's crap.. and there's got to be a better way. (See above answers) But I tried all the suggestions here and still got nill. Ended up chasing errors, ripping the code to bits. Then I tried this:
import keyboard
keyboard.press_and_release('tab')
keyboard.press_and_release('tab')
keyboard.press_and_release('tab') #repeat as needed
keyboard.press_and_release('space')
It's pretty insufferable and you've got to make sure that you don't lose focus otherwise you'll just be tabbing and spacing on the wrong thing.
My assumption on why the other methods didn't work for me is that I'm trying to click on something the developers didn't want a bot clicking on. So I'm not clicking on it!
I got this error because I was using a wrong CSS selector with the Selenium WebDriver Node.js function By.css().
You can check if your selector is correct by using it in the web console of your web browser (Ctrl+Shift+K shortcut), with the JavaScript function document.querySelectorAll().
If it's working in the debug, then wait must be the proper solution.
I will suggest to use the explicit wait, as given below:
WebDriverWait wait = new WebDriverWait(new ChromeDriver(), 5);
wait.until(ExpectedConditions.presenceOfElementLocated(By.cssSelector("#Passwd")));
I came across this error too. I thought it might have been because the field was not visible. I tried the scroll solution above and although the field became visible in the controlled browser session I still got the exception. The solution I am committing looks similar to below. It looks like the event can bubble to the contained input field and the end result is the Selected property becomes true.
The field appears in my page something like this.
<label>
<input name="generic" type="checkbox" ... >
<label>
The generic working code looks more or less like this:
var checkbox = driver.FindElement(By.Name("generic"), mustBeVisible: false);
checkbox.Selected.Should().BeFalse();
var label = checkbox.FindElement(By.XPath(".."));
label.Click();
checkbox.Selected.Should().BeTrue();
You'll need to translate this to your specific language. I'm using C# and FluentAssertions. This solution worked for me with Chrome 94 and Selenium 3.141.0.
I had to hover over the element first for the sub-elements to appear. I didn't take that into account at first.
WebElement boardMenu = this.driver.findElement(By.linkText(boardTitle));
Actions action = new Actions(this.driver);
action.moveToElement(boardMenu).perform();
Another tip is to check that you are having one element of that DOM. Try using Ctrl+F when inspecting the web page and check your xpath there; it should return one element if you are going with the findElement method.