How you can retry actions in Katalon Studio

Problem

There can be many instances where you want to re-try a simple action, even part or all of a test case!

These could be:

  • performing a search for an item/member/user/order/… on a list page. In my real-life project, we’re looking up members and member leads, and then running some tests on those. They may or may not have already been created before looking them up on the AUT page.
  • hitting refresh button widget until an item/member/user/order/… appears.
  • pinging an email inbox until a certain email is found

As you maybe aware, Katalon Studio lacks built-in mechanism for retrying methods. So, how do we do it?

Solution

We create a really simple Custom Keyword for it! Let’s name it ActionHandler or something similar, and define it to be:

package com.signaturemd.utils

public class ActionHandler {
    public static void HandleRetryableAction(Closure onAction, Closure onDone, long timeOut) {
        long startTime = System.currentTimeSeconds();
        while (System.currentTimeSeconds() < startTime + timeOut) {
            try {
                onDone(true, onAction());
                return;
            } catch (Exception ex) {
                onDone(false, ex);
            }
        }
    }
}

How to use it

Now, when you go to use it, for example in your test cases, just be like:

ActionHandler.HandleRetryableAction({
    // the code for your action goes here
}, { boolean success, Object result -> 
    if (success) { 
        // any preparatory steps for the rest of the test case/method
        return;
    }

    // anything you need to do before re-trying the failed action goes here
})

Those brackets of code being passed in are called Closures, which are basically in this case callback functions. The callback signature must match that of its caller.

Also note that you can use the Golang-style _ to name a variable (and then not use it in that scope).

Oh, and you do NOT have to put the rest of the test case inside the onDone callback!

Example irl use cases

These are irl use cases of this util method…

Finding or creating a member

I have several test cases on different member types. If the member doesn’t exist in the lookup table, we go to convert them as member lead. That looks like:

BaseMemberModel model = new MemberFactory().createMainMember();

TestObject firstMemberLink = findTestObject('Page_Member List/Member Table/First Member Name link');

ActionHandler.HandleRetryableAction({
	MemberListPage page = new MemberListPage()
	page.go();
	page.initFilters(practiceProfile)
	
	page.applyNameFilters(model)
	
	// submit the filter info and click on the first entry that appear
	WebUI.click(findTestObject('Object Repository/Page_Zoho shared repository/CRM pages/Person List pages/Filter Sidebar/Apply Filter button'))
	
	page.waitForTableLoad()
	
	WebUI.verifyElementPresent(firstMemberLink, 2)
	
}, { boolean success, _ ->  
	if (success) { 
		WebUI.click(firstMemberLink)
		
		WebUI.waitForPageLoad(5)
		
		return;
	}

	SMDTestCaseUtils.ConvertMemberLead({
		return new MemberLeadFactory().createMainFamilyMemberLead();
	}, 
	model,
	practiceProfile,
	)
}, TimeUnit.MINUTES.toSeconds(6))

Handling e-mail message

I have an SMDEmailUtils in my code base, that has an ExtractSignUpLink(), defined to be:

	public static String ExtractSignUpLink() {
		String link;

		int retryAttempts;

		ActionHandler.HandleRetryableAction({
			link = this.ProcessHTML(this.GetLatestMessageBody(30),
					"//a[.//div[@class = 'sign-mail-btn-text']]/@href");
		}, { boolean success, ex ->
			if (success)
				return;
			if (ex instanceof HttpResponseException) { 
				final int errorCode = ((HttpResponseException)ex).getStatusCode();
				if (ex.isSuccessStatusCode())
					KeywordUtil.logInfo("Somehow, we got an exception, that has a success status code, with message: '${ex.getStatusMessage()}'");
				if ((errorCode < 400) || (errorCode >= 500))
					throw ex;
				
				this.handleUserHttpError(ex);
			}
			sleep(1000 * 2**retryAttempts++);
		}, TimeUnit.MINUTES.toSeconds(15))

		return link;
	}

1 Like

@Russ_Thomas I’m confused…how is this NOT “tips and tricks”?

1 Like

My bad :blush: