Selenium

Changing the scope of a variable to be available within a Method

After reading the value from a dropdown, I wanted to use that piece of information for a comparison test in another part of the Test Case. That's not a problem, except that I want to use the variable within a defined Method within the test case. I've done this sort of thing before and passed the needed values to the method. The Method didn't need any parameters, so I looked for another way to make that variable more "global" in scope.

Turns out this can be done using @Field

The first step is to import the correct library

import groovy.transform.Field

From there, "flag" the corresponding variable and change it's scope.

@Field String quoteBranchName
quoteBranchName=allQuoteBranchesList[0]
log.logWarning('The listed Branch in the quote is: ' + quoteBranchName)

That variable can now be referenced within a Method defined within that same Test Case

def addInventoryItem() {
    log.logWarning('The listed Branch in the quote is: ' + quoteBranchName)
        if (inventoryLocations.contains(quoteBranchName)==false){
        log.logError("The Inventory Item does not match the Branch Location")
    }
}

This is the first time I've needed to make this kind of reference. The verdict is still out on whether this is "cheating" or not :), but it gets the job, so I'm going with it.

Other articles of interest:

Reading text of the currently selected value from a dropdown list

I was recently working on a test case where I needed to use the default value from a dropdown. For my case, I wanted to know the default location of the user. The dropdown value is set through Javascript and a query. Since it has a default, I didn't want to set it, I wanted to know what that default was. This turned out to be a little more problematic than I thought.

My first attempt was to use .getAttribute which has worked for other fields.

String branchLocation = WebUI.getAttribute(findTestObject('Dropdown Location'),'value') returns
c6f25c57-47a7-4ae3-b269-a57567faa23f which is a GUID and can't be translated into anything I can work with.

I then tried it with getText which does work, but brings back all the options available in the dropdown, not just the currently selected one.

String branchLocation = WebUI.getText(findTestObject('Dropdown Location'))

This returns

Location #1
Location #2
Location #3
Location #4
Etc

This is better, but is clearly more information than I want. All I want is the first entry. With that in mind, the String is turned into a List with a split on the CRLF that exists at the end of each line. This gives one entry for each index of the List

String allBranchLocations = WebUI.getText(findTestObject('Dropdown Location'))
List allBranchesList=allBranchLocations.split("\\r?\\n") //Remove CRLF from each dropdown entry
String branchName=allBranchesList[0]

With that little conversion, branchName contains the first item from the dropdown, which is the default value. This can now be used for my comparison. This may not be the best way to get the first item, or perhaps the most reliable, but it works situation and is easier than some of the other solutions I saw offered up.

Other articles of interest:

Getting started with Katalon Studio

You don't have automate an entire website to gain a benefit from automation. Even for yourself, there are plenty of ways Katalon Studio can help you save time. One of the main goals of automation is to perform repetitive tasks and emulate the same functions you do on a daily basis. And on one of the best places to start is filling in forms.

Entering form data is by no means a difficult job, but it's tedious and after a couple of passes, you really don't care what you type as long as the field isn't blank. Plus, it can be a waste of time. If it takes 5 minutes to fill in a form accurately and wait for it to save, that's roughly 10 forms an hour. And that's an hour that can be invested in something more meaningful.

With some simple automation code, filling in the entire form can be reduced to 30 seconds. Plus, it will be filled out correctly each time with predictable data you can search for and confirm exists. So instead of spending 5 minutes for each form, it would be possible to create 10 contacts in 5 minutes, or 10 times the amount of work with 1/10th the effort. And that savings of nearly 45 minutes can be put toward other projects like training, self-study, or for improving the automation code itself.

Filling in form data is one of the easier tasks to accomplish with automation. In most cases, the objects will follow a similar naming pattern such as:

css=input[name="contact_email"]
//div[@id='add-Contact']/form/input[7]

It would be a matter of copy/paste to change the xpath to the correct name, or use a variable for multiple inputfield objects.

The same should be true for entering text:

WebUI.setText(findTestObject('Object Location/inputfield-Contact-Contact Email'), 'user@domain.com')

