Selenium WebDriver Safe Tests

I know this question has been asked many times before, but I still could not find a solution that works for me. When I run tests with Selenium WebDriver in most cases, they fail with a "NoSuchElementException". I tried to use Explicit and Implicit Expectations, but nothing works. So, is there any other way besides using Waits in which I can make my tests more reliable?

I am using selenium-java-2.31.0 with FirefoxDriver. The following are sample code that I tried to make my tests more reliable:

public void waitAndClickElement(WebDriver driver, final By selector) { Wait<WebDriver> wait = new FluentWait<WebDriver>(driver) .withTimeout(50, TimeUnit.SECONDS) .pollingEvery(5, TimeUnit.SECONDS) .ignoring(NoSuchElementException.class); WebElement elementToClick = wait .until(new Function<WebDriver, WebElement>() { public WebElement apply(WebDriver driver) { return driver.findElement(selector); } }); waitForElementVisible(driver, selector); elementToClick.click(); } 

.. and this:

 public WebElement waitForElementPresent(WebDriver driver, final By selector){ Wait<WebDriver> wait = new FluentWait<WebDriver>(driver) .withTimeout(70, TimeUnit.SECONDS) .pollingEvery(5, TimeUnit.SECONDS) .ignoring(NoSuchElementException.class); WebElement elementToClick = wait .until(new Function<WebDriver, WebElement>() { public WebElement apply(WebDriver driver) { return driver.findElement(selector); } }); return elementToClick; } 

... and this:

 WebDriverWait wait = new WebDriverWait(driver, 50); WebElement user_name = wait.until(visibilityOfElementLocated(By.xpath("//*@id='userName']"))); 

... and this:

 driver.manage().timeouts().implicitlyWait(50, TimeUnit.SECONDS); 

... and finally, one of the tests I'm trying to make more reliable:

 @Test public void test1{ waitAndClickElement(driver, By.xpath("//*[@id='linkLogIn']")); waitForElementPresent(driver, By.xpath("//*[@id='userName']")).sendKeys("name"); waitForElementPresent(driver, By.xpath("//*[@id='inputEmail']")).sendKeys(" email@gmail.com "); waitForElementPresent(driver,By.xpath("//*[@id='resetPassword']")).click(); assertTrue(isElementPresent(By.xpath("//*[@id='moduleMain']"))); 

}

Thanks!

+4
source share
6 answers

Try using a custom method. It works great for me,

 public boolean waitForElementToBePresent(By by, int waitInMilliSeconds) throws Exception { WebDriver driver = getDriver(); int wait = waitInMilliSeconds; int iterations = (wait/250); long startmilliSec = System.currentTimeMillis(); for (int i = 0; i < iterations; i++) { if((System.currentTimeMillis()-startmilliSec)>wait) return false; List<WebElement> elements = driver.findElements(by); if (elements != null && elements.size() > 0) return true; Thread.sleep(250); } return false; } 

