Wait commands doesn't wait enough time

Not really, no. The problem here is:

You have not described clearly what your website is meant to be doing. It’s possible to infer what it might be doing from some of what you said, but I would be as likely to hinder you as help you. Please, write out a clear paragraph describing how the site is meant to behave.

With that said, I’m guessing you don’t need the loop. Clicking TO_2 causes a page (or section of a page) to load wherein TO_1 resides. Once TO_1 is present then your test (not shown) is meant to proceed - correct?

Statements:

FailureHandling works.
waitFor* APIs work.

Your logic though is still under question.

Follow the advice I gave here, then perhaps we can help you:

1 Like

Thanks Taylor! would you give me some simple example how to use loop with try catch.

Hi Russ,
My script previously is simple search which gives me list of the results (10 records per 1 page). There are 2 kind of results - highlighted in green and red, I need to search for first red record and click it to open details.
My loop firstly is checking first if red record is displayed on the list of results(TestObject_1’), if not it’s clicking next page button (TestObject_2) and it works if I use delay command. I would like to use wait command to check if TestObject_2 is displayed on the page (it’s displaying when new page finished loading) to save time of execution because sometimes red record is presenting on 10th page and loading each page with results takes from 10 to even 40 seconds.
I hope it’s more clear now.

Hi Robert,
I tried to reproduce your case. As far a I can see with your loading scenario, you can optimize your loop, because if your result is on the first page, you wait only 5 seconds, which might not be enought. And later, when you wait until your page is fully loaded, you again wait 5 seconds. Please see the following :

// wait for the first result page to be fully loaded
WebUI.waitForElementVisible(findTestObject(‘next’), 40, FailureHandling.OPTIONAL)

// search for your element with shorter failed timeout (as we already ensure page is loaded)
while (WebUI.verifyElementPresent(findTestObject(‘objetRecherche’), 1, FailureHandling.OPTIONAL) != true) {

// if not, click next
WebUI.click(findTestObject(‘next’))

// wait for the page to be fully loaded
WebUI.waitForElementVisible(findTestObject(‘next’), 40, FailureHandling.OPTIONAL)

// add this extra comment so your logs will look nicer (for the next check loop result)
WebUI.comment(‘next while’)
}

WebUI.click(findTestObject(‘objetRecherche’))

Also, please pay intention to the extra comment at the end of the while loop : this will help you debug your script.

Update:

Summary

Please ignore the following message:

Hi @Robert_C,
Try seting Default timeout in Project Setting to 40 seconds.
If you set 5 seconds in waitElementPresent() but 40 seconds for default timeout then it will be waited up to 5 seconds. However, if 5 seconds is set in waitElementPresent() but 1 second set for default timeout setting, it will be waited 1 second maximum

Are you saying that setting a value higher than the default value will never be taken into account ? Isn’t it a bug ?

Here is my solution - I’ve created new object for spinner which is displaying during searching (TestObject_3) so now my loop looks like that:

while (WebUI.verifyElementPresent(findTestObject(‘TestObject_1’), 5, FailureHandling.OPTIONAL) != true) {

WebUI.click(findTestObject(‘TestObject_2’))

WebUI.waitForElementNotPresent(findTestObject(‘TestObject_3’), 40, FailureHandling.CONTINUE_ON_FAILURE)

}
and it’s waiting until this spinner disappear to continue looping.

Thanks for all your suggestions!

Sounds like you have a working solution, but just wanted to toss an idea to solve this more generically, as I’ve grappled with similar challenges. What it sounds like is happening is that most or all of your page has loaded, but there’s some AJAX going on in the background, and thus your web developer puts up a ‘spinner’ to prevent user interaction with the page until it’s complete.

This would explain why your wait conditions end after ~5 seconds, even though there’s a spinner. As far as the DOM is concerned, your elements are available and ready to be interacted with.

First, check if your page is jQuery enabled by executing the following in the browser console:

!!window.jQuery

If you get ‘true’, try using a custom wait condition like the following one:

new WebDriverWait(driver, 300, 100).until(new ExpectedCondition<Boolean>() {
						@Override
						public Boolean apply(WebDriver d) {
							JavascriptExecutor js = (JavascriptExecutor)d;
							return (Boolean)js.executeScript(
									"return !!window.jQuery && window.jQuery.active == 0");
						}
					});

This will work, spinner or no spinner, for any application that makes heavy use of AJAX.

4 Likes

Default timeout will be used only if no timeout is set in waitElementPresent().

I’m sorry for misunderstanding default timeout. Confirm that if we don’t set a timeout for waitElementPresent, the default timeout will be taken.

1 Like

Hi Brandon, Could you please tell … How to use this in Katalon and the imports required --> Using @Keyword.

Thanks.

Sure:

package util

import org.openqa.selenium.JavascriptExecutor
import org.openqa.selenium.WebDriver
import org.openqa.selenium.support.ui.ExpectedCondition
import org.openqa.selenium.support.ui.WebDriverWait

import com.kms.katalon.core.annotation.Keyword
import com.kms.katalon.core.webui.driver.DriverFactory

public class Util {

	@Keyword
	public void waitUntilJQueryReady() {
		new WebDriverWait(DriverFactory.getWebDriver(), 300, 100).until(new ExpectedCondition<Boolean>() {
					@Override
					public Boolean apply(WebDriver d) {
						JavascriptExecutor js = (JavascriptExecutor)d;
						return (Boolean)js.executeScript(
								"return !!window.jQuery && window.jQuery.active == 0");
					}
				});
	}
}

Usage would just be:

CustomKeywords.‘util.Util.waitUntilJQueryReady’()

1 Like

Thanks a ton Brandon.:slight_smile:

I have quick doubt, Hope you don’t mind my ignorance …

a. How is it different from built in keyword WebUI.waitForJQueryLoad(10)
b. what does 300, 100 mean in new WebDriverWait(DriverFactory.getWebDriver(), 300, 100).

While we’re waiting for Brandon to surface…

The jQuery.active property is a counter. Each time jQuery starts an asynchronous process, it increments the counter. Each time a process completes (regardless of a success status) it decrements the counter. The code is waiting for the the counter to reach zero, meaning, “it’s finished and ready”.

I don’t know the detail behind waitForJQueryLoad but it certainly doesn’t do what Brandon has given you.

The selenium APIs are documented here:

Thanks Russ :+1:

You can check the source for the WebUI implementation of this here: https://github.com/katalon-studio/katalon-studio-testing-framework/blob/0e936ccef5035367f00ffa262e8515cbd533ea9c/Include/scripts/groovy/com/kms/katalon/core/webui/keyword/builtin/WaitForJQueryLoadKeyword.groovy

Russ has already linked you the WebDriverWait documentation, but to reiterate, the constructor that I used is:

So the 300 is the timeout in seconds (5 minutes) and the 100 is the polling frequency (aka the sleep time between checking the active jQuery count) in milliseconds.

2 Likes

Thanks Brandon :slightly_smiling_face:

In case if I use this CustomKeywords.‘util.Util.waitUntilJQueryReady’() for non-Jqery page, the application is running in an infinite loop.

Run up the website in a browser (by hand) and open the devtools console. Type:

jQuery.active

Type it again and again and again…

If the value displayed is always greater than 0, there is a bug in the application page. Tell the devlopers you found a bug making the page untestable.

If it does reach zero, then you used Brandon’s code incorrectly. It’s hard to say what you did wrong from here.

1 Like

It is not running in an infinite loop, it will run for 5 minutes (remember the 300 argument?):

return !!window.jQuery && window.jQuery.active == 0

For a non-jQuery application, this will always return false. Thus if you call this for a non-jQuery application, it will wait all the way up to the given timeout.

You can remove the “!!window.jQuery” argument if you want, but if you then run this on a non-jQuery app, instead of waiting the full duration of the timeout, you will get an error:

org.openqa.selenium.WebDriverException: unknown error: Cannot read property 'active' of undefined

So it’s up to you.

1 Like