Another success with Katalon Studio

Previously I made mentioned that we migrated from one web platform to another and Katalon was instrumental in running hundreds of tests to ferret out where we had data or code issues.

Right on the heels of that migration, we needed to do an a framework upgrade. In essence we had to run the same validation tests again to confirm we didn’t have any code or data issues.

The test suite has grown and includes several new tests, but still takes less than 10 minutes to run. Plus, when using the data driven test case I discussed earlier, this can be run for dozens of passes, one after the other, and we just check the Reports folder to see if there were any problems.

At the customer site, their QA resource wanted a minimum of a week to confirm the framework upgrade. I have to admit, my jaw dropped. I didn’t understand why it would take so long to go through a dozen or so passes with a mixture of users.

Then it dawned on me. He needs to validate the site manually as they aren’t using any automated methods. He needs to click each page, fill in the forms, drill down through each subpage and confirm everything loads and is visible. He then needs to compare data on one page to the information on another and calculate the totals of multiple columns.

Based on other commitments, that may only be 1 or 2 validation passes per day. In order to feel comfortable, they would need to confirm at least a dozen, and the more the better. The time quickly adds up and a week might only get the bare minimum done.

With the help of Katalon and what we have in place, I can perform a dozen validations per day, while I work on other projects. The tasks can be run in the background, on another screen or even headless and I just have to check the reports.

Since I’ve run these tests dozens of times already, I know what the reports should look like, so I can easily pick out any anomalies.

We are continually developing and refining our tests, but the time investment is paying off with multiple hours saved per validation pass. At our current rate, we only need a couple of hours to validate 90% of the site. That last 10% is for validating against source data. But since so much time is saved up front, even with that manual 10%, we can do all our validation and be confident in what we deliver within a day.

Plus, our development time is getting shorter each iteration as the code gets better and tighter and common routines get grouped together. Katalon is making some serious strides for us and to be honest, I feel we’ve only scratched the surface. I’m very excited over what we will have in place 6 months from now.

Other articles of interest:

Getting the number of pages in a pagination ribbon

For a recent test, I needed to determine the number of pages available in a pagination ribbon. My goal was to make sure I could go from the first page to the last page and back again. This would validate the pagination ribbon was working and would have a different number of pages for different filtered results.

As a simple test, I read the first name on the page, jump to the end, read the name on the page and make sure the two are different. When I get back to Page 1, I read the first name again and make sure it’s the same name as when I read it the first time.

To start with, the pagination ribbon was a group of List Items with the ul and li tags. I first tried to work with it as an object, which will work, but in order to count the number of pages, I accessed it with the webdriver. I will still need to access the pagination ribbon as an object so I can click the correct page.

To illustrate, the pagination ribbon looks like this:


The pagination ribbon is defined as:


In order to work with it later, I defined an object as:


To count the number of LI items and thus number of pages, I used this:

WebDriver driver = DriverFactory.getWebDriver()
//Determine the number of elements available in the pagination ribbon
WebElement Webtable=driver.findElement("root"));
//Get the number of list items in the ribbon and turn it into a List
List<WebElement> TotalRowCount=Webtable.findElements(By.xpath("//*[@id='root']/div/div/div[2]/div/div/div[4]/ul/li"));

Now I have the total number of pages contained within the ribbon and the range I can move around in. Since the LI element accepts a variable as part of the object, I can jump to any page I choose.

I then use this code to jump to the end.

//Click the last page on the ribbon
lastPage=WebUI.getText(findTestObject('Page_/Dashboard/link-Pagination Ribbon', [('Variable') : (lastPageOfPagination-1)]))

This code gets me back to the first page:

//Return to page 1 of the pagination ribbon'Page_/Dashboard/link-Pagination Ribbon', [('Variable') : startOfPagination]))

Because a filter can return zero results, I added some logic to force the upper and lower boundaries. For my site, the ribbon still displays for no results with the symbols for first and last page. For that case, I still get the upper limit as listed above, but then subtract 1 to show the lower limit.

Based on the number of our pagination ribbon, the code looks like this:

if (lastPageOfPagination<=4){
} else {

When there are results, Page 1 shows at position 3. When there are no results, pagination starts at position 2.

Ribbons may act differently, but it should be possible to count them using the webdriver and know exactly how many pages you are working with.

Other articles of interest:

Using TypeIt4Me with Katalon Studio

In an previous article, I made comment of TypeIt4Me as a helpful tool to work alongside Katalon Studio. After several months, I have a full library of code snippets tucked away in TypeIt4Me, that allow me to put tests together much faster. In essence, I have automated parts of my automation code.

TypeIt4Me is a text expander that allows me to type a single keyword and have it converted to a block of code. In most demos you see, the example is to type in something like “ttyl” which converts to Talk to you later. Or an “addr” abbreviation gets converted to:

1313 Mockingbird Ln
Anywhere ST, 90210.

These are fine examples, but code snippets are just as valid and save a huge amount of time.

For example, I have the keyword replace@ set up as:

tempText=tempText.replaceAll("[\$,]", "")

I can also type in for@ and get:

for (loop = 1; loop <=10; loop++) {

The amount of expanded text can be just about anything. I also have one for the “lorem ipsum” text. I type in lorem@ and I get:

Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Sed posuere consectetur est at lobortis. Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Sed posuere consectetur est at lobortis. Etc, etc, etc, for another couple paragraphs.

It could also be more meaningful code like reading the contents of a table using the web driver code, as in this example:


WebDriver driver = DriverFactory.getWebDriver()
WebElement Webtable=driver.findElement("sales_dash_table")); // Replace TableID with Actual Table ID or Xpath
//Get the number of rows in the table and turn it into a List
List<WebElement> TotalRowCount=Webtable.findElements(By.xpath("//*[@id='sales_dash_table']/tbody/tr"));
//Display the number of rows in the table for the given sales rep
log.logWarning("No. of Rows in the WebTable: "+TotalRowCount.size());
//Loop through the table and output the information to Log File
//Read columns 1-4, assign each to a variable, then output the result to the Log File
for (loop =1;loop<=TotalRowCount.size();loop++)
companyName= driver.findElement(By.xpath("//*[@id='sales_dash_table']/tbody/tr[" + (loop)+ "]/td[1]")).getText();
log.logWarning('Company Name:=' + companyName)
sales= driver.findElement(By.xpath("//*[@id='sales_dash_table']/tbody/tr[" + (loop)+ "]/td[2]")).getText();
log.logWarning('Sales Figure Amount:=' + sales)
gp= driver.findElement(By.xpath("//*[@id='sales_dash_table']/tbody/tr[" + (loop)+ "]/td[3]")).getText();
log.logWarning('Gross Profit:=' + gp)
margin= driver.findElement(By.xpath("//*[@id='sales_dash_table']/tbody/tr[" + (loop)+ "]/td[4]")).getText();
log.logWarning('Margin % :=' + margin)

This is exceptionally faster than copy/paste and even if these snippets don’t turn out to be ones I use every day, I have a library of examples all in one place. For many, the only thing I have to change is the variables.

If you notice, each keyword has the @ symbol at the end. This is something I chose to make sure the text isn’t expanded accidentally. It purposefully denotes in my mind that I am inserting text and is a simple keystroke to add.

The other benefit of an program like TypeIt4Me, is that it’s available system wide. Atom and other editors can store snippets just as easily, but TypeIt4Me is available in all apps. I can use it within Katalon, within Atom, within Textmate, within Jira, within Github and everywhere else I work.

Text expanders aren’t just for writing emails or expanding the odd abbreviation here and there. They can be extremely power and beneficial to write commonly used code fragments and as a repository of useful code. TypeIt4Me says I have saved over a dozen hours of typing using this method.

Other articles of interest:

Recovering from Divide By 0 and Coming Back From Infinity with IsNaN and IsInfinite

While doing a series of regression tests, I noticed a few tests displayed errors due to a returned result of NaN. When I checked the test itself, it was for a margin calculation, and in some cases, one of the values was zero. This caused a divide by zero error, which returns NaN as a result. If this happens on the site, a 0.0% is displayed, but my test didn’t handle it correctly.

There would be two ways to approach this. One is the detect zeros before doing a divide and set the result to 0. This forces the result to agree with the site.

Another method is to use the isNaN function of Groovy. The calculation code stays the same, but the result is checked to see if it’s a number. For my situation, if the results is NaN, I set the answer to 0.0 to match the site result.

My formula is the following:

float calculatedMargin=(((Float.valueOf(GP) / Float.valueOf(sales)) * 100).round(1))

While it wouldn’t be hard to check if the value of GP or Sales is 0, I prefer to check the result at the end of the calculation using the following:

//If the result is NaN, or Infinity, set the calculatedMargin value to 0.0

if (calculatedMargin.isNaN()==true){
if (calculatedMargin.isInfinite()==true){

You’ll notice there is an isInfinite check. After correcting the NaN issue, I noticed the calculation could also return “Infinity” as a result. This is basically the other side of the coin when doing calculations with zero. If detected, this check sets the calculatedMargin to zero.

Both of these division errors are now handled by built in functions. Again, I could try and prevent the error in the first place by checking for zero values before doing any calculations. But, I prefer the second approach and just check the result. I could turn this validation into a Keyword, pass the calculated result, and use the validation in multiple places. That might be more efficient way of detecting and controlling the error.

I saw many solutions to this problem, but Groovy has these built in functions that handle the situation nicely and my false positive errors have been handled.

Other articles of interest:

Checking for Page Load with a Custom Keyword

While looking through my code, I decided to set up a single validation test that would check to make sure the page I wanted to work with loaded correctly. Instead of repeatedly using 10-15 lines to do it a few different ways, it seemed the better choice would be to create a Custom Keyword and use one line of code to call it each time.

To that end, I set up this simple, but rather effective Custom Keyword that looks for header text on the page I’m trying to get to. I set up the test to accept my chosen text as a parameter so I can pass it anything.

For each page I go to, there is some sort of header text that identifies the page. It may say Profile or Customer or Sales, but there is something I can use for validation.

I created the following Custom Keyword that simply looks for the header text I pass to it. For example, when the page is loaded, look for the text My Profile on it. If it’s there, the page loaded and the text will execute as expected.

If that text doesn’t appear, meaning some sort of problem has occurred, I get the title of the page, log an error and stop execution. Again, it’s a pretty simple test, but it’s proving quite effective.


def checkPageLoad(String findText) {
/* Confirm the correct page has loaded by looking for the requested text
* The search text is passed to the Keyword from the calling statement
* If the text is missing, determine the kind of error and display more meaningful text
def elementVisible = WebUI.verifyTextPresent(findText, false, FailureHandling.OPTIONAL)
if (elementVisible == false) {
//Get the title of the page and determine the kind of error
def title = WebUI.getWindowTitle()
log.logError('ERROR: The requested page did not load with the following error:= ' + title )
if (title=='There was an error'){
log.logError('ERROR: There is a Data Inconsistency Error')
} else {
log.logError('ERROR: The page could not be found - 404 error')
log.logWarning('--- The test ended unexpectedly with errors ---')
KeywordUtil.markFailedAndStop('ERROR: Unable to load the requested page - Test has failed')

To quickly explain the test:

It uses the WebUI.verifyTextPresent to find the text I passed.

If that text does not appear, it gets the WindowTitle which has an error message.

Based on the page title, one of two error conditions has occurred.

An error notice is written to the log file and the test is marked as Failed.

To call the Keyword and pass it the text I’m expected, I use this:

CustomKeywords.'errorCheck.validateSalesDashboard.checkPageLoad'('My Profile')

If the words, “My Profile” appear on the page, the test runs as normal. If they are missing, the error messages are logged and the test is halted. This gives me a way to make sure each page I interact with loads correctly and that the test is working with the correct page.

This Keyword is now called dozens of times from within my Test Cases. Additionally, I can change this in one source file rather going to each to make a modification. I have saved time and shaved off a few hundred lines worth of code.

Other articles of interest:

Recent Comments