REALLY waiting for element to load

I’ve seen many times that the Katalon script does not REALLY waits until the page or the element is completely loaded and ready to be clickable. Doesn’t matter if I use:

      WebUI.waitForPageLoad(60)  
      WebUI.waitForElementPresent(findTestObject(....), 60)

      WebUI.waitForElementVisible(findTestObject( ..... ), 60)  

      WebUI.waitForElementClickable(findTestObject( .....), 60)  

This resulting in timeouts and errors.

I have implemented a check that is cumbersome but WORKS EVERY TIME. It shouldn’t be necessary having the above mentioned calls.
This loop REALLY DOES THE TRICK in all occasions, if I run 50 test senarios (scripts) with maybe 4 variations each so I actually run 200 scripts it is extremely irritating to get errors because of timeouts due to slow comms. And that type of errors are way too common.

for (int j = 0; j <= 120; j++) {

if (WebUI.waitForElementNotPresent(findTestObject(‘REPOSITORY/Button’), 5) == false) {

WebUI.comment(‘Button is ready. Continue.’)

WebUI.waitForElementPresent(findTestObject(‘REPOSITORY/Button’), 60)

WebUI.waitForElementVisible(findTestObject(‘REPOSITORY/Button’), 60)

WebUI.waitForElementClickable(findTestObject(‘REPOSITORY/Button’), 60)

WebUI.click(findTestObject(‘REPOSITORY/Button’))

break

} else {

WebUI.comment(‘Button is still not ready. Wait.’)

WebUI.delay(1)

}
}

This certainly can be improved in a thousand ways but it WORKS 100% as it is now. I use it for critical fields that have given me problems (often, but not only, the first field in a page), since WebUI.waitForPageLoad does not, according to my experience, completely waits for page load. The three waits above (Present, Visible, Clickable) might seem superfluous when waitForElementNotPresent has returned ‘false’ but that is not true, maybe because they give a little pause before clicking, which is the small difference needed for the above check to be rock solid and to never fail.

MY QUESTION IS: how can the above check be performed smarter.

14 Likes

Upvoted.

I would like to have the cleaner version of this functionality, too. Maybe the developers among us could help with the leaning of code. :slight_smile:

There’s something similar here:
http://forum.katalon.com/discussion/comment/16699/#Comment_16699.

Thanks Mate Mrse, for the upvote.

I will be programming the above lines in a Keyword or Method to call from the script. Basically I need 2 variations, one for click object and one for ‘send keys’ (to insert a text, better than ‘set text’ imo.

But I agree with you Mate Mrse if someone with good programming skills could come up with a solution based on the code above or based on an even better solution would be great.

Upvoted.

This is fine for a largely static web page, but for dynamic pages where javascript/ajax might be called upon to alter the dom, you may still run into timing/synchronization issues.

So please, be aware of the whole issue at hand.

FWIW, I do something very similar in custom Keyword Class/method that uses JavaScript right on the page to check if an element is ready. So your algorithm is fine but I’d advise you wrap it up into a Keyword method and use it everywhere.

Plus, prior to any of this, I have already waited for and proved everything I can think of to be ready:

URL is loaded (waitForPageLoad)
jQuery ready ($ is not undefined)
Ajax/jQuery not busy (check jQuery.active)
An HTML footer that appears on every page (check contents are visible)

So, by the time I come to check for a specific element, a lot of computing time has already been consumed waiting for that stuff without the need for forced, fixed-period, “best guess” delays.

While I’m here, I never could get sensible results from WebUI.waitForJQueryLoad.
It never seemed to take into account that upon loading, jQuery was very busy “doing things” and not in fact “ready” (which is why jQuery is loaded, right? It does stuff on the page… modifies the DOM, etc.). So I wrote my own which works reliably.

Anyway, I’m drifting the topic.

Good call Claudinho!

1 Like

Thanks to all.

I have defined a Custom Keyword and it works like a dream.

HOWEVER.

At the moment I have hardcoded the calls and it works, naturally only for this button.

I haven’t figured out how I can pass the full directory of my object ‘REPOSITORY/ObjectName’ as a parameter to the @Keyword. It is the Type of the argument I can’t figure out. Katalon auto generated Keyword has arg type TestObject. I have tried with ‘String’ type but to no avail.

Would be grateful if someone can explain how can I dynamically pass the argument

@Keyword

def clickElement(TestObject to) {

try {

for (int j = 0; j <= 120; j++) {

if (WebUI.waitForElementNotPresent(findTestObject(‘REPOSITORY/ObjectName’), 5) == false) {

WebUI.comment(‘Wait for Button present. Continue.’)

WebUI.waitForElementPresent(findTestObject(‘REPOSITORY/ObjectName’), 60)

WebUI.comment(‘Wait for Button I ACCEPT is visible. Continue.’)

WebUI.waitForElementVisible(findTestObject(‘REPOSITORY/ObjectName’), 60)

WebUI.comment(‘Wait for Button I ACCEPT is clickable. Continue.’)

WebUI.waitForElementClickable(findTestObject(‘REPOSITORY/ObjectName’), 60)

WebUI.comment(‘Click on Button I ACCEPT and Continue.’)

WebUI.click(findTestObject(‘REPOSITORY/ObjectName’))

WebUI.comment(‘break’)

break

} else {

WebUI.comment(‘Button input_FINAL confirmButtonTop is still not present. Wait.’)

WebUI.delay(1)

}

}

} catch (WebElementNotFoundException e) {

KeywordUtil.markFailed(“Element not found”)

} catch (Exception e) {

KeywordUtil.markFailed(“Fail to click on element”)

}

You don’t need “the full directory” path to your object since Katalon “knows” the first part, “Object Respository”. All you need is the rest:

someMethod("folder_name/object_name")

...

def someMethod(String toPath) {
  TestObject to = findTestObject(toPath)
  WebUI.click(to)
  ...
}

And of course, if you don’t use folders in your OR, leave it and the slash, out.

someMethod("object_name")

Works perfect! Thanks

The
@Keyword works fine but with a little exception that I am suspicious it is an
Eclipse issue or problem.

If
I add a new call to the Keyword
then I get an error:

--------------------------------------------------------------------------------------------------------------------

SCRIPT
FAILED because (of)
org.codehaus.groovy.runtime.metaclass.MissingMethodExceptionNoStack: No
signature of method: com.ImprovedWait.NEW_Wait.smartWaitAndSendKeysMethod() is
applicable for argument types: (java.lang.String,
com.kms.katalon.core.testdata.InternalData) values: [REPOSITORY/SCRIPT,
com.kms.katalon.core.testdata.InternalData@22f59fa]

Possible
solutions: smartWaitAndSendKeysMethod(java.lang.String, java.lang.String)

--------------------------------------------------------------------------------------------------------------------

as
if the Keyword parameters were not defined as java.lang.String which they are.

Hovering
over the String parameters show that they are java.lang.String

Restarting
Katalon makes the error dissapear and the script runs fine until next edit.

I’ve never seen that before.

I use the Keyword mechanism differently. I don’t use the @Keyword decorator and I make my methods static (and import the package statically, too). You only need to use @Keyword if you want Katalon to find them for use in the Manual View/UI. I only ever use Script View so I don’t need that extra baggage…

package com.my_company 

public class someClass extends Whatever {
  static void someMethod(String str1, String str2) {
    // cool stuff here
  }
}

Then, in a test case:

import static com.my_company.someClass.*

someMethod("one", "two")
1 Like

Thanks.

I will try a new conversation specific for the Keyword issue, it should work.

Maybe I missed including something in the script, something that is ‘read’ every time i start Katalon.

Because other from that, as long as I don’t edit, it works well. It’s a shame!

Bump!

@Claudinho, thanks for posting this suggestion. I used it today in some of our flakier tests and it appears to have helped. In other cases it simplified tests where the tester had written waitForElementPresent, waitForVisible, waitForClickable. Thanks again.

Using this, but the wait is waiting the ENTIRE time inputted, even if it finds the object right away. In the OP’s original code, that is 5 seconds. Shouldn’t the wait only wait 5 seconds maximum, and move on if it finds it in less than that time?

I’m guessing that, since the object is present in your case, and the keyword is waiting for element NOT present, it has to wait the entire 5 seconds to make sure the object does not disappear.

So we’re right back to using a delay then, really. In this case, 5 seconds to really confirm it’s there. So this is really only a good method to use if you KNOW the element will not be there right away or the element is problematic. I was hoping to use this an an implicit wait all over the place.

Good point. I’d say we’re using it for elements that are, as you put it, problematic. They undergo some combination of state changes: added to DOM, made visible, and enabled.

I think what generally happens here is that the element we are “waiting” for is actually already loaded in the DOM, just not visible or accessible. In this case, I would think waitForElementVisible or waitForElementClickable would be the way to go, but they don’t seem to work any better. Is there any deeper documentation anywhere on how these waits work or what code they are using under the hood?

Also, a bit of a tip. We found on our AUT that often times tests would fail because an object wasn’t interactable because some other object was obscuring it. So we used delays. NO MORE! Instead, we have created these obscuring objects in our repository, and when we encounter them, we do a waitForElementNotPresent. This ensures the test waits for the obscuring object to go away before trying to interact with the next object. Seems to work well. In our AUT, we’ve found the majority of times, these obscuring objects have a class = ‘mask’, so we created a simple object with class = mask and use it over an over with the waitForElementNotPresent keyword. Moves much more quickly than having explicit delays everywhere.

Hi
I tried different scenario with:
WebUI.waitForElementPresent()
WebUI.waitForElementNotPresent()
sometime it work sometime it wont.
So,I did something like this and it worked for me.
public static void waitForSpinner(TestObject spinner){
for (int j = 0; j <= 20; j++) {
if(WebUI.verifyElementVisible(spinner, FailureHandling.OPTIONAL)){
WebUI.comment(‘Element is not ready.’)
WebUI.delay(1)
//continue
}else{
WebUI.comment(‘Page is ready’)
break
}
if(j==10){
KeywordUtil.markFailed(“Element is not found”)
break
}
}
}
But this is totally depend on web pages/elements behavior.

This is cool, Ashwin. I actually didn’t know that you could pass a TestObject into a method/custom keyword.

So, I could parameratize it and create a custom keyword like this:

def smartWait(TestObject testObject, Integer waitTime){
	for (int j = 0; j <= waitTime; j++) {
		if(WebUI.verifyElementVisible(testObject, FailureHandling.OPTIONAL)){
			WebUI.comment('Element ' + testObject + ' is not ready.')
			WebUI.delay(1)
		//continue
	}else{
	WebUI.comment(testObject + ' is ready')
	break
	}
if(j==10){
	KeywordUtil.markFailed('Element ' + testObject + ' was never found')
break
   }
}

But, wouldn’t you need some logic after the if statement, like == true? Or is that handled via the FailureHandling.OPTIONAL somehow? Also, what about incorporating the OP’s suggestion of having all 3 wait methods?

1 Like

@Patrick_Clough: verifyElement* return true/false, So there is no point to check like == true ?
FailureHandling.OPTIONAL is used to continue with test script execution.
what about incorporating the OP’s suggestion of having all 3 wait methods?
This is totally depend on web pages/elements behavior. Check the definition of 3 wait methods and there related verifyElement method, you will understand the difference.
For my application wait* methods are not consistent/reliable. Thats why i m using verifyElement methods

How did you get locator for spinner? I have similar issues with waits and also thought about similar method as yours but I couldn’t find a way to get locator for spinner it’s displaying for couple secs and disappearing so it’s not possible to find xpath to this element.