WebDriver wait until this or that element is found - selenium-webdriver

In one of the application workflows I have more than 10 pages to navigate.
I have to keep clicking on the 'Next' button continuously - it makes an AJAX call to re-load new content and 'Next' button will also be reloaded.
The number of pages to navigate is not always 10. It might be anything from 10-100.
My test will be complete whenever there is a webelement found with the id 'testcomplete'.
So Currently i use ExpectedConditions()
WebDriverWait wait = new WebDriverWait(driver, 30);
//Keep clicking next
while(isNextPresent()){
NextButton.click();
}
//testcomplete reached here
System.out.println("test complete");
private boolean isNextPresent(){
try{
WebElement element = wait.until(ExpectedConditions.visibilityOf(NextButton));
return true;
}catch(Exception e){
//
}
return false;
}
Currently my code works fine. But i am trying to improve it. I hate the unnecessary wait of 30 seconds when the element with the id 'testcomplete' is present. Because that time 'NextButton' will not be present.
How can I improve this isNextPresent function? Ie, to return false immediately when there is 'testcomplete' instead of waiting for 30 seconds?
Note: I have tagged protractor as well because I also have a similar requirement in protractor.

You can combine the conditions of both elements and take an action depending on the fact which one first returns true for 'visibilityOf(myElement)'. Maybe something like this in pseudo (sorry, no IDE around):
loop(i < 30){
// wait NextBtn for 1 sec, if true click and break
// wait TestCopmlete for 1 sec
}

Use EC.or(), a la:
wait.until(ExpectedConditions.or(
ExpectedConditions.visibilityOf(NextButton),
ExpectedConditions.visibilityOf(element(by.id('testcomplete')))
));
Then after this comes back, expect the desired state:
expect(NextButton.isDisplayed()).toBeTruthy();

Related

Clarification on how Codename One UITimer works

I need a clarification about the Codename One UITimer.
For example, if I want to execute the same code every two seconds, a code like UITimer.timer(2000, true, () -> { do something; }); works until the user stays in the current Form? Is that right?
If I want to execute the same code every two seconds regardless the shown Form, have I to use something different from UITimer, like a custom separate thread? For example the following code?
Form hi = new Form("Hi World", BoxLayout.y());
hi.add(new Label("Hi World"));
hi.show();
EasyThread.start("MyTimer").run(() -> {
boolean executeMe = true;
while (executeMe) {
Log.p("Do something every two seconds...");
try {
Thread.sleep(2000);
} catch (InterruptedException ex) {
Log.p("Stopping the EasyThread \"MyTimer\" because an exception");
Log.e(ex);
executeMe = false;
}
}
});
Moreover, if I execute this example code, the first logged line is:
[MyTimer] 0:0:0,59 - Codename One revisions: 8b451ecb7bfbe60baf91006441e7d7d9c46afe09
Why is that line logged by my custom thread instead of by the EDT?
Yes, UITimer is an animation associated with the current Form. It doesn't draw anything but uses the builtin animation mechanism which runs on the EDT. Notice that if you leave a form and return to it the timer will continue e.g.:
Opened form at 0 time and set a timer for 15 seconds
Went to different form at 7 seconds
Returned to original after 30 seconds - the timer will fire immediately on return
You can also use a regular Timer or Thread. However, for your specific code EasyThread doesn't provide a benefit over a regular thread since it runs in an infinite loop. The benefit of EasyThread is in it's job processing ability.
Notice that you would need to use callSerially to return to the EDT when working with such timers/threads.

Element ... is not clickable at point (35, 37) [duplicate]