Use it like

 waitForElementToBePresent(By.id("linkLogIn", 5000); driver.findElement(By.id("linkLogIn")).click(); 
+1
source

WebDriver is completely stable if you handle exceptions correctly. The problem is that the methods of the ExpectedConditions class do not handle exceptions for you, although most people will answer your question as if it happened.

You can try my method if you want. This method returns between 0 and 90 seconds, depending on the scenario. You can change this method a bit, but it should work. important concepts :

 1. Use the new FluentWait class with the .ignoring method (or .ignoreAll() ). 2. Use findElement() BUT make sure you catch (and nicely handle) the possible exceptions (that you are ignoring in the wait). 3. Use a loop to retry after exceptions but govern that by either time or # of tries. 

And the code:

 public WebElement getElementByLocator( final By locator ) { LOGGER.info( "Get element by locator: " + locator.toString() ); final long startTime = System.currentTimeMillis(); Wait<WebDriver> wait = new FluentWait<WebDriver>( driver ) .withTimeout(30, TimeUnit.SECONDS) .pollingEvery(5, TimeUnit.SECONDS) .ignoring( NoSuchElementException.class ) .ignoring( StaleElementReferenceException.class ) ; int tries = 0; boolean found = false; WebElement we = null; while ( (System.currentTimeMillis() - startTime) < 91000 ) { LOGGER.info( "Searching for element. Try number " + (tries++) ); try { we = wait.until( ExpectedConditions.visibilityOfElementLocated( locator ) ); found = true; break; } catch ( StaleElementReferenceException e ) { LOGGER.info( "Stale element: \n" + e.getMessage() + "\n"); } catch ( NoSuchElementException nse ) { LOGGER.info( "No such element: \n" + nse.getMessage() + "\n"); } } long endTime = System.currentTimeMillis(); long totalTime = endTime - startTime; if ( found ) { LOGGER.info("Found element after waiting for " + totalTime + " mill." ); } else { LOGGER.info( "Failed to find element after " + totalTime + " mill." ); } return we; } 
+1
source

When you run findElement, you will receive an error message when it is not found. This happens for one of three reasons:

Your selector is wrong

If the selector is wrong, it’s best to debug it until you get to this place and pause the test. Then use the console to find the correct selector to find the item.

Item is missing

You may notice in your first action that the item you are looking for is actually missing. In this case, find out why you are in this wrong state and correct it. If you expect the element to not be there, Here is a great C # example on how to extend your IWebElement object to allow a. There is an Exists () method.

Item is late

Determining whether an element is just late is easy. Run the test usually once, and then run in debug mode, step by step, each step manually. If your normal test run failed while you are following the steps with the manual, you know you found your problem. Typically, the problem is related to the AJAX load that does not occur when the page loads. In these cases, a good webdev usually adds some kind of spinner image that you can easily find. I created a helper method WaitForPageLoad (), which first waits for the page to load, and then checks to see if there is a counter, and then again waits for the page to load. You want 2 pages to load because the modal will rotate and then load when a new page load is loaded and then rotate. Finally, the page is complete, your item will be present.

+1
source

Have you tried to catch element by element without waiting for all the theses and wait.until?

simple: WebElement username = driver.findelement(By.id("userName"));

Can you omit your html?

EDIT:

I can suggest the following:

 protected void sleep(int i) { driver.manage().timeouts().implicitlyWait(i, TimeUnit.SECONDS); } @test void test(){ driver.findElement(By.id("linkLogIn")).click(); sleep(6); driver.findElement(By.id("userName")).sendKeys("user"); sleep(1); driver.findElement(By.id("inputEmail")).sendKeys(" mail@gmail.com "); sleep(1); driver.findElement(By.id("resetPassword")).click(); sleep(10); Assert.assertTrue(isElementPresent(By.id("moduleMain"))); } 
0
source

I ran into the same type of problem using WebDriver with C #. I can offer two different ways how you can avoid (not completely, but minimize) the NoSuchElementException exception in your tests:

  • First of all, you should find out how your application works - whether it uses a lot of Ajax and other asynchronous programs. requests / responses. Then you can use an explicit wait for each item that cannot be found right away.

  • You can write your own implementation of the WebElement class based on the Selenium WebDriver WebElement class. The main idea is that every time you use your web element, it will be moved, so you will not worry about NoSuchElement or StaleElementException.

0
source

Well, your code tells me that you only wait until the element appears.

 waitForElementPresent(driver, By.xpath("//*[@id='userName']")).sendKeys("name"); waitForElementPresent(driver, By.xpath("//*[@id='inputEmail']")).sendKeys(" email@gmail.com "); 

I am not told anything that you clicked on the field, and then use sendkeys to enter the text. How about adding a click

  waitForElementPresent(driver, By.xpath("//*[@id='userName']")); driver.findElement(by.id ="userName").click(); driver.findElement(by.id ="userName").sendKeys("name"); 

The problem is focusing the mouse on the webdriver, it needs to be focused in the corresponding AFAIK field

-1
source

All Articles