Skip to content

Instantly share code, notes, and snippets.

@jasonrobot
Last active August 22, 2018 19:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jasonrobot/c38625bdbcb1ea39aa26e71b2b571a18 to your computer and use it in GitHub Desktop.
Save jasonrobot/c38625bdbcb1ea39aa26e71b2b571a18 to your computer and use it in GitHub Desktop.
Some examples of more complicated waits for tricky scenarios
/* for this one, we were entering text to a textarea element, and it was being stored as the element's value. Selenium
* is fast enough that it will do this, then move on the the next bit of code (usually clicking a save or done button)
* before JS has updated the value with the text. Its tempting to use a Thread.sleep, but using Selenium's built-in
* waits, we can handle this */
el(socialIconUrlInput).sendKeys(url);
wait.until(ExpectedConditions.textToBePresentInElementValue(socialIconUrlInput, url)); //now we're sure its ok to move on
clickElement(el(doneButton));
/* in this case, a button was being clicked that caused a list of options to change in the UI. These option buttons were
* being removed, then replaced with the new ones when the button was clicked (which gets done via JS). Selenium would
* click the button, then find the element for the options as JS was modifying the DOM, causing a stale element exception.
* This wait avoids the stale element by expecting it to happen */
WebElement option1 = el(option1Button);
clickElement(el(editButton))
wait.until(ExpectedConditions.stalenessOf(option1)); // we wait until the DOM gets manipulated
el(option1Button).click(); //note that we can't use the old refrence (it got stale!) so we have to find the element again
/* this can be used to fix a lot of stale element refrence exception errors. Just be aware that if the condition never
* happens, this will throw a TimeoutException. You may need to catch that exception if the wait condition isnt consistent
* enougn and you dont want the test to fail */
try
{
wait.until(ExpectedConditions.stalenessOf(option1));
}
catch (TimeoutException e)
{
// dont need to handle it, just make sure it isnt thrown. TimeoutException is a RuntimeException!
}
/* sometimes you need to wait for the opposite of something. When testing that an unsaved data warning will appear in an
* editor, selenium can edit the page and navigate away faster than the JS can register the edit. We already have a custom
* expected condition that we use to wait for there to be no unsaved changes, and by inverting it, we can wait for there
* to be unsaved changes. (no need to write a second custom condition) */
public void clickCancel (boolean expectChanges)
{
if ( expectChanges )
{
//this way we'll know that the JS has registered changes and we should see our warning message
wait(25).until(ExpectedConditions.not(CustomConditions.hasNoChanges));
}
el(cancel).click();
}
/* speaking of custom conditions, you can write them for nearly anything! There are a ton of really useful ones included
* with selenium, but sometimes you have to get creative. Here's the one mentioned in the previous example that waits for
* an editor to have no changes to save */
public static ExpectedCondition<Boolean> hasNoChanges = new ExpectedCondition<Boolean>()
{
String script = "return ontraport.window.panel.currentPane.hasChanges() === false";
@Override
public Boolean apply (WebDriver driverObject)
{
return (Boolean) ((JavascriptExecutor) driverObject).executeScript(script);
}
};
/* We even have one that will wait until a landing page is hosted. Check out the tools/CustomConditions class for more! */
/* A neat feature of the .until method of WebDriverWait is that its return type is defined by the ExpectedCondition using
* Java's generic types. It will (afaik) always be either Boolean or WebElement. This means you can actually use waits to
* find elements, like this */
wait.until(ExpectedConditions.presenceOfElementLocated(By.cssSelector("table"))).findElement(By.cssSelector("td"));
wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("input"))).sendKeys("foobar");
/* Here's a tricky situation: You need to wait to be redirected to another page, but it could be one of many pages, so you
* can't just do something simple like wait for an element to be present. You can use ExpectedConditions.not() for this */
String currentUrl = driver.getCurrentUrl();
wait.until(ExpectedConditions.not(ExpectedConditions.urlContains(currentUrl));
/* There are a bunch more of these built in to Selenium. Even some crazy ones like:
* numberOfWindowsToBe(int)
* javaScriptThrowsNoExceptions(String)
* frameToBeAvailavleAndSwitchToIt(By)
* attributeToBe(By, String, String)
* and lots more. I'd suggest checking out both the Javadoc and the source code for the ExpectedConditions class. */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment