I published a GitHub repository:
Problem to solve
All Katalon Studio users would be familiar with the Project Setting > Excecution
dialog of the Katalon Studio GUI as follows:
Let’s look at the Default wait for element timeout (in seconds)
. Of course, you can change the value during the authoring time before you run your Test Cases. Now I want to update the timeout value programatically runtime. Is it possbile?
Katalon API includes a class com.kms.katalon.core.configuration.RunConfiguration
which implements a method int getTimeOut()
The value of Default wait for element timeout (in seconds)
is made accessible as the return of int getTimeOut()
method.
Howerver, RunConfiguration
class has no setTimeOut(int)
method. Therefore it seems that Katalon does not support a capability to update the timeout value by user codes. — But I want to know how to hack it.
Solution
You can read the source code of com.kms.katalon.core.configuration.RunConfiguration
class. The source code is bundled in the Katalon Studio distribution. You can find it in the <Katalon Studio installation folder>/Contents/Eclipse/configuration/resources/source/com.kms.katalon.core/com.kms.katalon.core-sources.jar
.
By a deep study in the source code, I found a way of hacking. See the following solution described.
Description
Adding a method into RunConfiguration class that pretty-prints the Execution Setting
// Test Cases/prettyPrintExecutionSetting
import com.kms.katalon.core.configuration.RunConfiguration
import com.kazurayam.ks.RunConfigurationModifier
RunConfigurationModifier.implementPrettyPrintExecutionSetting()
String prettyJson = RunConfiguration.prettyPrintExecutionSetting()
println "localExecutionSettingMapStorage:"
println prettyJson
When I ran this, I got the following output in the console:
1月 23, 2025 8:50:59 午後 com.kms.katalon.core.logging.KeywordLogger startTest
情報: --------------------
1月 23, 2025 8:50:59 午後 com.kms.katalon.core.logging.KeywordLogger startTest
情報: START Test Cases/prettyPrintExecutionSetting
localExecutionSettingMapStorage:
{
"Name" : "Chrome",
"allowCustomizeRequestResponseSizeLimit" : false,
"allowCustomizeRequestTimeout" : false,
"allowUsingSelfHealing" : false,
"allowUsingTimeCapsule" : true,
"description" : "",
"executedEntity" : "TestCase",
"execution" : {
"current_testcase" : "Test Cases/prettyPrintExecutionSetting",
"drivers" : {
"preferences" : {
"WebUI" : { }
},
"system" : {
"WebUI" : {
"browserType" : "CHROME_DRIVER",
"chromeDriverPath" : "/Applications/Katalon Studio.app/Contents/Eclipse/configuration/resources/drivers/chromedriver_mac/chromedriver"
}
}
},
"general" : {
"actionDelay" : 0.0,
"autoApplyNeighborXpaths" : false,
"defaultFailureHandling" : "STOP_ON_FAILURE",
"defaultPageLoadTimeout" : 30.0,
"enablePageLoadTimeout" : false,
"excludeKeywords" : [ "verifyElementPresent", "verifyElementNotPresent" ],
"executionProfile" : "default",
"ignorePageLoadTimeoutException" : false,
"methodsPriorityOrder" : [ {
"left" : "XPATH",
"right" : true
}, {
"left" : "SMART_LOCATOR",
"right" : true
}, {
"left" : "BASIC",
"right" : true
}, {
"left" : "CSS",
"right" : true
}, {
"left" : "IMAGE",
"right" : true
} ],
"proxy" : "{\"proxyOption\":\"NO_PROXY\",\"proxyServerType\":\"HTTP\",\"username\":\"\",\"password\":\"\",\"proxyServerAddress\":\"\",\"proxyServerPort\":0,\"exceptionList\":\"\",\"applyToDesiredCapabilities\":true}",
"report" : {
"reportFolder" : "/var/folders/7m/lm7d6nx51kj0kbtnsskz6r3m0000gn/T/Katalon/Test Cases/prettyPrintExecutionSetting/20250127_082617",
"screenCaptureOption" : true,
"takeScreenshotSettings" : {
"enable" : true
},
"videoRecorderOption" : {
"allowedRecordIfFailed" : true,
"allowedRecordIfPassed" : false,
"enable" : false,
"recordAllTestCases" : false,
"useBrowserRecorder" : true,
"videoFormat" : "AVI",
"videoQuality" : "LOW"
}
},
"selfHealingEnabled" : false,
"terminateDriverAfterTestCase" : false,
"terminateDriverAfterTestSuite" : true,
"testDataInfo" : { },
"timeCapsuleEnabled" : false,
"timeout" : 30.0,
"useActionDelayInSecond" : "SECONDS",
"xpathsPriority" : [ {
"left" : "xpath:attributes",
"right" : true
}, {
"left" : "xpath:idRelative",
"right" : true
}, {
"left" : "dom:name",
"right" : true
}, {
"left" : "xpath:link",
"right" : true
}, {
"left" : "xpath:neighbor",
"right" : true
}, {
"left" : "xpath:href",
"right" : true
}, {
"left" : "xpath:img",
"right" : true
}, {
"left" : "xpath:position",
"right" : true
}, {
"left" : "xpath:customAttributes",
"right" : true
} ]
},
"globalSmartWaitEnabled" : true,
"hideHostname" : false,
"logTestSteps" : true,
"smartLocatorEnabled" : false,
"smartLocatorSettingDefaultEnabled" : true
},
"host" : {
"hostAddress" : "127.0.0.1",
"hostName" : "kazurayam - localhost",
"hostPort" : 58769.0,
"os" : "Mac OS X 64bit"
},
"id" : "Test Cases/prettyPrintExecutionSetting",
"isDebugLaunchMode" : false,
"katalon.buildNumber" : "223",
"katalon.versionNumber" : "10.0.1",
"logbackConfigFileLocation" : "/Applications/Katalon Studio.app/Contents/Eclipse/configuration/org.eclipse.osgi/86/0/.cp/resources/logback/logback-console.xml",
"maxFailedTests" : -1.0,
"name" : "prettyPrintExecutionSetting",
"pluginTestListeners" : [ "KatalonReportListener" ],
"projectDir" : "/Users/kazurayam/katalon-workspace/KS_RunConfigurationModifier",
"runningMode" : "GUI",
"sessionServer.host" : "localhost",
"sessionServer.port" : 58642.0,
"source" : "/Users/kazurayam/katalon-workspace/KS_RunConfigurationModifier/Test Cases/prettyPrintExecutionSetting.tc",
"testops" : { }
}
1月 27, 2025 8:26:24 午前 com.kms.katalon.core.logging.KeywordLogger endTest
情報: END Test Cases/prettyPrintExecutionSetting
The call to RunConfigurationModifier.implementPrettyPrintExecutionSetting()
dynamically injects a static method prettyPrintExecutionSetting
in the RunConfiguration class.
The call to RunConfiguration.prettyPrintExecutionSetting()
prints the content of the localExecutionSettingMapStorage
variable inside the RunConfiguration
object, which contains the values set in the Project Settings > Execution
GUI window of Katalon Studio.
Updating Project Settings > Execution > Default wait for element timeout
// Test Cases/updateTimeOut
import com.kms.katalon.core.configuration.RunConfiguration
import com.kazurayam.ks.RunConfigurationModifier
println "Before updating: RunConfiguration.getTimeOut()=" + RunConfiguration.getTimeOut()
assert RunConfiguration.getTimeOut() == 30
RunConfigurationModifier.implementSetTimeOut()
RunConfiguration.setTimeOut(8)
println "After updating: RunConfiguration.getTimeOut()=" + RunConfiguration.getTimeOut()
assert RunConfiguration.getTimeOut() == 8
When I ran this I got the following output in the console:
1月 23, 2025 8:56:34 午後 com.kms.katalon.core.logging.KeywordLogger startTest
情報: --------------------
1月 23, 2025 8:56:34 午後 com.kms.katalon.core.logging.KeywordLogger startTest
情報: START Test Cases/updateDefaultTimeOut
Before modifying: RunConfiguration.getTimeOut()=30
After modifying: RunConfiguration.getTimeOut()=8
1月 23, 2025 8:56:35 午後 com.kms.katalon.core.logging.KeywordLogger endTest
情報: END Test Cases/updateDefaultTimeOut
How is it implemented?
Please read the source of com.kazurayam.ks.RunConfigurationModifier
classs. Here I would quote it:
package com.kazurayam.ks
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.databind.ObjectWriter
import com.fasterxml.jackson.databind.SerializationFeature
import com.kms.katalon.core.annotation.Keyword
import com.kms.katalon.core.configuration.RunConfiguration
/**
* The Jackson-databind-2.17.1.jar is bundled in Katalon Studio v10.0.1
*
*
*/
public class RunConfigurationModifier {
@Keyword
public static void implementPrettyPrintExecutionSetting() {
RunConfiguration.metaClass.'static'.prettyPrintExecutionSetting << {
->
ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS, true)
//mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
ObjectWriter writer = mapper.writerWithDefaultPrettyPrinter()
String prettyJson = writer.writeValueAsString(localExecutionSettingMapStorage)
return prettyJson
}
}
@Keyword
public static void implementSetTimeOut() {
RunConfiguration.metaClass.'static'.setTimeOut << { int seconds ->
localExecutionSettingMapStorage.get('execution').get('general').put('timeout', seconds)
}
}
@Keyword
public static void implementGetLogTestSteps() {
RunConfiguration.metaClass.'static'.getLogTestSteps << {
->
return localExecutionSettingMapStorage.get('execution').get('logTestSteps')
}
}
@Keyword
public static void implementSetLogTestSteps() {
RunConfiguration.metaClass.'static'.setLogTestSteps << { boolean b ->
localExecutionSettingMapStorage.get('execution').put('logTestSteps', b)
}
}
}
In the RunConfigurationModifier
class, I used the Groovy’s Meta-programming technique. With this technique, the prettyPrintExecutionSetting
method and others are added to the RunConfiguration
class.
The implementSetTimeOut
method of the RunConfigurationModifier
adds the setTimeOut(int)
method that is missing in the original RunConfiguration
class. If you would like, you would be able to add more methods that update other items in the Project Setting > Execution
. Please try it yourself.
Warning: this does not work with Katalon Studio v9
I developed this project using Katalon Studio Free v10.0.1. I tried the v0.2.0 to run the Test Cases/prettyPrintExecutionSetting
using Katalon v9.0.0 and it hanged with the following message:
2025-01-26 12:38:40.524 INFO c.k.katalon.core.main.TestCaseExecutor - --------------------
2025-01-26 12:38:40.557 INFO c.k.katalon.core.main.TestCaseExecutor - START Test Cases/prettyPrintExecutionSetting
2025-01-26 12:38:41.571 DEBUG testcase.prettyPrintExecutionSetting - 1: RunConfigurationModifier.implementPrettyPrintExecutionSetting()
2025-01-26 12:38:41.750 DEBUG testcase.prettyPrintExecutionSetting - 2: prettyJson = prettyPrintExecutionSetting()
2025-01-26 12:38:42.755 ERROR c.k.katalon.core.main.TestCaseExecutor - ❌ Test Cases/prettyPrintExecutionSetting FAILED.
Reason:
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class com.kms.katalon.core.configuration.RunConfiguration$1 and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS)
at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:77)
at com.fasterxml.jackson.databind.SerializerProvider.reportBadDefinition(SerializerProvider.java:1306)
at com.fasterxml.jackson.databind.DatabindContext.reportBadDefinition(DatabindContext.java:408)
at com.fasterxml.jackson.databind.ser.impl.UnknownSerializer.failForEmpty(UnknownSerializer.java:53)
at com.fasterxml.jackson.databind.ser.impl.UnknownSerializer.serialize(UnknownSerializer.java:30)
at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:480)
at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:319)
at com.fasterxml.jackson.databind.ObjectWriter$Prefetch.serialize(ObjectWriter.java:1572)
at com.fasterxml.jackson.databind.ObjectWriter._writeValueAndClose(ObjectWriter.java:1273)
at com.fasterxml.jackson.databind.ObjectWriter.writeValueAsString(ObjectWriter.java:1140)
at com.kazurayam.ks.RunConfigurationModifier$_implementPrettyPrintExecutionSetting_closure1.doCall(RunConfigurationModifier.groovy:16)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at prettyPrintExecutionSetting.run(prettyPrintExecutionSetting:8)
at com.kms.katalon.core.main.ScriptEngine.run(ScriptEngine.java:194)
at com.kms.katalon.core.main.ScriptEngine.runScriptAsRawText(ScriptEngine.java:119)
at com.kms.katalon.core.main.TestCaseExecutor.runScript(TestCaseExecutor.java:448)
at com.kms.katalon.core.main.TestCaseExecutor.doExecute(TestCaseExecutor.java:439)
at com.kms.katalon.core.main.TestCaseExecutor.processExecutionPhase(TestCaseExecutor.java:418)
at com.kms.katalon.core.main.TestCaseExecutor.accessMainPhase(TestCaseExecutor.java:410)
at com.kms.katalon.core.main.TestCaseExecutor.execute(TestCaseExecutor.java:285)
at com.kms.katalon.core.main.TestCaseMain.runTestCase(TestCaseMain.java:144)
at com.kms.katalon.core.main.TestCaseMain.runTestCase(TestCaseMain.java:135)
at TempTestCase1737862711294.run(TempTestCase1737862711294.groovy:25)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
2025-01-26 12:38:42.864 ERROR c.k.katalon.core.main.TestCaseExecutor - ❌ Test Cases/prettyPrintExecutionSetting FAILED.
Reason:
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class com.kms.katalon.core.configuration.RunConfiguration$1 and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS)
at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:77)
at com.fasterxml.jackson.databind.SerializerProvider.reportBadDefinition(SerializerProvider.java:1306)
at com.fasterxml.jackson.databind.DatabindContext.reportBadDefinition(DatabindContext.java:408)
at com.fasterxml.jackson.databind.ser.impl.UnknownSerializer.failForEmpty(UnknownSerializer.java:53)
at com.fasterxml.jackson.databind.ser.impl.UnknownSerializer.serialize(UnknownSerializer.java:30)
at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:480)
at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:319)
at com.fasterxml.jackson.databind.ObjectWriter$Prefetch.serialize(ObjectWriter.java:1572)
at com.fasterxml.jackson.databind.ObjectWriter._writeValueAndClose(ObjectWriter.java:1273)
at com.fasterxml.jackson.databind.ObjectWriter.writeValueAsString(ObjectWriter.java:1140)
at com.kazurayam.ks.RunConfigurationModifier$_implementPrettyPrintExecutionSetting_closure1.doCall(RunConfigurationModifier.groovy:16)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at prettyPrintExecutionSetting.run(prettyPrintExecutionSetting:8)
at com.kms.katalon.core.main.ScriptEngine.run(ScriptEngine.java:194)
at com.kms.katalon.core.main.ScriptEngine.runScriptAsRawText(ScriptEngine.java:119)
at com.kms.katalon.core.main.TestCaseExecutor.runScript(TestCaseExecutor.java:448)
at com.kms.katalon.core.main.TestCaseExecutor.doExecute(TestCaseExecutor.java:439)
at com.kms.katalon.core.main.TestCaseExecutor.processExecutionPhase(TestCaseExecutor.java:418)
at com.kms.katalon.core.main.TestCaseExecutor.accessMainPhase(TestCaseExecutor.java:410)
at com.kms.katalon.core.main.TestCaseExecutor.execute(TestCaseExecutor.java:285)
at com.kms.katalon.core.main.TestCaseMain.runTestCase(TestCaseMain.java:144)
at com.kms.katalon.core.main.TestCaseMain.runTestCase(TestCaseMain.java:135)
at TempTestCase1737862711294.run(TempTestCase1737862711294.groovy:25)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
2025-01-26 12:38:42.954 INFO c.k.katalon.core.main.TestCaseExecutor - END Test Cases/prettyPrintExecutionSetting
I guess that the RunConfiguration class of v9 has some fault that I can not remedy. I wouldn’t dig into this issue any more.