diff --git a/src/main/java/aquality/selenium/elements/interfaces/ByImage.java b/src/main/java/aquality/selenium/elements/interfaces/ByImage.java index 96bc864..97b8569 100644 --- a/src/main/java/aquality/selenium/elements/interfaces/ByImage.java +++ b/src/main/java/aquality/selenium/elements/interfaces/ByImage.java @@ -18,12 +18,12 @@ /** * Locator to search elements by image. * Takes screenshot and finds match using openCV. + * Performs screenshot scaling if devicePixelRatio != 1. * Then finds elements by coordinates using javascript. */ public class ByImage extends By { private static boolean wasLibraryLoaded = false; private final Mat template; - private final boolean doScaling; private static void loadLibrary() { if (!wasLibraryLoaded) { @@ -39,19 +39,8 @@ private static void loadLibrary() { * @param file image file to locate element by. */ public ByImage(File file) { - this(file, false); - } - - /** - * Constructor accepting image file. - * - * @param file image file to locate element by. - * @param doScaling perform screenshot scaling if devicePixelRatio != 1 - */ - public ByImage(File file, boolean doScaling) { loadLibrary(); this.template = Imgcodecs.imread(file.getAbsolutePath(), Imgcodecs.IMREAD_UNCHANGED); - this.doScaling = doScaling; } /** @@ -60,19 +49,8 @@ public ByImage(File file, boolean doScaling) { * @param bytes image bytes to locate element by. */ public ByImage(byte[] bytes) { - this(bytes, false); - } - - /** - * Constructor accepting image file. - * - * @param bytes image bytes to locate element by. - * @param doScaling perform screenshot scaling if devicePixelRatio != 1 - */ - public ByImage(byte[] bytes, boolean doScaling) { loadLibrary(); this.template = Imgcodecs.imdecode(new MatOfByte(bytes), Imgcodecs.IMREAD_UNCHANGED); - this.doScaling = doScaling; } @Override @@ -82,21 +60,14 @@ public String toString() { @Override public List findElements(SearchContext context) { - byte[] screenshotBytes = getScreenshot(context); - Mat source = Imgcodecs.imdecode(new MatOfByte(screenshotBytes), Imgcodecs.IMREAD_UNCHANGED); - long devicePixelRatio = (long) AqualityServices.getBrowser().executeScript(JavaScript.GET_DEVICE_PIXEL_RATIO); - if (devicePixelRatio != 1 && doScaling) { - int scaledWidth = (int) (source.width() / devicePixelRatio); - int scaledHeight = (int) (source.height() / devicePixelRatio); - Imgproc.resize(source, source, new Size(scaledWidth, scaledHeight), 0, 0, Imgproc.INTER_AREA); - } + Mat source = getScreenshot(context); Mat result = new Mat(); Imgproc.matchTemplate(source, template, result, Imgproc.TM_CCOEFF_NORMED); float threshold = 1 - AqualityServices.getConfiguration().getVisualizationConfiguration().getDefaultThreshold(); Core.MinMaxLocResult minMaxLoc = Core.minMaxLoc(result); - int matchCounter = (result.width() - template.width() + 1) * (result.height() - template.height() + 1); + int matchCounter = Math.abs((result.width() - template.width() + 1) * (result.height() - template.height() + 1)); List matchLocations = new ArrayList<>(); while (matchCounter > 0 && minMaxLoc.maxVal >= threshold) { matchCounter--; @@ -149,11 +120,20 @@ protected static double distanceToPoint(Point matchLocation, WebElement element) * Takes screenshot from searchContext if supported, or from browser. * * @param context search context for element location. - * @return captured screenshot as byte array. + * @return captured screenshot as Mat object. */ - protected byte[] getScreenshot(SearchContext context) { - return !(context instanceof TakesScreenshot) - ? AqualityServices.getBrowser().getScreenshot() - : ((TakesScreenshot) context).getScreenshotAs(OutputType.BYTES); + protected Mat getScreenshot(SearchContext context) { + byte[] screenshotBytes = context instanceof TakesScreenshot + ? ((TakesScreenshot) context).getScreenshotAs(OutputType.BYTES) + : AqualityServices.getBrowser().getScreenshot(); + boolean isBrowserScreenshot = context instanceof WebDriver || !(context instanceof TakesScreenshot); + Mat source = Imgcodecs.imdecode(new MatOfByte(screenshotBytes), Imgcodecs.IMREAD_UNCHANGED); + long devicePixelRatio = (long) AqualityServices.getBrowser().executeScript(JavaScript.GET_DEVICE_PIXEL_RATIO); + if (devicePixelRatio != 1 && isBrowserScreenshot) { + int scaledWidth = (int) (source.width() / devicePixelRatio); + int scaledHeight = (int) (source.height() / devicePixelRatio); + Imgproc.resize(source, source, new Size(scaledWidth, scaledHeight), 0, 0, Imgproc.INTER_AREA); + } + return source; } } diff --git a/src/test/java/tests/integration/LocatorTests.java b/src/test/java/tests/integration/LocatorTests.java index 499ccb0..424018b 100644 --- a/src/test/java/tests/integration/LocatorTests.java +++ b/src/test/java/tests/integration/LocatorTests.java @@ -5,6 +5,7 @@ import aquality.selenium.elements.interfaces.ILabel; import automationpractice.forms.ChallengingDomForm; import org.openqa.selenium.By; +import org.openqa.selenium.OutputType; import org.openqa.selenium.WebElement; import org.openqa.selenium.support.locators.RelativeLocator; import org.testng.Assert; @@ -38,14 +39,18 @@ public void testByImageLocator() { Assert.assertFalse(form.getLabelByImage().state().isDisplayed(), "Should be impossible to find element on page by image when it is absent"); getBrowser().goTo(form.getUrl()); Assert.assertTrue(form.getLabelByImage().state().isDisplayed(), "Should be possible to find element on page by image"); + Assert.assertEquals(form.getLabelByImage().getElement().getTagName(), "img", "Correct element must be found"); List childLabels = form.getChildLabelsByImage(); List docLabels = form.getLabelsByImage(); Assert.assertTrue(docLabels.size() > 1, "List of elements should be possible to find by image"); Assert.assertEquals(docLabels.size(), childLabels.size(), "Should be possible to find child elements by image with the same count"); - ILabel screen = AqualityServices.getElementFactory().getLabel(new ByImage(AqualityServices.getBrowser().getScreenshot()), "full screen"); - Assert.assertTrue(screen.state().waitForDisplayed(), "Should be possible to find element by full page screenshot"); + ILabel documentByTag = AqualityServices.getElementFactory().getLabel(By.tagName("body"), "document by tag"); + ILabel documentByImage = AqualityServices.getElementFactory().getLabel(new ByImage(documentByTag.getElement().getScreenshotAs(OutputType.BYTES)), + "full screen"); + Assert.assertTrue(documentByImage.state().isDisplayed(), "Should be possible to find element by document screenshot"); + Assert.assertEquals(documentByImage.getElement().getTagName(), "body", "Correct element must be found"); } @Test diff --git a/src/test/java/theinternet/forms/BrokenImagesForm.java b/src/test/java/theinternet/forms/BrokenImagesForm.java index 5069876..9cffb24 100644 --- a/src/test/java/theinternet/forms/BrokenImagesForm.java +++ b/src/test/java/theinternet/forms/BrokenImagesForm.java @@ -8,7 +8,7 @@ import java.util.List; public class BrokenImagesForm extends TheInternetForm { - private final By imageLocator = new ByImage(FileUtil.getResourceFileByName("brokenImage.png"), true); + private final By imageLocator = new ByImage(FileUtil.getResourceFileByName("brokenImage.png")); public BrokenImagesForm(){ super(By.id("content"), "Broken Images form");