WS.SendRequest(findTestObject) not valid in Groovy but works in Test Case

Please let us know what you are using Katalon Studio for?

I have currently applied Katalon Studio in my project

How would your work be affected if this issue has not been resolved?

  1. I cannot continue (this test) and have to work on something else while awaiting your response

Operating System

Windows 10

Katalon Studio Version - 7.8.1

Katalon Studio logs

  • Windows logs folder: \config.metadata.log

Screenshots / Videos

  • Please attach screenshots or videos if necessary to reproduce the issue
    Issue

Unable to reference methods of class WSBuiltInKeywords in groovy script the same way it is done in Test Case. Note: WebUI methods work but not WS (WebService) methods. See error below.

Import

Import is defined as WS

import com.kms.katalon.core.webservice.keyword.WSBuiltInKeywords as WS

Code (Same method works in Katalon Test but not in Groovy script)

ResponseObject xmlGetList = WS.sendRequestAndVerify(findTestObject(‘API/JOB/TA_API_JOB_JOBRUN_GETLIST’, [(‘URL’) : aURL, (‘JOB_ID’) : jobId]))

Error

Description Resource Path Location Type
Groovy:[Static type checking] - Cannot find matching method com.kms.katalon.core.webservice.keyword.WSBuiltInKeywords#sendRequestAndVerify(com.kms.katalon.core.testobject.TestObject). Please check if the declared type is right and if the method exists. UtilMethods.groovy /C%%Users%jims%git%twa%TWA.prj/Keywords/com/taf line 235 Java Problem

Is the syntax different for Groovy or am I missing an Import? Is there a limitation of using Groovy to execute the same Katalon methods?

Thanks in advance for any help you can give!

What do you mean by ‘groovy script’?
A standard groovy environment setup?
I hope you realize that katalon is using own libraries, some of them backed top of plain java, some of them backed top of groovy.
Thats’s why the packages you need to import looks like ‘com.katalon.blah’

Hi bionel,
I have a Katalon ‘Keywords’ groovy script called UtilMethods.groovy so that is why I call it a groovy script.

In this script, I’m trying to execute the WS for SendRequestAndVerify but the ‘findTestObject’ is not recognized by Katalon.

Katalon Test Case uses the same code and has no issue but it doesn’t work in the Groovy. I’m using the groovy script (Keyword) to create a custom method because I use this same code in 6+ different tests.

I’ve executed WebUI methods in groovy script (custom keyword) without issue but WS is giving the errors previously mentioned.

Can you please share your code? I am still confused but at this moment i will bet on a missing import

Hi bionel,

I commented out @TypeChecked and I didn’t have any errors and the script executed as expected.
I would prefer to have some validation to code format/syntax with Groovy TypeChecked but I guess it isn’t possible with Katalon.

Do you have any thoughts?

package com.taf

import static com.kms.katalon.core.testobject.ObjectRepository.findTestObject

import com.kms.katalon.core.annotation.Keyword
import com.kms.katalon.core.testobject.ResponseObject as ResponseObject
import com.kms.katalon.core.util.KeywordUtil
import com.kms.katalon.core.webservice.keyword.WSBuiltInKeywords as WS

import groovy.time.TimeCategory
import groovy.transform.TypeChecked
import groovy.util.slurpersupport.GPathResult
import groovy.xml.*

//@TypeChecked
public class UtilVal {

/**
 * Jim Sears 2020/12/14
 * Custom function to validate job status using API
 * Custom groovy method would not work for this code because WebService (WS) methods are not recognized.
 * @param TABLE representing the database table for calling test.
 * @param DATA_SCENARIO representing the row in the table that contains the validation columns
 */
@Keyword
static validateJobRunStatus(HashMap<String, String> data){
	'Loop through all validation columns on table, stopping if no data is provided'
	for (int i = 1; i <= 6; i++) {
		String inputData = data.get('VAL_COL_0' + i)

		'Stop processing columns if column is empty'
		if (inputData == '') {
			break
		}

		Integer ix = 0

		def arrData = inputData.split(';;')

		def jobId = arrData[0]

		def expected = arrData[1]

		String aURL = data.get('URL')

		//Groovy:[Static type checking] - Cannot call com.kms.katalon.core.testobject.ObjectRepository#findTestObject(java.lang.String, java.util.Map <java.lang.String, java.lang.Object>) 
		//with arguments [java.lang.String, java.util.LinkedHashMap <java.lang.String, java.lang.String>] 	
		ResponseObject xmlGetList = WS.sendRequest(findTestObject('API/JOB/TA_API_JOB_JOBRUN_GETLIST', [('URL') : aURL, ('JOB_ID') : jobId]))

		def getListContent = xmlGetList.responseBodyContent

		GPathResult getListParsedXml = new XmlSlurper().parseText(getListContent)

		'XML node path errors in Groovy script. Need method to get property value. Cannot use node path directly in Groovy script '
		def jobRunId = getListParsedXml.id.text()			

		'Verify jobRunId was found'
		UtilMethods.compare(jobRunId!=0, 'Found job run id [' + jobRunId + '] for job id [' + jobId + ']')

		def start = new Date()

		def now = new Date()

		String actual = ''

		Integer seconds = 0

		ResponseObject xmlGet

		'Repeat API call (max 10 seconds) waiting for backend system to process earlier activity'
		while (seconds < 10) {
			ix = (ix + 1)

			//Groovy:[Static type checking] - Cannot call com.kms.katalon.core.testobject.ObjectRepository#findTestObject(java.lang.String, java.util.Map <java.lang.String, java.lang.Object>) 
			//with arguments [java.lang.String, java.util.LinkedHashMap <java.lang.String, java.lang.String>]
			xmlGet = WS.sendRequestAndVerify(findTestObject('API/JOBRUN/TA_API_JOBRUN_GET', [('URL') : data.get('URL'), ('JOBRUN_ID') : jobRunId]))

			'Get Job status by tag from XML'
			def xmlGetContent = xmlGet.responseBodyContent

			//GPathResult getParsedXml = new XmlSlurper().parseText(xmlGetContent)
			def getParsedXml = new XmlSlurper().parseText(xmlGetContent)

			'XML node path errors in Groovy script. Need method to get property value. Cannot use node path directly in Groovy script '
			actual = getParsedXml.jobrun.statusname.text()

			'Exit loop if expected matches actual. Peforming actual compare now would fail the test so using the method equals.'
			if (actual.equals(expected)) {
				break
			}

			'Explicitly slowing script from creating too many API calls and building large result files.'
			WS.delay(1)

			'Re-calculate seconds for loop'
			seconds = TimeCategory.minus(new Date(), start).seconds

			'Inform user of repeated API calls in case an endless loop occurs'
			KeywordUtil.logInfo('(' + ix + '):Repeating API call due to backend processing delay... ')
		}

		'Perform Validation'
		UtilMethods.compare(actual.equals(expected), ((((('Job [' + jobRunId) + '] actual status [') + actual) + '] matches expected status [') + expected) + '].')
	}
}

Mhm… I dont have anything solid at this moment, i have to read a bit what this annotation has to do.
What i know up to now is that, various java annotations are not suported in katalon, due to the design (it somehow limiting the scope of ‘pure programming’)
Will dig more

At this moment i will make just a small warning: a custom keyword is not an ordinary groovy script but a class, despite the extension

I’m not much of technical programmer so your comment about class is helpful.
Thanks for the help.

@jim.sears

I tried to reproduce your case on my side.

@TypeChecked
public class UtilVal {
    ....
        ResponseObject xmlGetList =
            WS.sendRequest(findTestObject('API/JOB/TA_API_JOB_JOBRUN_GETLIST',
                                            [('URL') : aURL, ('JOB_ID') : jobId]))
        ....
}

I got the following validation error.

Groovy:[Static type checking] - Cannot call com.kms.katalon.core.testobject.ObjectRepository#findTestObject(java.lang.String, java.util.Map <java.lang.String, java.lang.Object>)
with arguments [java.lang.String, java.util.LinkedHashMap <java.lang.String, java.lang.String>]

I read the message, and I understood that I need to change the code so that it casts the type of the 2nd parameter explicitly.

        ResponseObject xmlGetList =
            WS.sendRequest(findTestObject('API/JOB/TA_API_JOB_JOBRUN_GETLIST',
                                            (Map)[('URL') : aURL, ('JOB_ID') : jobId]))

Then I got the following compilation error message:

Groovy:[Static type checking] - Cannot find matching method com.kms.katalon.core.webservice.keyword.WSBuiltInKeywords#sendRequest(com.kms.katalon.core.testobject.TestObject). Please check if the declared type is right and if the method exists.

I read the message and realized that I need to cast TestObject to RequestObject explicitly. So I changed the code again:

import com.kms.katalon.core.testobject.RequestObject as RequestObject
...
        ResponseObject xmlGetList =
            WS.sendRequest((RequestObject)findTestObject('API/JOB/TA_API_JOB_JOBRUN_GETLIST',
                                            (Map)[('URL') : aURL, ('JOB_ID') : jobId]))

Then the compilation error disappeared. The problem was fixed.


I am afraid, your question is off the mark. @TypeCheck is working fine in Katalon Studio. It gave you good enough messages. The message told you how to make your code type-safe. When you use @TypeCheck, you are required to bother yourself writing explicit type-casting codes. That is what you wanted to do, isn’t it?

I think that type-casting code is not very groovy-ish. So I would never use @TypeCheck in Katalon.

3 Likes

Hi kazurayam,

Thank you for taking the time to explain what I was missing. I wonder why the type cast is required in groovy keyword but not in the Test Case itself.

I thought TypeChecked was explicitly made for checking groovy code. It makes sense what you are saying though because some of the groovy code I see use def to declare variables instead of using the actual type. Is that what you mean by groovy-ish? In other words, Groovy is designed to be easy to use so it isn’t “strongly typed” language?

Thanks again for the solution!

No, you are still misunderstanding.

@TypeChecked annotation works in the classes under the Keywords directory, but in Test Cases you can not write @TypeChecked. See the following screenshot as example.

Please find in the above screenshot that Katalon Studio does not understand a line of @TypeChecked. Katalon Studio gets confused with the line and emitted a pointless error “unexpected token WebUI”.

Why @TypeChecked is not accepted in Katalon’s Test Case scripts? — I will tell it next.

A script of “Test Case” is not a 100% pure Groovy script. It is just a text. Katalon Studio reads it, preprocess it, generates a real Groovy script, and run it.

Let me give you an example. With Katalon Studio v7.8.0 I chose Files>New Sample Project>Sample UI project(Healthcare). I created a project HealthcareTest. In the project I find a Test case Test Cases/Main Test Cases/TC1_Verify Successful Login. I can open it with Editor in Script mode as well as in Manual mode.

Then I open the project with my favorite editor Emacs, l find a file:

  • <projectDir>/Libs/TempTestCase1608161020295.groovy.

The file contains lines like this:

TestCaseMain.runTestCase(
    'Test Cases/Main Test Cases/TC1_Verify Successful Login',
    new TestCaseBinding('Test Cases/Main Test Cases/TC1_Verify Successful Login',[:]),
        FailureHandling.STOP_ON_FAILURE , false)

Here you can see that a Test Case code is read and processed as a text file. I mean, the Test Case code is NOT immediately compiled and execute by the Groovy runtime.

I guess, Katalon Studio reads the Test Case code as text and performs an Abstract Syntax Tree Transformation. Why Katalon Studio does AST here? — I do not know. All I guess is that the Manual mode of the Editor requires the AST.

The Katalon Studio reads and parses a Test Case script as a text. Understand? So KS defines the syntactical rules allowed in the input. KS reads a text expecting it to be like Groovy but not 100% pure. Somehow KS is designed to be ignorant of @TypeChecked in a Test Case script. Therefore, when KS finds the annotation in the input text, it gets confused.

Alles klar!

Understood. The KS preprocessor doesn’t understand @TypeChecked and there is no need for it too.

I don’t think I asked my question clearly. I didn’t mean why doesn’t TestCase understand TypeChecked , I meant why does TestCase not require type casting while the Groovy class does. I think the answer is still the same. KS doesn’t need me to type cast then it doesn’t throw an error.

As long as the precompiler is happy then I’m happy. :slight_smile: