I'm new to selenium and I'm kind of stuck.
I'm automating GWT base application and I need to wait till map tiles are fully loaded before moving to next process.
I'm try to find in google but no luck.
I found something like
public static final void waitTillPageLoad()
{
WebDriverWait wait = new WebDriverWait(LoginTestScript.fd, 40);
wait.until( new Predicate<WebDriver>() {
public boolean apply(WebDriver driver) {
return ((JavascriptExecutor)driver).executeScript("return document.readyState").equals("complete");
}
}
);
}
but, I need to wait untill map tiles loaded not document.readyState
do anyone have idea how can I wait until all map tiles loaded successfully.
Thank you.
You can use the below method:
public boolean checkForPresenceOfElementByXpath(String xpath){
try{
new WebDriverWait(driver, 5)).until(ExpectedConditions.visibilityOfElementLocated(By.xpath("(xpath)[last()]")));
return true;
}catch(Exception e){
return false;
}
}
Remove the return type and return statements, if you dont want to return the values.
Related
I am automating in Java Selenium, without using Page Factory.
I have an Add Candidate Button element that is clicked in two tests. One is straightforward, after entering InviteToCompany page I click this button and proceed. However, another requires me to go past InviteToCompany page, but then use Go Back Arrow to go back to 'InviteToCompany' page and click Add Candidate Button again. This is when StaleElementReferenceException appears.
I have written such a piece of code to deal with this issue, however I am wondering, if there is a cleaner and neater way, than catching exception for second test, to proceed.
public InviteToCompanyPO clickAddCandidateBtn() {
try {
getClickableElement(addCandidateBtn).click();
} catch (StaleElementReferenceException e) {
log.warn("StaleElementReferenceException caught, retrying...", e);
getClickableElement(addCandidateBtn).click();
}
return new InviteToCompanyPO(driver);
}
Before I had to write second test (the one causing staleness), this method simply looked like this:
public InviteToCompanyPO clickAddCandidateBtn() {
getClickableElement(addCandidateBtn).click();
return new InviteToCompanyPO(driver);
}
I tried writing something like this:
public InviteToCompanyPO clickAddCandidateBtn() {
wait
.ignoring(StaleElementReferenceException.class)
.until(ExpectedConditions.elementToBeClickable(addCandidateBtn))
.click();
return new InviteToCompanyPO(driver);
}
but it doesn't work.
I guess you are using a page factory?
Anyway, when you back to the InviteToCompany page and need to click Add Candidate Button again you will need to get that element again.
I mean to pass the locator or By of that element and get the WebElement object again with driver.findElement() method.
This causes by the fact that WebElement is actually a reference (pointer) to the actual Web Element on the page. And when you navigating from the page to other page the references to the objects on the previous page becoming invalid, Stale. When you open the previous page again it is rendered again, so you need to get the references (pointers) to elements on that page again.
Cleaner way You can use a Webdriver wait Like this to click
public void refreshedClick(By by){
new WebDriverWait(driver, timeout)
.ignoring(StaleElementReferenceException.class)
.until(new Predicate<WebDriver>() {
#Override
public boolean apply(#Nullable WebDriver driver) {
driver.findElement(by).click();
return true;
}
});
}
Java 8
public void refreshedClick(By by){
new WebDriverWait(driver, timeout)
.ignoring(StaleElementReferenceException.class)
.until((WebDriver d) -> {
d.findElement(by).click();
return true;
});
}
I am trying to build a bot with selenium. the problem is that from time to time the website logging me out without any notice. I know how to detect it, and I know the way to handle it. the problem is that it is not reasonable to check before every line if the server logged me out. this is what I can do:
ChromeDriver driver = new ChromeDriver();
driver.get(url);
Connect(driver, loginData);
if(isConnected(driver) == false)
reconnect(driver, loginData);
driver.findElement(By.id("element-id")).click();
if(isConnected(driver) == false)
reconnect(driver, loginData);
...
But checking if I need to reconnect every line is not a good solution.
I thought about making a thread that checks all the time if I disconnected but I don't know how to pause the main thread until I reconnect to the server when I find out I disconnected
You can have a solution similar to your own, but instead of creating your own wrapper to ChromeDriver, you can use EventFiringWebDriver for that.
you can run the check inside a while loop in a side thread, and if the server disconnects you, stop the main thread. after you reconnect, restart it again.
The website logging you out seems to be time out. As I guess, you are testing in a non-production environment, please look for how to set the time_out = 0 (no-expire).
Thread solutions would be too clumsy and a single non synchronous miss can produce undetectable erroneous results.
I solved it by wrapping ChromeDriver with a class of my own that checks before every operation if a disconnect has detected. if anyone has a better solution I would like to hear. This is my solution:
public java.util.List<WebElement> findElements(By by) throws disconnectException {
if(keepLogin) {
if(checkConnectionOver()) {
throw new disconnectException();
}
}
return driver.findElements(by);
}
public WebElement findElement(By by) throws disconnectException {
if(keepLogin) {
if(checkConnectionOver()) {
throw new disconnectException();
}
}
return driver.findElement(by);
}
public Object executeScript(String script, Object... args) throws disconnectException {
if(keepLogin) {
if(checkConnectionOver()) {
throw new disconnectException();
}
}
return driver.executeScript(script, args);
}
public void get(String url) {
driver.get(url);
}
public String getCurrentUrl() {
return driver.getCurrentUrl();
}
I'm working on a BDD project.
Sometimes the tests go too fast for the developers to see what is happening when they run them.
At the moment I'm solving it placing something like
Thread.sleep(humanWaitTime)
before each method but it defeats the purpose of writing efficient code.
Is there any way to set this globally so that it can easily be taken out when doing a regression test and not clutter my code?
Thank you!
You can use WebDriverEventListener and fake wait for not existing element,
you should:
create class: public class CustomDriverListener implements
WebDriverEventListener and implement all methods
in this class add next method:
private void fakeWaiter(WebDriver driver) {
WebDriverWait wait = new WebDriverWait(driver, 20);
try {
wait.until(listenerDriver -> listenerDriver.findElement(By.xpath("//[.='it'sFakeElement']")));
} catch (org.openqa.selenium.TimeoutException e) {
//ignore it
}
}
add invocation of this method to methods that you need, like:
#Override
public void afterFindBy(By by, WebElement element, WebDriver driver) {
fakeWaiter(driver);
}
#Override
public void afterClickOn(WebElement element, WebDriver driver) {
fakeWaiter(driver);
}
#Override
public void afterChangeValueOf(WebElement element, WebDriver driver, CharSequence[] keysToSend) {
fakeWaiter(driver);
}
#Override
public void afterScript(String script, WebDriver driver) {
fakeWaiter(driver);
}
Create EventFiringWebDriver object and register your
CustomDriverListener:
WebDriver webDriver = new ChromeDriver();
EventFiringWebDriver driver = new EventFiringWebDriver(webDriver);
driver.register(new CustomDriverListener());
Now if you use "driver" in your tests all operations will be slower(depend on timer in fakeWaiter method)
P.S. sorry for bad formatting =(
You can probably use Implicit wait,
driver.manage().timeouts().implicitlyWait(TimeOut, TimeUnit.SECONDS);
Lets say on top of your code block, you write:-
driver.manage().timeouts().implicitlyWait(15, TimeUnit.SECONDS);
Then, before each line of your code, the webdriver instance will wait for 15 seconds, you don't have to give wait times after each statement.
The implicit wait will tell to the web driver to wait for certain amount of time before it throws a "No Such Element Exception". The default setting is 0. Once we set the time, web driver will wait for that time before throwing an exception.
I would like to implement a custom wait method which should wait till a loading popup is visible.
This loading popup has its own id = "wait". I use this custom expectedConditions (from Stackoverflow) to check it:
public static ExpectedCondition<Boolean> absenceOfElementLocated(
final WebElement element) {
return new ExpectedCondition<Boolean>() {
#Override
public Boolean apply(WebDriver driver) {
try {
element.isDisplayed();
return false;
} catch (NoSuchElementException e) {
return true;
} catch (StaleElementReferenceException e) {
return true;
}
}
#Override
public String toString() {
return "element to not being present: " + element.getText();
}
};
}
My script pass on when the loading still visible and I do not know why.
Thanks!
Use ExpectedConditions#invisibilityOfElementLocated(By locator)
You can also use negation -> ExpectedConditions#not(ExpectedCondition condition)
A basic example:
Go to this page: Primefaces - dropdown
There is Submit button on this page, if you click on this button, then Selected message will appear on the screen, then this message will dissapear after a few seconds.
So we will wait in our code for the following events:
the button appears and is clickeable (it cannot be clicked until it is not clickeable)
the message appears and is visible
the message disappears an is not visible
WebDriver driver = new ChromeDriver();
try {
driver.get("https://www.primefaces.org/showcase/ui/ajax/dropdown.xhtml");
final By buttonSubmit = By.xpath("//button[ *[ text() = 'Submit' ]]");
final By message = By.xpath("//span[ text() = 'Selected' ]");
WebDriverWait wait = new WebDriverWait(driver, 50);
long time = System.currentTimeMillis();
wait.until(ExpectedConditions.elementToBeClickable(buttonSubmit)).click();
System.out.println(String.format("Button clicked after %d miliseconds", System.currentTimeMillis() - time));
wait.until(ExpectedConditions.visibilityOfElementLocated(message));
System.out.println(String.format("The message appeared after %d miliseconds", System.currentTimeMillis() - time));
// wait.until(ExpectedConditions.invisibilityOfElementLocated(message));
wait.until(ExpectedConditions.not(ExpectedConditions.visibilityOfElementLocated(message)));
System.out.println(String.format("The message dissapeared after %d miliseconds", System.currentTimeMillis() - time));
} finally {
driver.quit();
}
And a result is:
Starting ChromeDriver 2.33.506120 (e3e53437346286c0bc2d2dc9aa4915ba81d9023f) on port 15827
.....
.....
.....
Button clicked after 153 miliseconds
The message appeared after 791 miliseconds
The message dissapeared after 6924 miliseconds
It's hard to tell why your code isn't working without more of the code. You do have some logic errors in your custom wait but you don't need that custom wait because ExpectedConditions already has visibility and invisibility covered.
Use this to wait for the popup to appear
new WebDriverWait(driver, 10).until(ExpectedConditions.visibilityOfElementLocated(By.id("wait")));
Use this to wait for the popup to disappear
new WebDriverWait(driver, 10).until(ExpectedConditions.invisibilityOfElementLocated(By.id("wait")));
There are times when a popup is just a container for dynamically loaded content. In these cases, you might wait for the frame of the popup to appear but the contents of the frame are not quite loaded yet so if you try to interact with them, you will get errors. In those cases you will need to wait for an element inside the container to be visible.
Same thing for when a dialog is closing. I've had experiences where I've waited for the dialog container to close but the grey overlay is still up blocking clicks, etc. In those cases I had to wait for the overlay to become invisible.
I would suggest that you spend some time familiarizing yourself with the available methods of ExpectedConditions and save yourself having to write custom waits for things that already exist and don't need to be debugged/tested.
I have an issue when clicking on a button with Selenium 2.0b3 Java API with FirefoxDriver. Clicking on the button sends a form to the webserver and then browser goes to a new page as a result of the form submission.
When clicking on an element with element.click(), selenium is waiting for the browser to complete its operations. The browser waits until the page load is finished. But, sometimes the page load takes an enormous amount of time due to some advertisement requests.
How to work around the synchronisation between element.click() and the page load?
EDIT:
As explained in the WebElement javadoc:
Click this element. If this causes a
new page to load, this method will
block until the page has loaded.
Thanks
Try the beta feature only for Firefox listed in the last section of the firefoxdriver wiki page http://code.google.com/p/selenium/wiki/FirefoxDriver
You will need at least version 2.9, I recommend going with the latest 2.18 (2.0b3 is nearly a year old now!)
driver.get() is actually supposed to block until the page has finished loading. However sometimes it doesn't for example if JavaScript continues to load after the main HTML has loaded. In this case you'll sometimes get problems with clicking elements which have not appeared yet. You can either use WebDriverWait() to wait for the element to appear or increase the implicit wait time with:
driver.manage().timeouts().implicitlyWait(X, TimeUnit.SECONDS);
Here is the equivalent using WebDriverWait:
public void waitAndClick(WebDriver driver, By by) {
WebDriverWait wait = new WebDriverWait(driver, 10000);
Function<WebDriver, Boolean> waitForElement = new waitForElement(by);
wait.until(waitForElement);
Actions builder = new Actions(driver);
builder.click(driver.findElement(by)).perform();
}
And the waitForElement class:
public class waitForElement implements Function<WebDriver, Boolean> {
private final By by;
private String text = null;
public waitForElement(By by) {
this.by = by;
}
public waitForElement(By by, String text) {
this.by = by;
this.text = text;
}
#Override
public Boolean apply(WebDriver from) {
if (this.text != null) {
for (WebElement e : from.findElements(this.by)) {
if (e.getText().equals(this.text)) {
return Boolean.TRUE;
}
}
return Boolean.FALSE;
} else {
try {
from.findElement(this.by);
} catch (Exception e) {
return Boolean.FALSE;
}
return Boolean.TRUE;
}
}
}
This is completely untested, but I thought I'd throw it out there for you. I thought that maybe you could work around it by building a custom action.
protected static void maybeAsyncClick(WebElement element, WebDriver driver)
{
Actions builder = new Actions(driver);
Action newClick = builder.moveToElement(element)
.click()
.build();
newClick.perform();
}