Last active
August 22, 2018 19:08
-
-
Save jasonrobot/c38625bdbcb1ea39aa26e71b2b571a18 to your computer and use it in GitHub Desktop.
Some examples of more complicated waits for tricky scenarios
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* 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