I have 3 select menus depending on each other. Selenium enables you to select a value of a select item but since the menus depend on each other there is a small waiting time between each one. You can have a thread sleeping for one second the time it loads but I want to know how to make the waiting dynamic. The WebDriverWait enables you to wait for an element but not a value of the element.
The secret to dynamic waits is the ExpectedConditions class. Used properly, you can get WebDriverWait to work with quite a large variety of conditions.
Without seeing the HTML of your page, I suspect you're going to need something like:
WebDriverWait wait = new WebDriverWait(driver, 10);
wait.until(ExpectedConditions
.textToBePresentInElementLocated(By.id("the-element's-id", "Value you are looking for");
You don't have to use id if it's not convenient: any of the usual locators like xpath and css will work too.
Related
I have a super-class Component, inside this class I store common ways to access elements attached to the component.
In the Component constructor, I initElements with the pagefactory
PageFactory.initElements(new AjaxElementLocatorFactory(root,10), this);
As I understand it, this will automatically keep element reference fresh, as long as the elements are annotated by the #FindBy annotation.
I have a specialized Component called SearchResultRow which extends Component.
In this component, I have all the WebElements related to a row in the search result.
What I want to do is to get the first search result and click on it. This is my code for that.
public void clickOnFirstResult() {
WebElement firstUser = wait.until(ExpectedConditions.elementToBeClickable(searchResultRoot.findElement(By.cssSelector("tbody > tr:nth-child(1)"))));
new SearchResultRow(firstUser).clickOn(SearchModel.NAME);
}
Here I wait for the element to become clickable, because it's a dynamic element that is not covered by the #FindBy annotation.
SearchModel.NAME refers to a WebElement annotated by #FindBy in the SearchResultRow component. Yet this method sometimes 10-15 % gives the error
stale element reference: element is not attached to the page document
Root cause
Stale element reference refers to web elements that were obtained before a page refresh but attempted to be used (i.e. calling click() method after said refresh.)
Solution
Wait.... Which are the best ways to wait for page reloads? One way is to use Implicit Waits. One very common way to implicitly wait some amount of time:
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
This is how it is done in Selenium Java, but there should be an equivalent method for whichever version of Selenium you are using. The question now is, what does this do? This is the way to tell the web driver to wait the given amount of time BEFORE attempting to obtain a web element. When the implicit wait time is set, it will remain set for the duration of your test session. Therefore, this is typically done at the very beginning before any tests begin to execute. More specifically, you should do it immediately after getting the web driver instance.
That said, this should not be enough. For example, what if the component become stale after initial load of a page? For that, you should use ExpectedConditions class and set an explicit wait for some condition to occur:
WebDriverWait wait = new WebDriverWait(driver, 10); // timeout of 10 seconds and polling the default value of 500 ms, or...
WebDriverWait wait = new WebDriverWait(driver, 10, 100); // timeout of 10 seconds and polling every 100 ms
Then use wait object to set your expected condition and obtain the required web element
WebElement element = wait.until(...);
You will need to pass the appropriate ExpectedConditions to the above method. Common ones to be used to avoid staleness:
WebElement element = wait.until(ExpectedConditions.elementSelectionStateToBe(...));
WebElement element = wait.until(ExpectedConditions.refreshed(...));
Lastly, you will check to see what the state of the element is before interacting with it. For example:
WebElement newElement = wait.until(ExpectedConditions.elementToBeClickable(element));
newElement.click();
In this case, element and newElement are the same object so using just wait.until(ExpectedConditions.elementToBeClickable(element)); should be enough before calling element.click(). By this point, you have established that the element is not stale and it is visible and enabled; and therefore, safe to be clicked (for instance).
It's caused by dynamic DOM.
wait.until(ExpectedConditions.elementToBeClickable(searchResultRoot.findElement(By.cssSelector("tbody > tr:nth-child(1)")))); ends when the element is found and clickable. However this occurs during the process of DOM building, so when you trying to click on this element it may disappear / change so the element you are referencing to is no more exists.
The simplest way to work with dynamic DOM pages is each time the DOM / page is reloaded / rebuilt is to give some enough delay time and only after that to deal with it's elements.
You already asked similar question and I already answered you there.
There is an element on page that appears every 2-5 min. I want to click this element as fast as possible when it appears. I think I should use sth like this:
new WebDriverWait(driver, Duration.ofSeconds(10000)).until(ExpectedConditions.elementToBeClickable(By.xpath("xpath"))).click();
And repeat it in infinite loop. But I need to wait this element asynchronously (in current thread I use this WebDriver for other actions), and I want to know how can I correctly do this. I read that WebDriver is not thread-safe, so it's incorrect to create new thread with infinit loop.
I consider it would be ideal to create some kind of callback for appearing of needed element, is it possible?
I'm fairly new to Selenium and I'm writing a test for a web app using it. In doing this, I'm using assertions to make sure the web app is working correctly. For a few of these assertions, I'm asserting on a web element that has a numeric value in which the expected number is known. The problem is when a change is made that changes this numeric value the change happens gradually based on how fast the internet connection is. Up to this point have resorted to using sleep's to wait for the element to finish refreshing before I use assertions but I would like to make it so this wait is no longer than the time it takes for the element to stop refreshing and thus not have to include sleep's that are either too short or too long.
You should try this:
WebDriverWait wait = new WebDriverWait(webDriver, timeoutInSeconds);
wait.until(ExpectedConditions.visibilityOfElementLocated(<specific locator of element>));
Sleep is not a good option because you wait always expected the amount of time.
In the approach presented above you always wait for the visibility of a specific element. When an element is visible your test steps will go forward. There is no extra wait time which you got with implicit sleep
Avoid using sleep and replace it with an implicit wait or use expected condition if applicable. below is c# code for it
int time =10; // set maximum time required for operation
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(time));
wait.Until(SeleniumExtras.WaitHelpers.ExpectedConditions.ElementIsVisible(By.XPath(""))); //replace "" with your desired xpath
The above code will wait for max 10 seconds for an element to be visible. but if it appears earlier then it will jump to next process so you need not have to wait for a specific time. Also, there are other expected conditions available like ElementExists, ElementToBeClickable etc. I will leave it to you to explore the appropriate option for yourself
if you wan t to use implicit wait specifically use below code
driver.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(50));
I am a new bee for the automation and I have used the JUnit to develop the automation test script on using selenium webdriver on here my requirements
I have developed the automation test script. For some actions on my code, I want some time to execute the next command like find the element and load the pages so I use the Thread.sleep(). So now I found the info about using the Thread.sleep is a not good for the making test script
So my question is Can anyone say then how I give the dynamic wait time to my code My code is as below,
System.setProperty("webdriver.chrome.driver", "//path of the chrome driver");
driver = new ChromeDriver();
driver.get("https://url for my org");
Thread.sleep(5000); //to load the login page of my Org
driver.findElement(By.xpath("my login xpath")).click();
Thread.sleep(1000);
driver.findElement(By.xpath("my login xpath")).sendKeys("username");
Thread.sleep(2000);
driver.findElement(By.xpath("my password xpath")).click();
Thread.sleep(1000);
driver.findElement(By.xpath("my password xpath")).sendKeys("my password");
driver.findElement(By.xpath("login button")).click();
Thread.sleep(6000); //for giving the time to login Org
I have used the different type of the wait time on my code as per my requirement.
If I go to the wait Class Can I able to achieve the same Wait time on
there?
My question is different for the getting the explicit wait is provide the constant wait time to the different places like if we define the followingly,
WebDriverWait wait = new WebDriverWait(driver, 10);
WebElement element = wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("element_xpath")));
element.click();
//for another wait
WebElement element = wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("element_xpath")));
element.sendKeys("something"); //Here it's wait time(10 seconds) is same to the after the click action wait time.
So Why I am waiting the same time for all my wait section without need? if having another way please let me know?
If I am wrong please correct me.
Thanks.
Firstly, I would very much like to advice you to use pageobjects or something like it. This is going to get you to maintenance-hell. Having said that, to solve your problem, you can use the implicit or explicit wait, whichever works best for you.
If you want to use the implicit wait, when initializing your driver, use:
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
If you want to use explicit wait, use this example and make it your own:
WebDriverWait wait = new WebDriverWait(driver, 10);
WebElement element =
wait.until(ExpectedConditions.elementToBeClickable(By.xpath("xpath")));
element.click();
In both examples, the driver will wait for a max of 10 seconds.
If you want to know the difference between the 2, check out the link and see what suits you best
http://toolsqa.com/selenium-webdriver/implicit-explicit-n-fluent-wait/
You should avoid using implicit wait due to the advice of Selenium contributors. You should also avoid mixing implicit and explicit waits as stated in the Selenium docs:
WARNING: Do not mix implicit and explicit waits. Doing so can cause unpredictable wait times.
You should instead use explicit waits, e.g. WebDriverWait. You shouldn't need a wait between entering data into fields. My general approach is to wait for a specific element to be visible on the page that indicates that a page is finished loading. You will want to pick one of the last elements to load on the page in the case where you have a long loading/dynamic section. After that element is loaded, you are free to enter text, etc. on the page at will. The only time you should need to wait again on the same page is if you trigger some dynamic behavior such as clicking a link that refreshes part of the page, making a selection from a dropdown that triggers a reload of another dropdown, etc.
Your code should look more like
driver.get("https://url for my org");
driver.findElement(By.xpath("my login xpath")).sendKeys("username");
driver.findElement(By.xpath("my password xpath")).sendKeys("my password");
driver.findElement(By.xpath("login button")).click();
// wait for element on newly loaded page and continue
You don't need a wait after navigating to a URL. Selenium will wait for the browser readyState to be complete.
You don't need to click in an element before using .sendKeys().
You don't (generally) need a wait between entering data into fields.
You should add implicit wait in your program as shown below
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
driver.get("https://url for my org");
Here Implicit waits are basically your way of telling WebDriver that it should wait 10 seconds(as mentioned in code) in cases if specified element not available on the UI (DOM), i.e. before throwing exception it will wait for 10 seconds.
Once you added implicit wait, remove all Thread.sleep(1000). It is not good practice to write Thread.sleep(1000) after every statement.
Or you can use explicit wait like
// Create object of WebDriverWait class
WebDriverWait wait=new WebDriverWait(driver,20);
// Wait till the element is not visible
WebElement element=wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("ur xpath here")));
boolean status = element.isDisplayed();
//Then perform other action on element
This waits up to 20 seconds before throwing a TimeoutException or if it finds the element will return it in 0 - 20 seconds. WebDriverWait by default calls the ExpectedCondition every 500 milliseconds until it returns successfully. A successful return is for ExpectedCondition type is Boolean return true or not null return value for all other ExpectedCondition types.
There have been questions on the difference between implicit and explicit wait in Selenium WebDriver.
What is difference between Implicit wait Vs. Explicit wait in selenium webdriver?
When to use explicit wait vs implicit wait in Selenium Webdriver?
On SeleniumHq also:
Implicit Waits
An implicit wait is to tell WebDriver to poll the DOM for a certain amount of time when trying to find an element or elements if
they are not immediately available. The default setting is 0. Once
set, the implicit wait is set for the life of the WebDriver object
instance.
But not clear what kind of wait is this, I mean would it wait till isDispalyed, isVisible or isClickable
I believe the implicit wait does not care about any of those properties (isDisplayed, isVisible or isClickable). It just waits the time you set up and checks regularly whether the element you try to select is available in your DOM. If it is not found it will lauch a timeout error.
I believe narko is right and here's some code that I think proves it.
By hiddenLocator = By.id("csi");
FirefoxDriver driver = new FirefoxDriver();
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
driver.get("http://www.google.com");
WebElement hiddenEle = driver.findElement(hiddenLocator);
WebDriverWait wait = new WebDriverWait(driver, 30);
wait.until(ExpectedConditions.presenceOfElementLocated(hiddenLocator));
System.out.println("done");
I went to google.com and found an element that was hidden
<textarea name="csi" id="csi" style="display:none"></textarea>
I set the implicit wait to 30s, set up a WebDriverWait for 30s, and then waited for the element to be present. From the presenceOfElementLocated() source
An expectation for checking that an element is present on the DOM of a page. This does not necessarily mean that the element is visible.
If implicit wait was waiting for anything other than just the presence of the element in the DOM, it would have waited for 30s... but it finished as soon as the page was loaded in the browser.
I did some research to better understand what these different functions are doing and how they are truly different. Here's what I found...
WebElement has three methods related to this question: isDisplayed(), isEnabled(), and isSelected(). From the docs...
isDisplayed() Is this element displayed or not? This method avoids the
problem of having to parse an element's "style" attribute.
isEnabled() Is the element currently enabled or not? This will
generally return true for everything but disabled input elements.
isSelected() Determine whether or not this element is selected or not.
ExpectedConditions also comes into play here with several methods. I'll just look briefly at elementToBeClickable(). From the docs...
elementToBeClickable An expectation for checking an element is visible
and enabled such that you can click it.
If you look at the source, the description is accurate. You can look at the source for the other methods, etc. if you want more info but I think this is enough to answer your question.