com.seleniumtests.uipage.htmlelements.PictureElement.java Source code

Java tutorial

Introduction

Here is the source code for com.seleniumtests.uipage.htmlelements.PictureElement.java

Source

/**
 * Orignal work: Copyright 2015 www.seleniumtests.com
 * Modified work: Copyright 2016 www.infotel.com
 *             Copyright 2017-2019 B.Hecquet
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.seleniumtests.uipage.htmlelements;

import java.io.File;
import java.time.Duration;

import org.openqa.selenium.By;
import org.openqa.selenium.Dimension;
import org.openqa.selenium.Point;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.interactions.Actions;

import com.seleniumtests.core.SeleniumTestsContextManager;
import com.seleniumtests.driver.BrowserType;
import com.seleniumtests.driver.CustomEventFiringWebDriver;
import com.seleniumtests.driver.WebUIDriver;
import com.seleniumtests.driver.screenshots.ScreenshotUtil;
import com.seleniumtests.driver.screenshots.ScreenshotUtil.Target;
import com.seleniumtests.uipage.ReplayOnError;

import io.appium.java_client.touch.TapOptions;
import io.appium.java_client.touch.WaitOptions;
import io.appium.java_client.touch.offset.PointOption;

/**
 * Element which is found inside driver snapshot
 * @author behe
 *
 */
public class PictureElement extends GenericPictureElement {

    private HtmlElement intoElement;

    public PictureElement() {
        // for mocks
    }

    public PictureElement(String label, String resourcePath, HtmlElement intoElement) {
        this(label, resourcePath, intoElement, 0.1);
    }

    public PictureElement(String label, String resourcePath, HtmlElement intoElement, double detectionThreshold) {
        this(label, createFileFromResource(resourcePath), intoElement, detectionThreshold);
        this.resourcePath = resourcePath;
    }

    public PictureElement(String label, File pictureFile, HtmlElement intoElement) {
        this(label, pictureFile, intoElement, 0.1);
    }

    /**
     * 
     * @param label
     * @param pictureFile         picture to search for in snapshot or on desktop
     * @param intoElement         HtmlElement inside of which our picture is. It allows scrolling to the zone where 
     *                         picture is searched before doing capture
     * @param detectionThreshold   sensitivity of search between 0 and 1. Be default, 0.1. More sensitivity means search can be less accurate, detect unwanted zones
     */
    public PictureElement(String label, File pictureFile, HtmlElement intoElement, double detectionThreshold) {
        super(label, pictureFile, detectionThreshold, false, new ScreenshotUtil());

        if (intoElement == null) {
            if (SeleniumTestsContextManager.isWebTest()) {
                this.intoElement = new HtmlElement("", By.tagName("body"));
            } else {
                this.intoElement = new HtmlElement("", By.xpath("/*"));
            }
        } else {
            this.intoElement = intoElement;
        }
    }

    public ScreenshotUtil getScreenshotUtil() {
        return new ScreenshotUtil();
    }

    /**
     * Search the picture in the screenshot taken by Robot or WebDriver
     * Robot is used in Desktop mode
     * WebDriver is used in mobile, because Robot is not available for mobile platforms
     * 
     * @param searchOnly
     * 
     * @deprecated use findElement instead
     */
    @Deprecated
    public void findElement(boolean searchOnly) {
        findElement();
    }

    public File getScreenshotFile() {
        screenshotUtil = getScreenshotUtil(); // update driver

        return screenshotUtil.capture(Target.PAGE, File.class, true);
    }

    protected void doAfterPictureSearch() {
        // scroll to element where our picture is so that we will be able to act on it
        // scrolling will display, on top of window, the top of the element
        intoElement.scrollToElement(0);
    }

    /**
     * Click at the coordinates xOffset, yOffset of the center of the found picture. Use negative offset to click on the left or
     * top of the picture center
     * In case the size ratio between searched picture and found picture is not 1, then, offset is
     * the source offset so that it's compatible with any screen size and resolution
     */
    @ReplayOnError(replayDelayMs = 1000)
    public void clickAt(int xOffset, int yOffset) {
        findElement();

        Point intoElementPos = intoElement.getCoordinates().onPage();
        int relativeX = detectedObjectRectangle.x + detectedObjectRectangle.width / 2 - intoElementPos.x;
        int relativeY = detectedObjectRectangle.y + detectedObjectRectangle.height / 2 - intoElementPos.y;

        moveAndClick(intoElement, relativeX + (int) (xOffset * pictureSizeRatio),
                relativeY + (int) (yOffset * pictureSizeRatio));
    }

