How to create java function

Hi,

I need to create a the function below to call in a test case. I believe this needs to be created as a keyword, however, I am not a coder/scripter and needs guidance on how to format this in the keyword function.

function contains(selector, text) {
const elements = document.querySelectorAll(selector);
return Array.from(elements).filter(function(element) {
return RegExp(text).test(element.textContent);
});
}

Any help would be appreciated.

Okay, we can do that.

If you only need to call it in one test case (like you said above) you don’t need to create a keyword. However, if you think you might use it in more test cases, then yes, a keyword would be a good idea.

Just so you know and understand, the code you provided is JavaScript, not Groovy.

Katalon can only use JavaScript by asking the browser to execute it – I normally use WebUI.executeJavaScript() to do that.

In your Test Case, add this code:


// Note the js variable uses THREE single quotes!
String js = '''
return contains(arguments[0], arguments[1]);
function contains(selector, text) {
    const elements = document.querySelectorAll(selector);
    return Array.from(elements).filter(function(element) {
        return RegExp(text).test(element.textContent);
    }); }
'''
WebUI.executeJavaScript(js, Arrays.asList(your_selector, your_text))

The NEW code is highlighted in bold. You will need to replace your_selector and your_text with the selector and text in your test.

Let me know if you’d like to make this a keyword or a method you can call from any test case.

@Russ_Thomas
Russ,

Thank you for your response, yes ideally, I would like make it a key word and call if from any test case. For more information, I will need to do the following in a specific test case

Const label = document.evaluate(//label[contains(., 'Current state')], document, null, XPathResult.ANY_TYPE, null ).iterateNext()

const control = label.closest(".MuiFormControl-root");
const openButton = control.querySelector("[title=‘Open’]").click()

document.querySelector(".MuiAutocomplete-popper li:first-child").click()

I will have to run similar actions for other fields within the UI.

Thanks again!

@Russ_Thomas
I don’t know if you saw my last post. I added the @ after I posted my response.

So I will need to call the function/method in multiple test cases.

Thanks!

Good Morning,

Is there anyone out there that can help?

Read the below to begin with. See if that helps in creating the “new” sheet you need for your keywords. Then it’s a simple copy and paste with some amending to finish it up.

@grylion54

Thank you.

I have the keyword create with this
String js = ‘’’
return contains(arguments[0], arguments[1]);
function contains(selector, text) {
const elements = document.querySelectorAll(selector);
return Array.from(elements).filter(function(element) {
return RegExp(text).test(element.textContent);
}); }
‘’’

I believe the WebUI.executeJavaScript(js, Arrays.asList(your_selector, your_text)) needs to be in the test case that needs to call the method.

I was also hoping for help with the following steps for 1 of my test cases after I call the method:
//Find the contains helper
const label = contains(“label”, “Current state”)[0]

//Find the ‘Open’ button
const control = label.closest(".MuiFormControl-root");

//Click the first item
const openButton = control.querySelector("[title=‘Open’]").click()

Back to your keyword, can you display your “calling” statement and the “header” of your @Keyword so we can review and agree its proper? This is the “amending” that I mentioned in my prior post.

package create_Function

import static com.kms.katalon.core.checkpoint.CheckpointFactory.findCheckpoint
import static com.kms.katalon.core.testcase.TestCaseFactory.findTestCase
import static com.kms.katalon.core.testdata.TestDataFactory.findTestData
import static com.kms.katalon.core.testobject.ObjectRepository.findTestObject
import static com.kms.katalon.core.testobject.ObjectRepository.findWindowsObject

import com.kms.katalon.core.annotation.Keyword
import com.kms.katalon.core.checkpoint.Checkpoint
import com.kms.katalon.core.cucumber.keyword.CucumberBuiltinKeywords as CucumberKW
import com.kms.katalon.core.mobile.keyword.MobileBuiltInKeywords as Mobile
import com.kms.katalon.core.model.FailureHandling
import com.kms.katalon.core.testcase.TestCase
import com.kms.katalon.core.testdata.TestData
import com.kms.katalon.core.testobject.TestObject
import com.kms.katalon.core.webservice.keyword.WSBuiltInKeywords as WS
import com.kms.katalon.core.webui.keyword.WebUiBuiltInKeywords as WebUI
import com.kms.katalon.core.windows.keyword.WindowsBuiltinKeywords as Windows
import org.openqa.selenium.JavascriptExecutor as JavascriptExecutor

import internal.GlobalVariable

public class function {
String js = ‘’’
return contains(arguments[0], arguments[1]);
function contains(selector, text) {
const elements = document.querySelectorAll(selector);
return Array.from(elements).filter(function(element) {
return RegExp(text).test(element.textContent);
}); }
‘’’
}

Just a couple of changes perhaps. On the “Introduction to Custom Keyword” link that I gave in my last post, there is an example of a custom keyword. Notice the @Keyword at the top. This is necessary for your method to become a Custom Keyword!

@Keyword 
def keywordName(parameters…) {
// enter your code here
// you can use either Groovy or Java
}

Also, notice the “(parameters…)” part in the custom keyword example above. You need to “pass into” the method here with the parameter list you will have in your “calling statement”, like

CustomKeywords.'create_Function.function.Meths'(selector, text)

So, give your Custom Keyword a “method name” in place of the keywordName in the example above, like I used “Meths” --but be more descriptive of what your method is supposed to do (and not “function” either on basic principle).

Hmmm
public class function {

@Keyword 
def keywordName(String selector, String text) {
   String js = '''
   return contains(arguments[0], arguments[1]);
   function contains(selector, text) {
   const elements = document.querySelectorAll(selector);
   return Array.from(elements).filter(function(element) {
   return RegExp(text).test(element.textContent);
   }); }
   '''
}
}

And let’s make a call out to @Russ_Thomas to assist you for your “return” type and parameters.

@davina.meyer

Sorry for the delay, I completely missed this. (Thanks for the shout out @grylion54)

  1. Make a new package, call it com.davina.meyer
      – or com.your_company_name if you prefer

  2. In the new package, make a new class (custom keyword in Katalon) call it utils

  3. Make the code inside the utils class look like this:


package com.davina.meyer

// imports here

public class utils {

  static boolean contains(String selector, String text) {

    String js = '''
      return contains(arguments[0], arguments[1]);
      function contains(selector, text) {
        const elements = document.querySelectorAll(selector);
        return Array.from(elements).filter(function(element) {
          return RegExp(text).test(element.textContent);
        }); 
      }
    '''
    return (boolean) WebUI.executeJavaScript(js, Arrays.asList(selector, text))
		
  } // contains method

} // class utils

  1. In your test case…
import static com.davina.meyer.utils.*
// other imports here

// Test case steps here

//call your new contains method
if(contains(your_selector, your_text)) {
  println "It works!"
} else {
  println "nope, not found"
}
  1. You don’t need @Keyword because we’re using static code.

  2. Caveat. I did not vet or test the code inside the contains() method - that’s your code :wink:

@Russ_Thomas and @grylion54
Thanks. I will give it a try.

@Russ_Thomas
So this is what I have come up with so far in the test case:

if(contains('label', 'Hometown state')) {
	println "It works!"
  } else {
	println "nope, not found"
  } //  

This works :slight_smile:

WebDriver driver = DriverFactory.getWebDriver()
def label = contains ("label", "Hometown state")
def control =  driver.findElements(By.className('MuiFormControl-root MuiTextField-root MuiFormControl-marginDense MuiFormControl-fullWidth')) + "/label"
def openButton =  driver.findElements(By.xpath('//*[@title="Open"]')) + "/control"
openButton.click()

Everything passes until I try to click on the last def. I can tell that it is not correct because the click() is underlined

Error: Reason:
groovy.lang.MissingMethodException: No signature of method: java.util.ArrayList.click() is applicable for argument types: () values: []
Possible solutions: clear(), clear(), clear(), clone(), wait(), size()

I need to click on the button to open the dropdown list, any suggestions?

Thanks!

Just a note that you should put 3 backticks (found on the same key as the tilde) above and below your code, like ```

if(contains('label', 'Hometown state')) {
   println "It works!"
} else {
   println "nope, not found"
} // This works :slight_smile:

WebDriver driver = DriverFactory.getWebDriver()
def label = contains ("label", "Hometown state")
def control = driver.findElements(By.className('MuiFormControl-root MuiTextField-root MuiFormControl-marginDense MuiFormControl-fullWidth')) + "/label"
def openButton = driver.findElements(By.xpath('//*[@title="Open"]')) + "/control"
openButton.click()

One concern I have is that your method, contains, returns a boolean data type? If you want label to be a WebElement, then you are going to have to change what you have, like maybe:

WebElement label = driver.findElement(By.xpath('//label[contains("Hometown state")]'))

or

def label = driver.findElement(By.xpath('//label[contains("Hometown state")]'))

You are using “findElements” (plural) so are you expecting more than one, like a List<WebElement>? If not, use “findElement” (singular).

@davina.meyer I edited your post to put in ``` (three backticks) like @grylion54 mentioned. If you edit it, you can see what I did.

I think you’re missing a key point

– the JavaScript code needs to be executed by the browser. that’s why it is sent as a big string inside triple quotes.

– the rest of the code is groovy code, executed by Katalon.

To click on a button in groovy code, use WebUI.click(your_button_object)

I feel I should make you aware, I’m not following your actual code, just the machinations of trying to incorporate JavaScript in your Test Case.

@Russ_Thomas
I don’t disagree that I don’t understand. Again, I am new to automation and scripting. The code I have was provided to me by a developer, I did not come up with it.

I have the keyword configured like your example and import it in my test case.

What I am trying to is find the label of Hometown state, the go to related field and click the open button

I really do appreciate your help! I am hoping that once I get this working then the other fields like this will be easier.

You might try:

def button = driver.findElement(By.xpath('//button[@title="Open"]'))

or

def button = driver.findElement(By.xpath('//label[text()="Hometown state"]/following-sibling::div[1]/div[1]/button[@title="Open"]'))
xpath summary

start at the label, “Hometown state”, then move to the first “sibling” <div> right below, then down a level to the first <div> with class=“MuiAutocomplete-endAdornment”, then down to the second button, with title= “Open”

or

def button = driver.findElement(By.xpath('//label[contains(text(),"Hometown state")]/following-sibling::div/div/button[2]'))
1 Like

@grylion54
Thank you! I was able to click the open button and select a state.

This has been a good Monday morning :slight_smile:

Again thanks for all your help. Happy holidays!