I am trying to make some tests using selenium based Katalon Studio. In one of my tests I have to write inside a textarea. The problem is that I get the following error:
...Element MyElement is not clickable at point (x, y)... Other element would receive the click...
In fact my element is place inside some other diva that might hide it but how can I make the click event hit my textarea?
Element ... is not clickable at point (x, y). Other element would receive the click" can be caused for different factors. You can address them by either of the following procedures:
Element not getting clicked due to JavaScript or AJAX calls present
Try to use Actions Class:
WebElement element = driver.findElement(By.id("id1"));
Actions actions = new Actions(driver);
actions.moveToElement(element).click().build().perform();
Element not getting clicked as it is not within Viewport
Try to use JavascriptExecutor to bring the element within Viewport:
JavascriptExecutor jse1 = (JavascriptExecutor)driver;
jse1.executeScript("scroll(250, 0)"); // if the element is on top.
jse1.executeScript("scroll(0, 250)"); // if the element is at bottom.
Or
WebElement myelement = driver.findElement(By.id("id1"));
JavascriptExecutor jse2 = (JavascriptExecutor)driver;
jse2.executeScript("arguments[0].scrollIntoView()", myelement);
The page is getting refreshed before the element gets clickable.
In this case induce some wait.
Element is present in the DOM but not clickable.
In this case add some ExplicitWait for the element to be clickable.
WebDriverWait wait2 = new WebDriverWait(driver, 10);
wait2.until(ExpectedConditions.elementToBeClickable(By.id("id1")));
Element is present but having temporary Overlay.
In this case induce ExplicitWait with ExpectedConditions set to invisibilityOfElementLocated for the Overlay to be invisible.
WebDriverWait wait3 = new WebDriverWait(driver, 10);
wait3.until(ExpectedConditions.invisibilityOfElementLocated(By.xpath("ele_to_inv")));
Element is present but having permanent Overlay.
Use JavascriptExecutor to send the click directly on the element.
WebElement ele = driver.findElement(By.xpath("element_xpath"));
JavascriptExecutor executor = (JavascriptExecutor)driver;
executor.executeScript("arguments[0].click();", ele);
I assume, you've checked already that there is no any other component overlapping here (transparent advertisement-iframes or some other component of the DOM => seen quite often such things in input/textfield elements) and, when manually (slowly) stepping your code, it's working smoothly, then ajax calls might cause this behaviour.
To avoid thread.sleep, try sticking with EventFiringWebDriver and register a handle to it.
(Depending on your application's techstack you may work it for Angular, JQuery or wicket in the handler, thus requiring different implementations)
(Btw: This approach also got me rid of "StaleElementException" stuff lots of times)
see:
org.openqa.selenium.support.events.EventFiringWebDriver
org.openqa.selenium.support.events.WebDriverEventListener
driveme = new ChromeDriver();
driver = new EventFiringWebDriver(driveme);
ActivityCapture handle=new ActivityCapture();
driver.register(handle);
=> ActivityCapture implements WebDriverEventListener
e.g. javascriptExecutor to deal with Ajax calls in a wicket/dojo techstack
#Override
public void beforeClickOn(WebElement arg0, WebDriver event1) {
try {
System.out.println("After click "+arg0.toString());
//System.out.println("Start afterClickOn - timestamp: System.currentTimeMillis(): " + System.currentTimeMillis());
JavascriptExecutor executor = (JavascriptExecutor) event1;
StringBuffer javaScript = new StringBuffer();
javaScript.append("for (var c in Wicket.channelManager.channels) {");
javaScript.append(" if (Wicket.channelManager.channels[c].busy) {");
javaScript.append(" return true;");
javaScript.append(" }");
;
;
;
javaScript.append("}");
javaScript.append("return false;");
//Boolean result = (Boolean) executor.executeScript(javaScript.toString());
WebDriverWait wait = new WebDriverWait(event1, 20);
wait.until(new ExpectedCondition<Boolean>() {
public Boolean apply(WebDriver driver) {
return !(Boolean) executor.executeScript(javaScript.toString());
}
});
//System.out.println("End afterClickOn - timestamp: System.currentTimeMillis(): " + System.currentTimeMillis());
} catch (Exception ex) {
//ex.printStackTrace();
}
}
As #DebanjanB said, your button (or another element) could be temporarily covered by another element, but you can wait and click it even if you don't know which element is covering the button.
To do this, you can define your own ExpectedCondition with the click action:
public class SuccessfulClick implements ExpectedCondition<Boolean> {
private WebElement element;
public SuccessfulClick(WebElement element) { //WebElement element
this.element = element;
}
#Override
public Boolean apply(WebDriver driver) {
try {
element.click();
return true;
} catch (ElementClickInterceptedException | StaleElementReferenceException | NoSuchElementException e) {
return false;
}
}
}
and then use this:
WebDriverWait wait10 = new WebDriverWait(driver, 10);
wait10.until(elementToBeClickable(btn));
wait10.until(new SuccessfulClick(btn));
Try Thread.Sleep()
Implicit - Thread.Sleep()
So this isn’t actually a feature of Selenium WebDriver, it’s a common feature in most programming languages though.
But none of that matter.
Thread.Sleep() does exactly what you think it does, it’s sleeps the thread. So when your program runs, in the majority of your cases that program will be some automated checks, they are running on a thread.
So when we call Thread.Sleep we are instructing our program to do absolutely nothing for a period of time, just sleep.
It doesn’t matter what our application under test is up to, we don’t care, our checks are having a nap time!
Depressingly though, it’s fairly common to see a few instances of Thread.Sleep() in Selenium WebDriver GUI check frameworks.
What tends to happen is a script will be failing or failing sporadically, and someone runs it locally and realises there is a race, that sometimes WedDriver is losing. It could be that an application sometimes takes longer to load, perhaps when it has more data, so to fix it they tell WebDriver to take a nap, to ensure that the application is loaded before the check continues.
Thread.sleep(5000);
The value provided is in milliseconds, so this code would sleep the check for 5 seconds.
I was having this problem, because I had clicked into a menu option that expanded, changing the size of the scrollable area, and the position of the other items. So I just had my program click back on the next level up of the menu, then forward again, to the level of the menu I was trying to access. It put the menu back to the original positioning so this "click intercepted" error would no longer happen.
The error didn't happen every time I clicked an expandable menu, only when the expandable menu option was already all the way at the bottom of its scrollable area.

How do I get Selenium to wait for a page to load fully before executing the click() command

My problem:
I am running phpunit with Selenium to test a website on a server that is on the other side of the world. So, there is a delay of a few seconds for things like clicking on a tab or a new page. I start Selenium Server with Chromedriver.
eg.
public function setUp()
{
$this->setHost('localhost'); // Set the hostname for the connection to the Selenium server.
$this->setPort(4444); // set port # for connection to selenium server
$this->setBrowser('chrome'); // set the browser to be used
$this->setBrowserUrl('https://www.*.com'); // set base URL for tests
$this->prepareSession()->currentWindow()->maximize(); // Maximize the window when the test starts
$this->timeouts()->implicitWait(30000); // Wait up to 30 seconds for all elements to appear
}
public function testLoginToeSeaCare(){
$this->timeouts()->implicitWait(10000); // Wait up to 10 seconds for all elements to appear
$url = 'https://www.*.com';
$loginName = 'Ned';
$loginPassword = 'Flanders';
$this->url($url); // Load this url
$this->timeouts()->implicitWait(30000); // Wait up to 30 seconds for all elements to appear
$username = $this->byId('username'); // Search page for input that has an id = 'username' and assign it to $username
$password = $this->byId('password'); // Search page for input that has an id = 'password' and assign it to $password
$this->byId('username')->value($loginName); // Enter the $loginName text in username field
$this->byId('password')->value($loginPassword); // Enter the $loginPassword in password field
$this->byCssSelector('form')->submit(); // submit the form
$tab1Link = $this->byLinkText("Tab1"); // Search for the textlink Tab1
$this->assertEquals('Tab1', $tab1Link->text()); // assert tab text is present
$this->timeouts()->implicitWait(10000); // Wait up to 10 seconds for all elements to appear
$tab2Link = $this->byLinkText("Tab2");
$tab2Link->click(); // Click 'Tab2' tab
}
There is an error reported when the above is run and I capture it in an xml file:
********::testSearch PHPUnit_Extensions_Selenium2TestCase_WebDriverException: unknown error: Element ... is not clickable at point (430, 139). Other element would receive the click: (Session info: chrome=57.0.2987.133) (Driver info: chromedriver=2.29.461591 (62ebf098771772160f391d75e589dc567915b233)
What I am trying to do is to wait for the DOM to be completely loaded before clicking on a button. But I get the above error intermittently. Does anyone know a way around this?? Its driving me nuts!!
Try the Explicit Waits.
"An explicit wait is the code you define to wait for a certain condition to occur before proceeding further in the code. There are some convenience methods provided that help you write code that will wait only as long as required. WebDriverWait in combination with ExpectedCondition is one way this can be accomplished."
For example,
// Wait for the page title to be 'My Page'.
// Default wait (= 30 sec)
$driver->wait()->until(WebDriverExpectedCondition::titleIs('My Page'));
// Wait for at most 10s and retry every 500ms if it the title is not correct.
$driver->wait(10, 500)->until(WebDriverExpectedCondition::titleIs('My Page'));
There are many prepared conditions you can pass to the until() method. All of them subclass WebDriverExpectedCondition, including elementToBeClickable() (https://github.com/facebook/php-webdriver/wiki/HowTo-Wait).
I don't know if this will help you
but in java there is a method to wait for a certain item to be visible
Here is how it is written
WebDriverWait Wait=new WebDriverWait(Driver, 10);
Wait.until(ExpectedConditions.visibilityOf(Driver.findElement(By.//your element locator)));
Sorry I don't know how to write it in PHP

Are there situations where an ExplictWait is not working?

I know about the three different types of waiting you can use in Selenium. I know why Thread.Sleep and ImplicitWait are never a good choice. So I'm always using ExplicitWaits, for instance to wait till a button is clickable. However, from time to time one or two tests in a collection of hundred tests fails because the Explictwait seems to fail.
I read the very interesting article: https://bocoup.com/weblog/a-day-at-the-races
about the reason why tests can fail from time to time and Explicit wait as the solution for this intermittent failures. This made me even more convinced about using ExplictWaits.
So I wonder is there anybody who knows situations were an Explicitwait is not doing the right job.
This is my C# code for waiting till a Webelement is clickable:
public static Boolean waitElementToBeClickable(IWebDriver driver, int seconds, IWebElement webelement)
{
Boolean clickable = true;
try
{
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(seconds));
wait.Until(ExpectedConditions.ElementToBeClickable(webelement));
}
catch
{
clickable = false;
}
return clickable;
}

Behat, PhantomJS - wait for page load after clicking link?

I'm using Behat 3 and PhantomJS 2. Currently I have a scenario defined as such:
#javascript
Scenario: I visit the blog through the Blog & Events menu.
Given I am an anonymous user
And I am on the homepage
And I follow "Link Text"
Then I should be on "/path-to-page"
When I run this with Goutte it's fine. When I run this with vanilla Selenium, it's fine (it launches a browser I can see). However, when I configure Selenium to point the webdriver host to PhantomJS, it explodes on Then I should be on "/path-to-page" claiming it's still on /.
If I add the following wait step:
#javascript
Scenario: I visit the blog through the Blog & Events menu.
Given I am an anonymous user
And I am on the homepage
And I follow "Link Text"
And I wait 4 seconds
Then I should be on "/path-to-page"
Then my scenario passes in the green, all good.
Is there a way to get PhantomJS to wait for the page to load before checking the current path? I don't want to depend on arbitrary timeouts. I need a headless solution and PhantomJS seems to be pretty well supported, but if I can't do something as simple as clicking a link and verifying the page that was loaded without adding random waiting steps everywhere, I might need to re-evaluate my decision.
Try using this implicit wait in your feature context. In my experience it has helped.
/**
* #BeforeStep
*/
public function implicitlyWait($event)
{
// Set up implicit timeouts
$driver = $this->getSession()->getDriver()->getWebDriverSession();
$driver->timeouts()->implicit_wait(array("ms" => 10000));
}
I was having the same issue, and doing something like this fails because its using the state of the current url:
$this->getSession()->wait(10000, "document.readyState === 'complete'");
So my workaround for this was adding a variable to the page every time a step is done. When I link is clicked, the variable will no long exist, this will guarantee that am working with a different page.
/**
* #AfterStep
*/
public function setStepStatus()
{
$this->getSession()->evaluateScript('window.behatStepHasCompleted = true;');
}
/**
* #When /^(?:|I )wait for the page to be loaded$/
*/
public function waitForThePageToBeLoaded()
{
$this->getSession()->wait(10000, "!window.behatStepHasCompleted && document.readyState === 'complete'");
}
You can always make use of a closure function to encapsule your steps, just as mentioned in the docs. Through it, you can get your steps to run when they're ready. Let's implement a spinner function:
public function spinner($closure, $secs) {
for ($i = 0; $i <= $secs; $i++) {
try {
$closure();
return;
}
catch (Exception $e) {
if ($i == $secs) {
throw $e;
}
}
sleep(1);
}
}
What we're doing here is wait for a number of seconds for the closure function to run successfully. When the time's run out, throw an exception, for we want to know when something's not behaving correctly.
Now let's wrap your function to assert you're in the right page within the spinner:
public function iShouldBeOnPage($wantedUrl) {
$this->spinner(function() use($wantedUrl) {
$currentUrl = $this->getSession()->getCurrentUrl();
if ($currentUrl == $wantedUrl) {
return;
}
else {
throw new Exception("url is $currentUrl, not $wantedUrl");
}
}, 30);
What we're doing here is wait up to 30 seconds to be on the url we want to be after clicking the button. It will not wait for 30 secs, but for as many secs we need until current url is the url we need to be at. Applying it in your function within the *Context.php will result in it being applied in every step you call it within your Gherkin files.

Resources