After creating one SetText entry, copy/paste the rest, change the object and entered text and the job is done.

With a little bit of prep work, it would be possible to spend an hour or so and put together a script that will give a return on the time investment after the first couple of runs. And keep giving back time every time it's run.

Running the Test Case to create a new contact is something I run regularly. I can make dozens of entries while working on something else. That is a very big win in my opinion.

The core of the script could be some as simple as:

WebUI.setText(findTestObject('Object/inputfield-Contact-First Name Last Name'), 'Bob Smith')
WebUI.setText(findTestObject('Object/inputfield-Contact-Role or Title'), 'Customer Title)
WebUI.setText(findTestObject('Object/inputfield-Contact-Contact Phone'), '5552221112')
WebUI.setText(findTestObject('Object/inputfield-Contact-Contact Mobile'), '5553331113')
WebUI.setText(findTestObject('Object/inputfield-Contact-Contact Office'), '5554441114')
WebUI.setText(findTestObject('Object/inputfield-Contact-Contact Email'), 'user@domain')
WebUI.setText(findTestObject('Object/inputfield-Contact-Address Line'), '12 West Upper Court')
WebUI.setText(findTestObject('Object/inputfield-Contact-City'), 'Tempe')
WebUI.setText(findTestObject('Object/inputfield-Contact-State'), 'AZ')
WebUI.setText(findTestObject('Object/inputfield-Contact-Zip Code'), '85281')
WebUI.setText(findTestObject('Object/inputfield-Contact-Phone Number'), '3335551212')
WebUI.setText(findTestObject('Object/inputfield-Contact-Email Address'), 'user@domain.com')
WebUI.click(findTestObject('Object/btn-Contact-Save Button'))

Other articles of interest:

Simple wildcard searches for pattern matching

For a search test I was working on, I needed to verify what was returned for the name of a warehouse location. Normally the .contains command would be used, but for this test, I needed to check for multiple criteria. I need to check the warehouse is assigned to a certain coast and contains certain city values. The warehouse could be East or West with several city names listed afterward in any given order. For example, the warehouse location could look like:

String branchName="Warehouse East #585 Palm Beach, FL Charlottesville, VA Nampa, ID Charlottesville, VA"
String branchName="Warehouse West Los Angeles, CA, San Francisco, CA, San Diego, CA"

I want to verify "Warehouse East" is part of the text and I want to verify "Palm Beach" is in the text. Since these two strings are not next to each other and the city could appear anywhere on the line the .contains will not work in this instance.

However, the .matches command can be used which supports the wildcards, * and ?. The usage is the same as we see for filenames. For example *image* matches all filenames with the word image such as image, images, fileimage. The only difference is we have to "escape" the wildcard with the use of .*

With that in mind we can make the following command verify our chosen text strings exist in the returned result.

println(branchName.matches("Warehouse East .*Palm Beach.*"))

To use the single wildcard .? we could write the line as:

println(branchName.matches(".?arehouse .?ast .*Palm Beach.*"))

This ignores the case for the W and E, so Warehouse East is the same as warehouse east

It is also possible to use a more "regex" style and write the above line as:

println(branchName ==~/.?arehouse .?ast .*Plam Beach.*/)

This falls into the brute force category of pattern matching, but I have pretty simple needs and taking the time to write a custom parser isn't necessary and ins't in the cards.

Other articles of interest:

Create a Dynamic Object at Runtime

I'm not quite at the point to need to make an object outside of the Object Repository, but I've seen reference to it multiple times and wanted to put together a simple example because who knows when it might come up. There have been several comments about keeping the size of the Object Repository small so it's better to programmatically create a one-off object rather than commit it to the project.

Katalon Studio allows creating objects during runtime through the TestObject library.

import com.kms.katalon.core.testobject.TestObject as TestObject
import com.kms.katalon.core.testobject.ConditionType

The object is created by giving it a name and associating a property to it. In the very simple example below, "xpath" is set with the location of a tab on the page.

TestObject is created with the name "dynamicObject"

The "dynamicObject" is given an xpath value that equals the contents of the xpath String

Once the object has been created, it can then be clicked.

The main work is done through this command:

TestObject dynamicObject = new TestObject('dynamicObject').addProperty('xpath', ConditionType.EQUALS, xpath, true)

xpathOfObject="//a[contains(text(),'Contacts')]"
TestObject dynamicObject = new TestObject('dynamicObject').addProperty('xpath', ConditionType.EQUALS, xpathOfObject, true)

WebUI.click(dynamicObject)

There is one important thing to note, since this object is not part of the project Object Repository, the call to manipulate it is slightly different. Note there is no, findTestObject, or the path of the object as part of the command. If the object were part of the project, the command would look like this:

WebUI.click(findTestObject('Project/Customer Profile/Tabs/tab-Contacts'))

The same would be true if this object were passed to a Custom Keyword:

WebUiCommonHelper.findWebElement(objectReference,5)
vs

WebUiCommonHelper.findWebElement(findTestObject(objectReference,5))

Again, I don't know that I have a use case for this scenario, but others have brought it up, and Katalon fully supports it. A dynamic object is quite an easy thing to create and the only real change is how the object is referenced by telling Katalon not to look in the Object Repository, but "locally" if you will.

Other articles of interest:

Recent Comments

  • Simple wildcard searches for pattern matching (2)
    • Don Pedro: For that scenario it seems .contains would be your choice. For example, variable.contains(‘amazo n.com’) to see if the url had amazon.com. In that case, www.amazon.com, forum.amazon.com, retail.amazon.com would all...
    • Jony: Hi, How can I use a wild card to assert a URL is the one I want. I just want to verify the domain ==expected but not anything after it. Tried * but not working and only works when I have full URL.
  • Create a Dynamic Object at Runtime (2)
    • Saish: How to add shadow root parent to this runtime object..
    • Jeremy Brien: I appreciate this! I saw this post on LinkedIn this morning and was able to find a use case for it! I found that defining my xpath with an iterable variable allows me to loop through and capture text from tables created...
  • Output status messages and test information by writing to the Log File Viewer in Katalon Studio (2)
    • Don Pedro: That would be things like: log.logWarning(‘The import date listed on the site is: ‘ + importDate) log.logWarning(‘The value from the site is: ‘ + salesFigure) log.logWarning(‘Filter Results for ‘ +...
    • Prashant Pednekar: Thanks for the informative article but can we also put some variable values to make it more exciting.
  • Setting up a repeatable Search Method in Katalon Studio (1)
    • RJ: Thanks a lot! This is very helpful 🙂
  • Filling forms with random numbers in Katalon Studio (3)
    • Patrick Clough: We created a handy random string generator custom keyword. The method takes in a string for the type of string you want, and an integer for the length. Looks like this: static String RANDOM_ALPHANUM =...
    • Don Pedro: randomNumber is the variable that holds the result of generating a new random number. Depending on how things work on your site, you might need to convert the number to a String before it’s recognized correctly....
    • Seth: When you are setting up randomNumber is this a new keyword or a new variable? I am trying to randomly generate unique socials and can’t seem to connect my generator to my Set Text.
  • Working with Dates and Date Formatting in Katalon Studio (5)
    • Ann: THANK YOU ! That worked perfectly !
    • Don Pedro: import groovy.time.TimeCategory currentDate = new Date() println currentDate use( TimeCategory ) { after30Mins = currentDate + 30.minutes } println after30Mins https://stackoverflow.com/ques tions/21166927/incrementing...
    • ricky julianto nugroho: hay can u gave me an example for plus a hour in the time ? example : now is 15 pm i want to print 16 in the text thank you
  • Boostnote for Code Snippets (1)
    • Manual: Hi Don, Regarding the code snippets and examples that you have created. Is there any GitHub repo or something that can be shared? Thanks
  • Using TypeIt4Me with Katalon Studio (3)
    • Manual: That’s great thanks for sharing.