I think I found the issue in Katalon. They somehow removed the function to get the Y location of a TestObject. I assume it used to exist, because they have a function WebUI.getElementLeftPosition(), which is necessary for a more efficient image search. However, I implemented my own function to handle this whole workflow. There are external libraries that will give you more options, such as partial matches, but I just want an exact match to a subimage. Providing a TestObject as expected by Katalon (see previous comment) is supported and completed 6 seconds faster on my machine (1.5 seconds instead of 7.5). This function assume that the image to verify will be in the viewport, but I may add a step to scroll to the object if we end up needing it for stability.
@Keyword
def verifyImagePresent(TestObject imageObject) {
String imagePath = imageObject.getImagePath()
WebElement imageElement = getWebElementFromTestObject(imageObject)
Point location = imageElement.getLocation()
int offsetX = location.getX()
int offsetY = location.getY()
return verifyImagePresent(imagePath, offsetX, offsetY)
}
@Keyword
def verifyImagePresent(String imagePath) {
return verifyImagePresent(imagePath, 0, 0)
}
@Keyword
def verifyImagePresent(String imagePath, int offsetX, int offsetY) {
boolean matches = false
String screenshotPath = FileUtils.getAbsoluteFilePath(‘screenshot.jpg’)
String expectedPath = FileUtils.getAbsoluteFilePath(imagePath)
WebUI.takeScreenshot(screenshotPath)
BufferedImage img, subImage
try{
img = ImageIO.read(new File(screenshotPath))
} catch (IOException ioe) {
System.out.println(“Unable to open file: $screenshotPath”)
}
int imgWidth = img.getWidth()
int imgHeight = img.getHeight()
try{
subImage = ImageIO.read(new File(expectedPath))
} catch (IOException ioe) {
System.out.println(“Unable to open file: $expectedPath”)
}
int subWidth = subImage.getWidth()
int subHeight = subImage.getHeight()
for (int x=offsetX; x<=(imgWidth-subWidth); x++) {
for (int y=offsetY; y<=(imgHeight-subHeight); y++){
BufferedImage cmpImage = img.getSubimage(x, y, subWidth, subHeight)
if (bufferedImagesEqual(subImage, cmpImage)) {
matches = true
break
}
}
}
FileUtils.deleteFile(screenshotPath)
assert matches : “The images do not match”
return matches
}
private boolean bufferedImagesEqual(BufferedImage img1, BufferedImage img2) {
if (img1.getWidth() == img2.getWidth() && img1.getHeight() == img2.getHeight()) {
for (int x = 0; x < img1.getWidth(); x++) {
for (int y = 0; y < img1.getHeight(); y++) {
if (img1.getRGB(x, y) != img2.getRGB(x, y))
return false
}
}
} else {
return false
}
return true
}
@Keyword
public WebElement getWebElementFromTestObject(TestObject testObject) {
String xpath = getXPath(testObject);
return new WebDriverWait(DriverFactory.getWebDriver(), GlobalVariable.short_loading)
.until(ExpectedConditions.visibilityOfElementLocated(By.xpath(xpath)))
}