I want to open a website with selenium and extract some text via xpath. It's working but I can get the text only if I wait a few seconds until the whole website is loaded, but it would be nicer to check if the website is fully loaded. I guess I should check for any background connections (ajax calls, GETs, POSTs or whatever), what is the best way to do it? At the moment I'm trying to extract the text in a while loop (ugly solution):
WebDriver driver = new FirefoxDriver();
driver.get("http://www.website.com");
// Try to get text
while (true) {
try {
WebElement findElement = driver.findElement(By.xpath("expression-here"));
System.out.println(findElement.getText());
break;
// If there is no text sleep one second and try again
} catch (org.openqa.selenium.NoSuchElementException e) {
System.out.println("Waiting...");
Thread.sleep(1000);
}
}
How would you solve this?
Selenium has already timeouts for this.
Look here: http://seleniumhq.org/docs/04_webdriver_advanced.jsp
I have solve it with:
webDriver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);
Prefer explicit waits:
1) more readable
2) been using those for long time
3) what if you know the element is not there (your test is to verify it) and don't need to poll for 10 seconds? With implicit you are now wasting time.
WebElement myDynamicElement = (new WebDriverWait(driver, 10))
.until(new ExpectedCondition<WebElement>(){
#Override
public WebElement apply(WebDriver d) {
return d.findElement(By.id("myDynamicElement"));
}});
Related
I'm facing a problem with finding an element that does not exist. When I try to login into the application, if it failed login it will show the element -
dr.findElement(By.className("message-error ")).getText();
And after a successful login it will show this:
dr.findElement(By.className("message-success")).getText();
When I run the code and it doesn't find the element, then execution stops with the exception: element is not found
String mes=null;
mes=dr.findElement(By.className("message-success")).getText();
if(mes!=null) {
File out= new File("success.txt");
FileWriter fr =new FileWriter(out,true);
PrintWriter pw=new PrintWriter(fr);
pw.println(mes+"|"+user.get(i)+"|"+pass.get(i));
pw.close();
}
mes=dr.findElement(By.className("message-error")).getText();
if(mes!=null) {
File out= new File("error.txt");
FileWriter fr =new FileWriter(out,true);
PrintWriter pw=new PrintWriter(fr);
pw.println(mes+"|"+user.get(i)+"|"+pass.get(i));
pw.close();
}
The element does not appear.
For example, the success element will not shown until it is successful and the error element will not appear in the CSS until it gets an error.
So how can I tell it if element should exit or come to live or appear do an action?
What is the right thing to do in an if statement if the login is successful? Do this and login fail do this?
Use WebdriverWait to wait for the visibility of success message,
// After valid login
WebDriverWait wait = new WebDriverWait(driver, 60);
WebElement successmessage wait.until(ExpectedConditions.visibilityOfElementLocated(By.className("message-success")));
sucessmessage.getText();
Similarly for error message,
// After invalid login
WebElement errormessage wait.until(ExpectedConditions.visibilityOfElementLocated(By.className("message-error")));
errormessage.getText();
What i think is you have same element but the class getting change as per application behavior. suppose if you are able to login in the application then it show the message element with class having attribute message-success and if it won't allow then error message with class having attribute 'message-error' in the same element.
I've handled the same in below code -
// first get the message element with some other locator or other attribute (don't use class name)
WebElement message = driver.findElement(By.locator);
if(message.getAttribute("class").contains("message-success")){
System.out.println("Success message is " + message.getText())
// write the code to perform further action you want on login success
}else if (message.getAttribute("class").contains("message-error")){
System.out.println("Error message is " + message.getText())
// write the code to perform further action you want on login Fail
}else{
System.out.println("Message is empty" + message.getText())
}
Let me know if you have further queries.
My Choice is to use Webdriver wait. it is the perfect way to find an element.
public WebDriverWait(WebDriver driver,15)
WebElement successmessage = wait.until(ExpectedConditions.visibilityOfallElementLocatedby(By.className("message-success")));
sucessmessage.getText();
visibilityOfallElementLocatedby :
An expectation for checking that all elements present on the web page that match the locator are visible. Visibility means that the elements are not only displayed but also have a height and width that is greater than 0.
The above i wrote is for success Message, similar way try for invalid login.
To use different types of wait, check this doc - https://seleniumhq.github.io/selenium/docs/api/java/allclasses-noframe.html
search Wait in that document.
this is the answer for the question it work with me
try {
WebElement sucmes=dr.findElement(By.xpath("//div[#class='message']"));
String suclogin="login success:";
if(sucmes.getText().contains(suclogin)) {
File suclogin= new File("suclog.txt");
FileWriter suclogr =new FileWriter(suclogin,true);
PrintWriter suclogrw=new PrintWriter(suclogr);
suclogrw.println(sucmes.getText());
suclogrw.close();
}else{
//the other action here
}
}
At times due to time out or other reason the page stops loading or gets loaded but the signup page doesn't appear, to make sure it appears we have to refresh the page, I have tried driver.navigate.refresh(), I have tried explicit wait and javascript executor, nothing works, I am adding the snippet of what I have tried, but it doesn't work either.
My scripts fails once the findelement().isdisplayed is false, it is not going in the if loop.
Below is the code-
for(int i=0;i<3;i++)
{
System.out.println("In for loop");
try
{
if(driver.findElement(byusername).isDisplayed())
{
System.out.println("Element found");
driver.findElement(byusername).sendKeys(username);
driver.findElement(bypassword).sendKeys(password);
driver.findElement(signIn).click();
System.out.println("Logged in");
basewait.until( ExpectedConditions.presenceOfElementLocated(Tab));
System.out.println("Wait completed, going to base class");
i=3;
}
else
{
System.out.println("Element not found"+i+" try");
driver.navigate().refresh();
driver.manage().timeouts().implicitlyWait(20, TimeUnit.SECONDS);
i++;
}
}
catch(NoSuchElementException e)
{
System.out.println(e);
}
Try to replace:
if(driver.findElement(byusername).isDisplayed())
with:
if(driver.findElements(byusername).size() > 0 && driver.findElements(byusername).get(0).isDisplayed())
This won't throw exception and you can go to else statement. driver.findElements(byusername) return a list of elements found and if no elements were found it returns just an empty list.
First, note that an implicit wait only needs to be set one time, after the instantiation of your web driver, unless for whatever reason you wanted to later change the timeout value of that setting.
Second, try using the below code to wait for the page to finish loading.
/**
* Wait for the web page to finish loading
*/
public void waitForPageToLoad() {
WebDriverWait wait = new WebDriverWait(driver, 10);
wait.until(new ExpectedCondition<Boolean>() {
public Boolean apply(WebDriver wdriver) {
return ((JavascriptExecutor) driver).executeScript("return document.readyState").equals("complete");
}
});
}
I am trying to write a Selenium test against Amazon site. I want to get "Sign in" element so that I can click on it.
url: www.amazon.es
Here is my Selenium Code:
System.setProperty("webdriver.gecko.driver","C:\\geckodriver-v0.18.0-win64\\geckodriver.exe");
WebDriver driver = new FirefoxDriver();
driver.get("https://www.amazon.es");
try
{
driver.findElement(By.id("nav-link-accountList")).click();
}
catch (Exception e)
{
System.out.println("Not Found");
}
Sometimes the code works correctly but sometimes it does not find the ID "nav-link-yourAccount". What is the problem? and how can I solve it?
Provide few seconds of wait, before click to this webelement so your driver may able to find the webelement.
For wait i am using Explicit wait method.
WebDriverWait wait = new WebDriverWait(driver,10);
wait.until(ExpectedConditions.elementToBeClickable(driver.findElement(By.id("nav-link-accountList"))));
driver.findElement(By.id("nav-link-accountList")).click();
The element which you are trying to click with id as nav-link-yourAccount is not clickable. To proceed further you need to click either the link with text Hola. Identifícate or the link with text Mi cuenta using one of the following xpaths:
//a[#id='nav-link-yourAccount']/span[text()='Hola. Identifícate']
or
//a[#id="nav-link-yourAccount"]/span[contains(text(),'Mi cuenta')]
Instead using implicit wait try using explicit wait for the login element.
I've tried with explicit wait over 50 click and it did works.
Here is code you can use.
public class dump {
public static void main(String a[]){
System.setProperty("webdriver.gecko.driver","C:\\geckodriver-v0.18.0-win64\\geckodriver.exe");
WebDriver driver = new FirefoxDriver();
WebDriverWait wait = new WebDriverWait(driver, 15);
for(int i=0; i<=50; i++){
driver.get("https://www.amazon.es");
try{
wait.until(ExpectedConditions.elementToBeClickable(By.xpath("//*[#id='nav-link-accountList']")));
driver.findElement(By.xpath("//*[#id='nav-link-accountList']")).click();
System.out.println("clicked\t"+i);
}catch (Exception e){
e.printStackTrace();
System.out.println("Not Found");
}
}
}
}
Here is the proof of run:
All the best!!
Apply wait until element is appeared, so that it avoids NoSuchElementException and code is working without any error.
Below code is working fine:
driver.get("https://www.amazon.es");
driver.manage().timeouts().implicitlyWait(20, TimeUnit.SECONDS);
WebElement accontButton=driver.findElement(By.id("nav-link-accountList"));
WebDriverWait waitforelement=new WebDriverWait(driver,20);
waitforelement.until(ExpectedConditions.elementToBeClickable(accontButton));
try{
accontButton.click();
}
catch (Exception e){
System.out.println("Not Found");
}
Have you tried to find elements by xpath?
System.setProperty("webdriver.gecko.driver","C:\\geckodriver-v0.18.0-win64\\geckodriver.exe");
WebDriver driver = new FirefoxDriver();
driver.get("https://www.amazon.es");
try
{
driver.findElement(By.xpath("//*[#id='nav-link-accountList']")).click();
}catch (Exception e)
{
System.out.println("Not Found");
}
Explicit wait is not working if the element located is of 'text'. But it is working fine if the driver performs some action i.e, entering text into text box or clicking a webelement etc.
public boolean waitForPageToLoad(String timeOutInSeconds) throws ScreenShotException, InterruptedException {
boolean bFlag = false;
WebElement element;
boolean bStatus = true;
int timeinseconds1 = Integer.parseInt(timeOutInSeconds);
try {
WebDriverWait wait = new WebDriverWait(webDriver, timeinseconds1);
while(timeinseconds1 > 0) {
element = wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("myDynamicElement")));
Log.info("Element status at runtime -->"+element.isDisplayed());
if(!element.isDisplayed()) {
timeinseconds1 = timeinseconds1 - 500;
Thread.sleep(1000);
}
else {
System.out.println("working");
bFlag = bStatus;
Log.info("Element status: - >"+bFlag);
break;
}
}
}
catch (Exception e) {
screenShot.screenShot(e);
}
return bFlag;
}
The above code doesnt work if my locator is of text i.e, say if I want to check whether 'Title' of the question in the stackoverflow is visible or not within 40seconds.Driver will wait for 40seconds though the title appears less than that. But, it works fine if the locator is Title text box. Please let me know how to resolve this.
You are using the wait quite differently that it is supposed to be used.
try {
WebDriverWait wait = new WebDriverWait(webDriver, timeinseconds1);
element = wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("myDynamicElement")));
} catch (TimeOutException toe) {
//handle the page not loading
}
//from now on continue the code as synchronous knowing that the page is loaded
I'm new to Selenium & Java. What I'm trying to accomplish is to wait for an element to appear on a timeout, and if that element appears before the timeout runs down, then just keep running. The code below will give a TimeoutException and stop the rest of the code from running.
WebElement myDynamicElement = (new WebDriverWait(driver, 10))
.until(ExpectedConditions.presenceOfElementLocated(By.id("my_element")));
Please try this way:
public boolean isFind(WebElement my_element) {
try{
WebElement myDynamicElement = (new WebDriverWait(driver, 10))
.until(ExpectedConditions.presenceOfElementLocated(By.id("my_element")));
}
catch(TimeoutException exception) {
return false;
}
return true;
}
Thank you for all your help, it took me a bit of playing around with it. Here is the solution I came up with. Hope it helps the next guy. Let me know if I messed something up please, thanks again.
try{
WebDriverWait wait = new WebDriverWait(driver, 5);
wait.until(ExpectedConditions.presenceOfElementLocated(By.xpath("//input[#id='signup_email']")));
}catch (org.openqa.selenium.TimeoutException e){
JOptionPane.showMessageDialog(null, "Login Complete!");
return;
}
You can use ExpectedConditions.visibilityOf
WebDriverWait wait = new WebDriverWait(d, 120);
wait.until(ExpectedConditions.visibilityOf(d.findElement(By.xpath("//input[#id='signup_email']"))));