Provided that the interactiability of the element for Joana is controlled by the value of “class” attribute, the following built-in keyword might be useful:
boolean result = WebUI.waitForElementAttributeValue(
findTestObject(some test object),
"class", "interactable", 10)
This keyword call will wait until the value of class attribute of the specified HTML element to be exactly equal to a string “interactable”. It timeouts after 10 seconds of wait. It returns boolean value.
However, this keyword is short in many cases. Why? The class attribute of a HTML element could vary dynamically. Testing “exactly equal” is not expressive enough. For example, I want to test if the following button element to have bar
class or not, but the value of "class"
attribute may be variable like:
<button class="foo" ...
<button class="foo bar" ...
<button class="bar foo" ...
A single call to WebUI.waitForElementAttributeValue()
keyword can not match 2 or more possible class values that contains bar
.
Ideally I want a pair of keywords:
-
WebUI.waitForElementHasClass(TestObject, String className, int timeout, FailureHandling)
and
WebUI.waitForElementNotHasClass(...)
As you all know, jQuery has hasClass function which is very helpful to work with dynamic HTMLs. It is a shame that Katalon doesn’t provide any built-in keyword equivalent to jQuery’s hasClass(). I suppose that Katalon keywords were designed ages ago before jQuery-era.
The waitForElementHasClass keyword can be implemented as a slight modification of WebUI.waitForElementAttributeValue()
keyword line#90:
It uses a simple equality test by ==
. You just want to replace it with a bit sophisticated Groovy code snippet. The following Test Case shows a demo how to implement hasClass
test:
import org.openqa.selenium.WebElement
import com.kms.katalon.core.testobject.ConditionType
import com.kms.katalon.core.testobject.TestObject
import com.kms.katalon.core.webui.keyword.WebUiBuiltInKeywords as WebUI
TestObject makeTestObject(String xpath) {
TestObject tObj = new TestObject(xpath)
tObj.addProperty("xpath", ConditionType.EQUALS, xpath)
return tObj
}
boolean hasClass(WebElement we, String className) {
String classValue = we.getAttribute("class")
if (classValue != null) {
return (classValue.split(" ") as List).contains(className)
} else {
return false
}
}
WebUI.openBrowser("")
WebUI.navigateToUrl("https://katalon-demo-cura.herokuapp.com/profile.php#login")
TestObject TO_menuToggle = makeTestObject("//a[@id='menu-toggle']")
WebUI.verifyElementPresent(TO_menuToggle, 10)
// <a id="menu-toggle" href="#" class="btn btn-dark btn-lg toggle"><i class="fa fa-bars"></i></a>
WebElement we = WebUI.findWebElement(TO_menuToggle)
WebUI.comment("the element has class 'foo': ${hasClass(we, 'foo')}")
WebUI.comment("the element has class 'btn': ${hasClass(we, 'btn')}")
WebUI.comment("the element has class 'btn-dark': ${hasClass(we, 'btn-dark')}")
WebUI.comment("the element has class 'toggle': ${hasClass(we, 'toggle')}")
WebUI.closeBrowser()
I think that waitForElementHasClass
keyword should be provided built-in. It would be far more useful than the existing waitForElementClickable
.
→ @vu.tran
Alternatively, @joana.pedroso can repeat calling WebUI.wait for ElementAttributeValue()
multiple times to cover all possible values of the class attribute, as follows:
boolean b1 = WebUI.verifyElementAttributeValue(findTestObject("id of the button"),
"class", "foo bar", 10)
boolean b2 = WebUI.verifyElementAttributeValue(findTestObject("id of the button"),
"class", "bar foo", 10)
if (b1 || b2) {
println "bar class was found"
} else {
println "bar class was not found"
}
This will work, though very slowly. How silly this code looks! 