Vishvambruth JT Vishvambruth JT - 1 month ago 16
Java Question

Need to write the selenium code without the Thread.sleep

I have written the below code to login to the website "qtpselenium.com".

The below code works just fine if i give Thread.sleep in between to make the code execution halt for some time.
If I comment the Thread.sleep, the code doesn't work as expected.
I have tried to use implicit and explicit waits of selenium to make driver to wait for the element to be visible but the code only works as expected when i use the Thread.sleep.

Is there any way I can make the below code to work without using the Thraed.Sleep statement.

and is it a bad practice to use Thread.sleep statements in the selenium code?

import java.util.concurrent.TimeUnit;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.FluentWait;

public class QTPSelenium {

public static WebDriver driver = null;

public static void main(String[] args) throws InterruptedException {

System.setProperty("webdriver.gecko.driver","C:\\Eclipse\\Drivers\\geckodriver.exe");
driver = new FirefoxDriver();
driver.get("http://qtpselenium.com/");

driver.findElement(By.xpath(".//*[@class='btn btn-default member_login']")).click();
Thread.sleep(10000);

driver.findElement(By.xpath("(//button[@type='submit'])[3]")).click();
Thread.sleep(10000);

driver.findElement(By.id("email")).sendKeys("Some Email ID");
driver.findElement(By.id("login-password")).sendKeys("Some Password");
driver.findElement(By.xpath("html/body/main/div[2]/div/div/div[1]/div/div/div/form/button")).click();
}
}

Answer

Yes, it is generally bad practice to use Thread.sleep(). Sleeps aren't dynamic. They only wait for the specified time... no more, no less. This generally is not good because if the element you are waiting for comes back in 25ms, then you will wait the full 10s. If the element comes at 10.5s, then it will fail. With automation we want to go as fast as possible while maintaining consistent results. Using WebDriverWait will allow the script to pause and wait for the specified condition. Once the condition is met, the script continues. If it isn't met, the script will pause for the specified amount of time and retry until either the condition is met or a timeout occurs (throws an exception). So, make sure you wait as long as is reasonable to wait.

Instead use WebDriverWait, as I have below. Take a look at ExpectedConditions. There are many conditions you can wait for... presence of an element, element to be clickable, etc.

I switched to the geckodriver and tried the code again. I changed your locators to make them more specific. They are basically looking for a tag that contains certain text. You can reuse that locator several times. The code below is working for me. I removed the sleeps and replaced them with WebDriverWait.

driver.get("http://qtpselenium.com/");
driver.findElement(By.xpath("//button[contains(.,'Member Login')]")).click();
WebDriverWait wait = new WebDriverWait(driver, 5); // create a WebDriverWait that we will reuse
wait.until(ExpectedConditions.elementToBeClickable(By.xpath("//button[contains(.,'Login to Selenium Account')]"))).click();
wait.until(ExpectedConditions.presenceOfElementLocated(By.id("email"))).sendKeys("Some Email ID");
driver.findElement(By.id("login-password")).sendKeys("Some Password");
driver.findElement(By.xpath("//button[contains(.,'Login')]")).click();