How to use conditional click on a switch element?

I have a page where I would have to input some text then,
click on a switch next to it to activate it.

But I want to only click on the switch if it is off;
If the switch is already on, the script should continue to the next steps.

I will share the code snippet as well as the switch element in the on/off state:

// Access the administrative settings page

WebUI.callTestCase(findTestCase('Admin/6_Adminstration/3_Settings/access-admin-settings'), [:], FailureHandling.STOP_ON_FAILURE)

// Scroll down to the meta input section

WebUI.scrollToElement(findTestObject('Admin/6_Administration/3_Settings/Flags/member-flags-input-field-1'), 1)

// Set the text of the meta title input field

WebUI.setText(findTestObject('Admin/6_Administration/3_Settings/Meta-Settings/input-title'), metaTitle)

// Click the switch next to the meta title input field

WebUI.click(findTestObject('Admin/6_Administration/3_Settings/Meta-Settings/input-title-switch'))

// Set the text of the meta description input field

WebUI.setText(findTestObject('Admin/6_Administration/3_Settings/Meta-Settings/input-description'), metaDescription)

// Click the switch next to the meta description input field

WebUI.click(findTestObject('Admin/6_Administration/3_Settings/Meta-Settings/input-description-switch'))

// Set the text of the meta keywords input field

WebUI.setText(findTestObject('Admin/6_Administration/3_Settings/Meta-Settings/input-keywords'), metaKeywords)

// Click the switch next to the meta keywords input field

WebUI.click(findTestObject('Admin/6_Administration/3_Settings/Meta-Settings/input-keywords-switch'))

// Scroll back to the top of the page

WebUI.scrollToPosition(0, 0)

// Click the save button

WebUI.click(findTestObject('Admin/6_Administration/3_Settings/Meta-Settings/save-settings'))

// Log out of the system

WebUI.callTestCase(findTestCase('Admin/admin-logout'), [:], FailureHandling.STOP_ON_FAILURE)

input switch off-state:
<input class="switch-input ng-valid ng-dirty" ng-checked="config.meta_tags.values.title_enabled.value" ng-model="config.meta_tags.values.title_enabled.value" type="checkbox">

input switch on-state:
<input class="switch-input ng-valid ng-dirty" ng-checked="config.meta_tags.values.title_enabled.value" ng-model="config.meta_tags.values.title_enabled.value" type="checkbox" checked="checked">

can you help improve the using WebUI.verifyElementHasAttribute
I have tried but I’m have errors.

groovy.lang.MissingMethodException: No signature of method: static com.kms.katalon.core.webui.keyword.WebUiBuiltInKeywords.verifyElementHasAttribute() is applicable for argument types: (com.kms.katalon.core.testobject.TestObject, java.lang.String) values: [TestObject - ‘Object Repository/Admin/6_Administration/3_Settings/Meta-Settings/input-title-switch’, …]

Thanks in advance for your help.

Per the documentation, the method takes 3 required args:

Parameters

Param Param Type Mandatory Description
to TestObject Required Represent a web element.
attributeName String Required The name of the attribute to verify.
timeout int Required System will wait at most timeout (seconds) to return result
flowControl FailureHandling Optional Specify failure handling schema to determine whether the execution should be allowed to continue or stop

However, you only supplied it 2. Give it some small timeOut (e.g. 1).

Also, in your case, you should supply it FailureHandling.OPTIONAL as well. This will insure that it acts purely as conditional, i.e. it won’t fail your test case or mark a warning on that step.

1 Like

Thanks for you reply @mwarren04011990 I’ve added the timeout however. It’s still failed when switch is off, even with the FailureHandling.OPTIONAL

Here the improved code:

// Access the administrative settings page
WebUI.callTestCase(findTestCase('Admin/6_Adminstration/3_Settings/access-admin-settings'), [:], FailureHandling.STOP_ON_FAILURE)

// Scroll down to the meta input section
WebUI.scrollToElement(findTestObject('Admin/6_Administration/3_Settings/Flags/member-flags-input-field-1'), 1)

// Set the text of the meta title input field
WebUI.setText(findTestObject('Admin/6_Administration/3_Settings/Meta-Settings/input-title'), metaTitle)

// Check if the switch next to the meta title input field is on
if (!(WebUI.verifyElementHasAttribute(findTestObject('Object Repository/Admin/6_Administration/3_Settings/Meta-Settings/input_Title_switch'), 
    'checked', 1))) {
    // Click the switch next to the meta title input field
    WebUI.click(findTestObject('Object Repository/Admin/6_Administration/3_Settings/Meta-Settings/input_Title_switch'), 
        FailureHandling.OPTIONAL)
}

// Set the text of the meta description input field
WebUI.setText(findTestObject('Admin/6_Administration/3_Settings/Meta-Settings/input-description'), metaDescription)

// Check if the switch next to the meta description input field is on
if (!(WebUI.verifyElementHasAttribute(findTestObject('Object Repository/Admin/6_Administration/3_Settings/Meta-Settings/input_Description_switch'), 
    'checked', 1))) {
    // Click the switch next to the meta description input field
    WebUI.click(findTestObject('Object Repository/Admin/6_Administration/3_Settings/Meta-Settings/input_Description_switch'), 
        FailureHandling.OPTIONAL)
}

// Set the text of the meta keywords input field
WebUI.setText(findTestObject('Admin/6_Administration/3_Settings/Meta-Settings/input-keywords'), metaKeywords)

// Check if the switch next to the meta keywords input field is on
if (!(WebUI.verifyElementHasAttribute(findTestObject('Object Repository/Admin/6_Administration/3_Settings/Meta-Settings/input_Keywords_switch'), 
    'checked', 1))) {
    // Click the switch next to the meta keywords input field
    WebUI.click(findTestObject('Object Repository/Admin/6_Administration/3_Settings/Meta-Settings/input_Keywords_switch'), 
        FailureHandling.OPTIONAL)
}

// Scroll back to the top of the page
WebUI.scrollToPosition(0, 0)

// Click the save button
WebUI.click(findTestObject('Admin/6_Administration/3_Settings/Meta-Settings/save-settings'))

// Log out of the system
WebUI.callTestCase(findTestCase('Admin/admin-logout'), [:], FailureHandling.STOP_ON_FAILURE)

And the error:

Caused by: com.kms.katalon.core.exception.StepFailedException: Object ‘Object Repository/Admin/6_Administration/3_Settings/Meta-Settings/input_Title_switch’ does not have attribute ‘checked’

Yeah, it’s maybe because the method return null and not false. How about trying something like below. Note that I put the FailureHandling on the if statement as well.


    // Check if the switch next to the meta description input field is on
    if (WebUI.verifyElementHasAttribute(findTestObject('Object Repository/Admin/6_Administration/3_Settings/Meta-Settings/input_Description_switch'), 'checked', 10, FailureHandling.OPTIONAL)) {
        WebUI.comment("switch was on")
    } else {
        WebUI.comment("switch was off")
        // Click the switch next to the meta description input field
        WebUI.click(findTestObject('Object Repository/Admin/6_Administration/3_Settings/Meta-Settings/input_Description_switch'),  FailureHandling.OPTIONAL))
    }

Stop! You’re both wrong!

@yvan.militisi those FailureHandling arguments should go on the WebUI.verifyElement... methods that were using as the if conditions, not the actions! Please read the link in my last answer for how those FailureHandlings work.

@grylion54 the WebUI.verifyElement... methods all return either true or false

As a boolean, they should return either true or false, but you can find other discussions on this forum where that does not seem to be the case. Similarly, part of my former team used to have the same philosophy that if couldn’t prove an item existed, then they would return null regardless if the method was supposed to return boolean. SIGH.

“There are two types of people in the world. Those who can extrapolate from incomplete data.”

Sounds like a bug that should be raised to the Katalon developer team…

After some back and forth. I found an alternative way to achieve what i wanted by using the parent element class that get switch-active when the switch is on.

I will share the final code here for reference. maybe it will help other having a similar issue

// Access the administrative settings page
WebUI.callTestCase(findTestCase('Admin/6_Adminstration/3_Settings/access-admin-settings'), [:], FailureHandling.STOP_ON_FAILURE)

// Scroll down to the meta input section
WebUI.scrollToElement(findTestObject('Admin/6_Administration/3_Settings/Flags/member-flags-input-field-1'), 1)

// Set the text of the meta title input field
WebUI.setText(findTestObject('Admin/6_Administration/3_Settings/Meta-Settings/input-title'), GlobalVariable.metaTitle)

TestObject switchTitle = findTestObject('Admin/6_Administration/3_Settings/Meta-Settings/input-title-switch')

String isCheckedTitle = WebUI.getAttribute(switchTitle, 'class')

if (!(isCheckedTitle.contains('switch-active'))) {
    // Click the switch if it is off
    WebUI.click(switchTitle)
}

// Set the text of the meta description input field
WebUI.setText(findTestObject('Admin/6_Administration/3_Settings/Meta-Settings/input-description'), GlobalVariable.metaDescription)

TestObject switchDescription = findTestObject('Admin/6_Administration/3_Settings/Meta-Settings/input-description-switch')

String isCheckedDescription = WebUI.getAttribute(switchDescription, 'class')

if (!(isCheckedDescription.contains('switch-active'))) {
    // Click the switch if it is off
    WebUI.click(switchDescription)
}

// Set the text of the meta keywords input field
WebUI.setText(findTestObject('Admin/6_Administration/3_Settings/Meta-Settings/input-keywords'), GlobalVariable.metaKeywords)

TestObject switchKeywords = findTestObject('Admin/6_Administration/3_Settings/Meta-Settings/input-keywords-switch')

String isCheckedKeywords = WebUI.getAttribute(switchKeywords, 'class')

if (!(isCheckedKeywords.contains('switch-active'))) {
    // Click the switch if it is off
    WebUI.click(switchKeywords)
}

// Scroll back to the top of the page
WebUI.scrollToPosition(0, 0)

// Click the save button
WebUI.click(findTestObject('Admin/6_Administration/3_Settings/Meta-Settings/save-settings'))

// Log out of the system
WebUI.callTestCase(findTestCase('Admin/admin-logout'), [:], FailureHandling.STOP_ON_FAILURE)
...
// Check if the switch next to the meta keywords input field is on
if (!(WebUI.verifyElementHasAttribute(findTestObject('Object Repository/Admin/6_Administration/3_Settings/Meta-Settings/input_Keywords_switch'), 
    'checked', 1, FailureHandling.OPTIONAL))) {
...

@yvan.militisi

I was late to the party.

You can try WebUI.waitForHasAttribute keyword instead of WebUI.verifyElementHasAttribute keyword.

...
// Check if the switch next to the meta keywords input field is on
if (!(WebUI.waitForElementHasAttribute(findTestObject('Object Repository/Admin/6_Administration/3_Settings/Meta-Settings/input_Keywords_switch'), 
    'checked', 1, FailureHandling.OPTIONAL))) {
...

WebUI.verifyElementHasPresent(target, 'checked', 1, FailureHandling.OPTIONAL) will throw a StepFailedException with terrifying StackTrace when the target element has no checked attribute when the timeout expires, and will return a Boolean value false.

On the other hand, WebUI.waitForElementHasPresent(target, 'checked', 1, FailureHandling.OPTIONAL) will throw no StepFailedException when the target element has no checked attribute when the timeout expires, and will return a Boolean value false.

As you may know, there are many WebUI keywords named “verify<condition>” and “waitFor<condition>”. What is the difference between these 2 groups?

Provided that FailureHandling.OPTIONAL is specified,

  1. when the condition turns to be true before the timeout expires, both will silently return true
  2. when the condition turns to be false at the timeout expires,
  • the verify* keywords will throw a StepFailedException with StackTrace printed in the console; still the Test Case will not stop, will continue.
  • the waitFor* keywords won’t throw any Exception; the Test Case will not stop, will continue.
  • both keyword will return a boolean value false.

I found this design principle by reading the source code of keywords.

I guess that this design principle is applied to the built-in keywords overall, but I haven’t checked if ALL of the keywords follow the priciple. There could be exceptions mistakenly.

I am afraid that the official Katalon documentation of the verify* and waitFor* keywords does not explain this design principle at all. Therefore some users got confused. I hope the documentation to be improved.

@vu.tran

2 Likes

Thank you so much for your detailed explanation and solution to my issue. @kazurayam
I tried it out and it worked perfectly. Your knowledge and willingness to help is greatly appreciated. Thank you again for your time and support.