    @ReplayOnError(replayDelayMs = 1000)
    public void doubleClickAt(int xOffset, int yOffset) {
        findElement();

        Point intoElementPos = intoElement.getCoordinates().onPage();
        int relativeX = detectedObjectRectangle.x + detectedObjectRectangle.width / 2 - intoElementPos.x;
        int relativeY = detectedObjectRectangle.y + detectedObjectRectangle.height / 2 - intoElementPos.y;

        moveAndDoubleClick(intoElement, relativeX + (int) (xOffset * pictureSizeRatio),
                relativeY + (int) (yOffset * pictureSizeRatio));
    }

    @ReplayOnError(replayDelayMs = 1000)
    public void swipe(int xMove, int yMove) {
        findElement();

        int xInit = detectedObjectRectangle.x + detectedObjectRectangle.width / 2;
        int yInit = detectedObjectRectangle.y + detectedObjectRectangle.height / 2;

        createTouchAction().press(PointOption.point(xInit, yInit))
                .waitAction(WaitOptions.waitOptions(Duration.ofMillis(500)))
                .moveTo(PointOption.point(xInit + xMove, yInit + yMove)).release().perform();
    }

    @ReplayOnError(replayDelayMs = 1000)
    public void tap() {
        findElement();

        createTouchAction()
                .moveTo(PointOption.point(detectedObjectRectangle.x + detectedObjectRectangle.width / 2,
                        detectedObjectRectangle.y + detectedObjectRectangle.height / 2))
                .tap(TapOptions.tapOptions().withTapsCount(1)).perform();
    }

    public void moveAndClick(WebElement element, int coordX, int coordY) {
        move(element, coordX, coordY).click().build().perform();
    }

    /**
     * Move to the center of the picture
     * @param element   The element to move to
     * @param coordX   x offset from the center of the element
     * @param coordY   y offset from the center of the element
     * @return
     */
    private Actions move(WebElement element, int coordX, int coordY) {

        if (SeleniumTestsContextManager.isWebTest()) {
            // issue #133: handle new actions specific case
            // more browsers will be added to this conditions once they are migrated to new composite actions
            if (SeleniumTestsContextManager.getThreadContext().getBrowser() == BrowserType.FIREFOX) {
                // issue #133: firefox moves to center of element in page
                coordX -= element.getSize().width / 2;
                coordY -= element.getSize().height / 2;
            } else if (SeleniumTestsContextManager.getThreadContext()
                    .getBrowser() == BrowserType.INTERNET_EXPLORER) {
                // issue #180: internet explorer moves to center of element in viewport
                Dimension viewportDim = ((CustomEventFiringWebDriver) (WebUIDriver.getWebDriver()))
                        .getViewPortDimensionWithoutScrollbar();
                coordX -= Math.min(element.getSize().width, viewportDim.width) / 2;
                coordY -= Math.min(element.getSize().height, viewportDim.height) / 2;
            }
        }

        return new Actions(WebUIDriver.getWebDriver()).moveToElement(element, coordX, coordY);
    }

    public void moveAndDoubleClick(WebElement element, int coordX, int coordY) {
        move(element, coordX, coordY).doubleClick().build().perform();
    }

    public void sendKeys(final CharSequence text, int xOffset, int yOffset) {
        clickAt(xOffset, yOffset);

        new Actions(WebUIDriver.getWebDriver()).sendKeys(text).build().perform();
    }

    /**
     * Check if picture is visible on desktop. This is only available for desktop tests
     * @param waitMs
     * @return
     * 
     * @deprecated use isElementPresent instead
     */
    @Deprecated
    public boolean isElementPresentOnDesktop(int waitMs) {
        return isElementPresent(waitMs);
    }

    /**
     * @deprecated use isElementPresent instead
     */
    @Deprecated
    public boolean isElementPresentOnDesktop() {
        return isElementPresent(0);
    }

    // TODO: actions for mobile
    // https://discuss.appium.io/t/tapping-on-the-screen-by-using-coordinates/5529/7

}