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?
Related
I read about how beneficial in using Implicit/Explicit waits, and decided to abandon Thread.sleep() in my code. However, the result is opposite. Using Thread.sleep(), I can actually locate the element, while Implicit/Explicit waits result in the ElementClickInterceptedException: element click intercepted: [duplicate] error for the same element.
The element I am trying to simulate a click on is an "I AGREE" button located in a dialog box. The following is the DOM for the button which I am trying to click.
And the following is the code to simulate the click.
Using Implicit Wait
driver.manage().timeouts().implicitlyWait(120, TimeUnit.SECONDS);
driver.findElement(By.xpath("/html/body/div[1]/div/div/div[4]/a")).click();
Result : ElementClickInterceptedException: element click intercepted: [duplicate] error
Using Explicit Wait
WebDriverWait wait = new WebDriverWait(driver, 60);
WebElement I_Agree;
I_Agree = wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("/html/body/div[1]/div/div/div[4]/a")));
I_Agree.click();
Result : ElementClickInterceptedException: element click intercepted: [duplicate] error
Using Thread.sleep()
Thread.sleep(20000);
driver.findElement(By.xpath("/html/body/div[1]/div/div/div[4]/a")).click();
Result : Element is found and click can be executed.
Hope to have advice on any mistakes I may have done.
implicitlyWait waits for the element existence.
So in case of
driver.findElement(By.xpath("/html/body/div[1]/div/div/div[4]/a")).click();
Selenium will try clicking that element immediately after the goal element appears.
In many cases the element can still be not clickable so utilizing the implicitlyWait may often cause exceptions.
Using ExpectedConditions.visibilityOfElementLocated will mostly work better, but still there are several situations this will not work.
In some cases the goal element can be out of the visible screen. In this case you will have to scroll to the goal element in order to bring it into the visible screen and then click it properly.
In some other cases during the page rendering Selenium will indicate element as visible and clickable while actually some other element may be overlapping on the goal element so clicking on it will cause the wrong element accepting the click. However if you give some more wait the page rendering process will complete and now you can click the goal element properly.
This is seems to be your case.
In most cases the overlapping element will be some kind of spinner element.
If so you should add the ExpectedConditions.invisibilityOfElementLocated condition to wait until the spinner / other overlapping element is disappeared.
To give more precise answer we need to see the specific site you are working on and the actual test flow you are doing.
You can see more about the ElementClickInterceptedException here, here, here and at more resources.
UPD
From your comments I see you did not actually understand. Both implicitly and explicitly waits are pooling the DOM to find element matching the passed condition. In both cases at the moment the condition is met Selenium will immediately stop waiting and polling, it will return an element (or Boolean true in some cases) and continue to the next command.
Implicitly wait is waiting for element presence. So in many cases the element itself is still not finally rendered and may still not be clickable or visible but it is already present, so in your case
driver.findElement(By.xpath("/html/body/div[1]/div/div/div[4]/a"))
may return the element that is still not ready to be clicked on.
This is why it is preferred to use explicit waits like ExpectedConditions.visibilityOfElementLocated since in this case Selenium will wait polling the DOM until it finds the desired element to be visible, this is much more mature state of the element on the page and it can normally be clicked on this point.
However, sometimes it can be some spinner etc. on that element. This is some external problem. So in this case we need to add ExpectedConditions.invisibilityOfElementLocated to wait until that spinner is disappeared.
There are more cases explicit wait will not be enough to be applied on the element itself. Sometimes you will have to scroll the desired element into the view, sometimes you will even need to use JavaScript click etc.
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.
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.
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.