I am using Katalon Studio, and need to retrieve some sign-up link from test email inbox. I found some API/service to access the test email inbox, can get the message I need from it, and it's a string of what looks like HTML.
I don't care about the HTML, I just want to "click on" the link in that email message!
How do I do that!?
Assuming you successfully have the message string, here's how you can retrieve the link from it, assuming that your email message retrival method call returns HTML string.
To save you some clicking:
import javax.xml.parsers.DocumentBuilderFactory
import javax.xml.xpath.XPathFactory
import org.w3c.dom.Element
// feel free to make this your own :)
public final class EmailUtils {
/**
* **NOTE**: forked from https://stackoverflow.com/a/2269464/2027839 , and then refactored
*
* Processes HTML, using XPath
*
* @param html
* @param xpath
* @return the result
*/
public static String ProcessHTML(String html, String xpath) {
final String properHTML = this.ToProperHTML(html);
final Element document = DocumentBuilderFactory.newInstance()
.newDocumentBuilder()
.parse(new ByteArrayInputStream( properHTML.bytes ))
.documentElement;
return XPathFactory.newInstance()
.newXPath()
.evaluate( xpath, document );
}
private static String ToProperHTML(String html) {
// SOURCE: https://stackoverflow.com/a/19125599/2027839
String properHTML = html.replaceAll( "(&(?!amp;))", "&" );
if (properHTML.contains('<!DOCTYPE html'))
return properHTML;
return """<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head></head>
<body>
${properHTML}
</body>
</html>
""";
}
}
From there, you'll have to log out your HTML message string (or put debug breakpoint around your method call and extract it from debugger), pretty print it, and from there, you can use your web-testing skills to create some xpath selector string for the actual link.
Then, you use my code like:
WebUI.navigateToUrl(yourEmailMessageContent, "${yourLinkXPath}/@href");
To be fair, email messages can take some time to hit inboxes. Hence you might also want to have some retry logic in place. Here is example from my real project code base:
import java.util.concurrent.TimeUnit
// ...rest of imports
public final class EmailUtils {
//...rest of code base
public static String ExtractSignUpLink() {
String link;
int retryAttempts;
ActionHandler.Handle({
link = this.ProcessHTML(this.GetLatestMessageBody(30),
"//a[.//div[@class = 'sign-mail-btn-text']]/@href");
}, { boolean success, ex ->
if (success)
return;
// handle ex
if (((GoogleJsonResponseException)ex).getDetails().getCode() >= 400)
throw ex;
sleep(1000 * 2**retryAttempts++);
}, TimeUnit.MINUTES.toSeconds(15))
return link;
}
//...rest of code base
}
public final class ActionHandler {
public static void Handle(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);
}
}
}
}