All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.smartbear.visualtest.util.Utils Maven / Gradle / Ivy

The newest version!
package com.smartbear.visualtest.util;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.io.CharSource;
import com.google.common.io.Files;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.reflect.TypeToken;
import com.smartbear.visualtest.api.ApiBuilder;
import com.smartbear.visualtest.models.*;
import io.appium.java_client.android.AndroidDriver;
import io.appium.java_client.ios.IOSDriver;
import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
import org.openqa.selenium.*;
import org.openqa.selenium.Dimension;
import org.openqa.selenium.remote.RemoteWebDriver;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Map;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * The Utils class contains various utility functions for tasks such as creating temporary directories,
 * getting page dimensions, and converting JSON to Java objects.
 */
public class Utils {
    // A function to create a temporary directory.
    public static final Gson gson = new Gson();
    public static final ObjectMapper mapper = new ObjectMapper();

    public static final Logger logger = Logger.getLogger(Utils.class.getName()).getParent();
    public static final Level FINE = Level.FINE;
    public static final Level ERROR = Level.SEVERE;

    public static final Properties applicationMessages = new Properties();

    /**
     * This function calculates the number of times a webpage needs to be scrolled to view the entire
     * page based on the dimensions of the viewport and the full page.
     * 
     * @param pageDimensions It is an object that contains information about the dimensions of the
     * webpage. It has two properties:
     * @return The method is returning an integer value which represents the number of times the page
     * needs to be scrolled to view the entire page based on the given page dimensions.
     */
    public static Integer getNumberOfPagesToScroll(PageDimensions pageDimensions) {
        double viewportHeight = pageDimensions.getWindowInner().getHeight();
        double fullPageHeight = pageDimensions.getFullpage().getHeight();
        return (Integer) (int) Math.ceil(fullPageHeight /  viewportHeight);
    }

    /**
     * This Java function returns the dimensions (width and height) of an image file.
     * dimensions.
     * @return The method is returning a Dimension object that contains the width and height of the
     * image file passed as a parameter. If there is an exception, the method returns null.
     */
    public static Dimension getImageDimension(BufferedImage image) {
        try {
            int h = image.getHeight();
            int w = image.getWidth();
            return new Dimension(w, h);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * This Java function retrieves the initial state of a web page using a JavascriptExecutor.
     * 
     * @param driver The "driver" parameter is an object that represents the web browser being used for
     * automated testing. It is typically an instance of a WebDriver implementation, such as
     * ChromeDriver or FirefoxDriver. The driver allows the automation script to interact with the web
     * page, perform actions, and retrieve information.
     * @return The method is returning an object of type `InitialPageState`.
     */
    public static InitialPageState getInitialPageState(Object driver) throws IOException {
        JavascriptExecutor js = (JavascriptExecutor) driver;

        String script = loadJavascriptFileAsString(Scripts.INITIAL_STATE);
        return getInitialPageStateFromJSON((String) (js.executeScript("return " + script)));
    }
    /**
     * This Java function uses a appium driver method to return app dimensions as
     * a JSON object.
     *
     * @param driver The "driver" parameter is an object that represents the web browser or mobile
     * device being used for automated testing. It is typically created by Appium
     * @return The method is returning an object of type `PageDimensions`.
     */
    public static PageDimensions getAppDimensions(Object driver, double devicePixelRatio) throws IOException {
        Dimension dim;
        Capabilities caps = ((RemoteWebDriver)driver).getCapabilities();
        if(Integer.parseInt(caps.getCapability("platformVersion").toString().split("\\.")[0]) < 11 && caps.getCapability("platformName").equals(Platform.ANDROID)){
            dim = new Dimension(Math.toIntExact((Long) ((Map) caps.getCapability("appium:viewportRect")).get("height")), Math.toIntExact((Long) ((Map) caps.getCapability("appium:viewportRect")).get("width")));
        }else{
            if (caps.getCapability("platformName").equals(Platform.ANDROID)){
                dim =  ((AndroidDriver) driver).manage().window().getSize();
            }else{
                dim =  ((IOSDriver) driver).manage().window().getSize();
            }
        }
        PageDimensions dimensions = new PageDimensions(new Document(dim.getHeight(), dim.getWidth()), new Body(dim.getHeight(), dim.getWidth()), new WindowInner(dim.getHeight(),dim.getWidth()), new Fullpage(dim.getHeight(), dim.getWidth()),  devicePixelRatio, new InitialScroll(0.0,0.0));
        return dimensions;
    }
    /**
     * This Java function uses a JavascriptExecutor to execute a script that returns page dimensions as
     * a JSON object.
     * 
     * @param driver The "driver" parameter is an object that represents the web browser or mobile
     * device being used for automated testing. It is typically created using a WebDriver
     * implementation such as Selenium.
     * @return The method is returning an object of type `PageDimensions`.
     */
    public static PageDimensions getPageDimensions(Object driver) throws IOException {
        JavascriptExecutor js = (JavascriptExecutor) driver;

        String script = loadJavascriptFileAsString(Scripts.PAGE_DIMENSIONS);
        return getPageDimensionsFromJSON((String) (js.executeScript("return " + script)));
    }

    /**
     * This Java function retrieves the user agent data of a web browser using a JavascriptExecutor
     * object.
     * 
     * @param driver The "driver" parameter is an object that represents the web browser driver being
     * used in the code. It is used to execute JavaScript code in the context of the web page being
     * accessed.
     * @return The method is returning an object of type UserAgentInfo.
     */
    @SuppressWarnings("unchecked")
    public static UserAgentInfo getNavigatorUserAgentData(Object driver) throws IOException {
        JavascriptExecutor js = (JavascriptExecutor) driver;

        String script = loadJavascriptFileAsString(Scripts.USER_AGENT);
        return getUserAgentFromMap((Map) js.executeScript("return " + script));
    }
    /**
     * This Java function retrieves the user agent data of an appium driver capabilities.
     *
     * @param driver The "driver" parameter is an object that represents the web browser driver being
     * used in the code. It is used to execute JavaScript code in the context of the web page being
     * accessed.
     * @return The method is returning an object of type UserAgentInfo.
     */
    public static UserAgentInfo getAppiumNavigatorUserAgentData(Object driver, double devicepixelratio){
        UserAgentInfo agent =new UserAgentInfo();
        Capabilities capabilities = ((RemoteWebDriver) driver).getCapabilities();
        agent.setAppPackage(capabilities.getCapability("appium:appActivity") != null ?
                capabilities.getCapability("appium:appPackage").toString():
                (capabilities.getCapability("appium:bundleId") != null ?
                        capabilities.getCapability("appium:app") != null ?
                                capabilities.getCapability("appium:app").toString():
                capabilities.getCapability("appium:bundleId").toString():
                null));
        agent.setAppActivity(capabilities.getCapability("appium:appActivity") != null ?
                capabilities.getCapability("appium:appActivity").toString():
                        capabilities.getCapability("appium:app") != null ?
                                capabilities.getCapability("appium:app").toString():
                capabilities.getCapability("appium:bundleId").toString());
        agent.setAppiumDriverType(capabilities.getCapability("appium:automationName").toString().toLowerCase());
        agent.setDriverType("Appium");
        agent.setDeviceName(capabilities.getCapability("appium:deviceModel") != null ?
                capabilities.getCapability("appium:deviceModel").toString():
                capabilities.getCapability("appium:deviceName") != null?
                        capabilities.getCapability("appium:deviceName").toString():
                        null);
        agent.setDevicePixelRatio(devicepixelratio);
        agent.setDeviceType("mobile");
        agent.setOrientation("portrait");
        agent.setOsName(capabilities.getCapability("platformName").toString().toLowerCase());
        agent.setOsVersion(capabilities.getCapability("appium:platformVersion").toString());
        agent.setScreenHeight((int) (((RemoteWebDriver)driver).manage().window().getSize().getHeight()* devicepixelratio));
        agent.setScreenWidth((int) (((RemoteWebDriver)driver).manage().window().getSize().getWidth()* devicepixelratio));
        if(capabilities.getCapabilityNames().contains("appium:deviceManufacturer")){
            agent.setDeviceName(capabilities.getCapability("appium:deviceManufacturer").toString() + " " + agent.getDeviceName());
        }
        return agent;
    }
    /**
     * The function returns a version of Chrome OS using a JavascriptExecutor object.
     *
     * @param driver The "driver" parameter is an object that represents the web browser driver being
     * used to automate browser actions. It could be an instance of a class such as ChromeDriver.
     * @return The method is returning a String that represents version of chrome.
     */
    public static String getChromeOsVersion(Object driver) throws IOException {
        JavascriptExecutor js = (JavascriptExecutor) driver;

        String script = loadJavascriptFileAsString(Scripts.CHROME_OS_VERSION);
        return (String) js.executeAsyncScript(script);
    }
    /**
     * The function returns a string representation of the captured DOM data using a JavascriptExecutor
     * object.
     * 
     * @param driver The "driver" parameter is an object that represents the web browser driver being
     * used to automate browser actions. It could be an instance of a class such as ChromeDriver,
     * FirefoxDriver, or SafariDriver, depending on the specific browser being used.
     * @return The method is returning a String that represents the captured DOM data as a JSON object.
     */
    public static String getDomCaptureDataAsString(Object driver, String type) throws IOException {
        JavascriptExecutor js = (JavascriptExecutor) driver;

        String script = loadJavascriptFileAsString(Scripts.DOM_CAPTURE);
        String dom = (String) js.executeScript("return " + script);
        JsonElement domElement = JsonParser.parseString(dom);
        JsonObject domObject = domElement.getAsJsonObject();
        domObject.add("screenshotType", JsonParser.parseString(type));
        return domObject.toString();
    }

    /**
     * This Java function parses a JSON string and returns a specific element as a string.
     * 
     * @param domCaptureInfo The parameter "domCaptureInfo" is a string that contains information about
     * the captured DOM (Document Object Model) of a web page. It is expected to be in JSON format and
     * should include a field called "ignoredElementsData" which contains information about any
     * elements that were ignored during the capture process.
     * @return The method returns a String representation of the "ignoredElementsData" element from the
     * input JSON string "domCaptureInfo". If there is an error while parsing the JSON, the method
     * returns null.
     */
    public static String getIgnoredElementsDataAsString(String domCaptureInfo) {
        try {
            JsonElement ignoredElement = JsonParser.parseString(domCaptureInfo);
            JsonObject ignoredElementObject = ignoredElement.getAsJsonObject();
            JsonElement ignoredElements = ignoredElementObject.get("ignoredElementsData");
            return ignoredElements.toString();
        } catch (Exception e) {
            Utils.logger.log(Level.SEVERE, "Error while parsing ignoredElements from DOM");
        }
        return null;
    }

    /**
     * This function loads a JavaScript file as a string given its name.
     * 
     * @param name The name of the JavaScript file that needs to be loaded as a string.
     * @return The method is returning a String representation of the contents of a JavaScript file.
     */
    public static String loadJavascriptFileAsString(String name) throws  IOException {
//        File sourceFile = new File("src/main/resources/scripts/" + name);
        File sourceFile = File.createTempFile("temp", ".js");
        FileWriter writer = new FileWriter(sourceFile);
        writer.write(name);
        writer.close();
        CharSource externalJS = Files.asCharSource(sourceFile, StandardCharsets.UTF_8);
        return externalJS.read();
    }

    /**
     * The function parses a JSON string into a PageDimensions object using the Gson library in Java.
     * 
     * @param json A string containing JSON data that represents a PageDimensions object.
     * @return A `PageDimensions` object is being returned. The method uses the Gson library to parse a
     * JSON string and convert it into a `PageDimensions` object.
     */
    private static PageDimensions getPageDimensionsFromJSON(String json) {
        Utils.logger.info("Webpage Dimensions: " + json);
        return new Gson().fromJson(
                json, new TypeToken() {}.getType()
        );
    }

    /**
     * The function parses a JSON string into an object of type InitialPageState using the Gson
     * library.
     * 
     * @param json The parameter "json" is a string that contains JSON data. This JSON data represents
     * the initial state of a web page. The method "getInitialPageStateFromJSON" uses the Gson library
     * to parse this JSON data and convert it into an object of type "InitialPageState".
     * @return The method is returning an object of type `InitialPageState` which is obtained by
     * deserializing the JSON string passed as a parameter using the Gson library.
     */
    private static InitialPageState getInitialPageStateFromJSON(String json) {
        return new Gson().fromJson(
                json, new TypeToken() {}.getType()
        );
    }

    /**
     * The function converts a map to a UserAgentInfo object using a mapper.
     * 
     * @param map A Map object that contains key-value pairs representing the properties of a user
     * agent. The keys are strings that represent the names of the properties, and the values are
     * objects that represent the values of the properties. The method converts this map into a
     * UserAgentInfo object using the Jackson ObjectMapper.
     * @return The method is returning an object of type `UserAgentInfo`. It is using the
     * `convertValue` method from the `mapper` object of the `Utils` class to convert the `map`
     * parameter to an instance of `UserAgentInfo` class.
     */
    private static UserAgentInfo getUserAgentFromMap(Map map) {
        return Utils.mapper.convertValue(map, UserAgentInfo.class);
    }

    /**
     * The function converts a JSON string to a Java object using the Gson library.
     * 
     * @param json a String representing a JSON object
     * @param clazz The "clazz" parameter is a Class object that represents the type of the Java object
     * that the JSON string should be converted to. It is used by the Gson library to deserialize the
     * JSON string into a Java object of the specified type.
     * @return The method returns an Object, which is either the converted Java object from the
     * provided JSON string or null if there was an error during the conversion process.
     */
    public static Object gsonToJavaObject(String json, Class clazz) {
        try {
            JsonObject jsonObject = new Gson().fromJson(json, JsonObject.class);
            return gson.fromJson(jsonObject, clazz);
        } catch (Exception e) {
            System.out.println("Error while converting json to java object");
        }
        return null;
    }

    /**
     * The function capitalizes the first letter of a given string.
     * 
     * @param str The input string that needs to be capitalized.
     * @return The method `capitalize` returns a capitalized version of the input string `str`. If the
     * input string is null or empty, the method returns the same string. Otherwise, the method returns
     * the first character of the string in uppercase, followed by the rest of the string.
     */
    public static String capitalize(String str) {
        if (str == null || str.isEmpty()) {
            return str;
        }

        return str.substring(0, 1).toUpperCase() + str.substring(1);
    }

    /**
     * The function returns the webpage to its initial state by resetting the body's transform, scroll
     * position, and overflow properties using JavaScript.
     * 
     * @param js The "js" parameter is an instance of the JavascriptExecutor interface, which allows
     * the execution of JavaScript code from within Java code.
     * @param initialPageState The initialPageState parameter is an object that contains the initial
     * state of the webpage. It includes the transform, scrollX, scrollY, and overflow properties.
     * These properties are used to reset the webpage to its initial state.
     */
    public static void returnToInitialState(JavascriptExecutor js, InitialPageState initialPageState) {
        js.executeScript("document.body.style.transform = '"+ initialPageState.getTransform() + "';");
        js.executeScript("window.scrollTo(" + initialPageState.getScrollX() + "," + initialPageState.getScrollY() + ")");
        js.executeScript("document.body.style.overflow = '" + initialPageState.getOverflowBody() + "';");
        js.executeScript("document.documentElement.style.overflow = '" + initialPageState.getOverflowDocument() + "';");
    }

    /**
     * This function loads a message from a properties file and interpolates any provided values into
     * the message.
     * 
     * @param key The key is a string that represents the message to be retrieved from the properties
     * file. It is used to identify the specific message that needs to be loaded.
     * @return The method is returning a String value which is the message corresponding to the given
     * key in the "ApplicationMessages.properties" file. If there are any placeholders in the message,
     * they will be replaced with the values provided in the "interpolate" parameter using the
     * String.format() method.
     */
    public static String loadResourceAsString(String key, String... interpolate) throws IOException, NullPointerException {
        Utils.applicationMessages.load(Utils.class.getClassLoader().getResourceAsStream("ApplicationMessages.properties"));
        String message = Utils.applicationMessages.getProperty(key);
        for(String one:interpolate) {
            message = String.format(message, one);
        }
        return message;
    }

    /**
     * The function freezes the current page using a JavascriptExecutor object.
     * 
     * @param js The "js" parameter is an instance of the JavascriptExecutor interface, which allows
     * for the execution of JavaScript code from within Java code. In this particular method, it is
     * used to execute a JavaScript script that freezes the current page.
     */
    @SuppressWarnings("unchecked")
    public static Map freezePage(JavascriptExecutor js) {
        return (Map) js.executeScript("return " + Scripts.FREEZE_PAGE);
    }

    public static int getFullPageHeight(JavascriptExecutor js) {
        String script = "return Math.max(window.document.body.offsetHeight,window.document.body.scrollHeight, window.document.documentElement.offsetHeight, window.document.documentElement.scrollHeight);";
        Object result = js.executeScript(script);
        return ((Number) result).intValue();
    }

    public static Double getScrollOffset(JavascriptExecutor js) {
        String script = "return window.scrollY";
        return (Long) js.executeScript(script) * 1.0;
    }
    public static String getParamsString(Map params)
            throws UnsupportedEncodingException {
        StringBuilder result = new StringBuilder();

        for (Map.Entry entry : params.entrySet()) {
            result.append(URLEncoder.encode(entry.getKey(), "UTF-8"));
            result.append("=");
            result.append(URLEncoder.encode(entry.getValue(), "UTF-8"));
            result.append("&");
        }

        String resultString = result.toString();
        return resultString.length() > 0
                ? resultString.substring(0, resultString.length() - 1)
                : resultString;
    }


    public static byte[] toByteArray(BufferedImage bi)
            throws IOException {

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ImageIO.write(bi, "png", baos);
        return baos.toByteArray();

    }
    public static String getTypeOfImage(Map options) throws Exception {
        if (options.containsKey("viewport")) {
            if (options.get("viewport") instanceof Boolean) {
                if ((Boolean) options.get("viewport")) {
                    return "viewport";
                } else {
                    throw new Exception("\"viewport\" should be set to \"true\" in oder to take a viewport screenshot");
                }
            } else {
                throw new Exception("Type of \"viewport\" option should be Boolean.");
            }
        } else if (options.containsKey("element")) {
            if (options.get("element") instanceof WebElement) {
                return "element";
            } else {
                throw new Exception("Type of \"element\" option should be WebElement.");
            }
        } else {
            return "fullpage";
        }
    }
    public static boolean pixelsAreCloseMatch(int p1, int p2){

        //see if p1 and p2 pixels are within a tolerance of 50
        //based on the euclidean distance formula

        Color c1 = new Color(p1);
        Color c2 = new Color(p2);

        double d = euclideanDiff(c1,c2);

        //seeing first shaded red in android chrome pretest at diff of 72
        return d <= 100;
    }
    private static double euclideanDiff(Color c1, Color c2){

        return Math.sqrt( Math.pow(c2.getRed() - c1.getRed(), 2) +  Math.pow(c2.getGreen() - c1.getGreen(),2) + Math.pow(c2.getBlue() - c1.getBlue(),2) );
    }

    public static void hideScrollBar(Object driver){
        JavascriptExecutor js = (JavascriptExecutor) driver;
        js.executeScript("return document.body.style.overflow='hidden';");
        js.executeScript("return document.documentElement.style.overflow='hidden';");
    }
    public static void checkSdkVersion(String latest) throws Exception {
        Properties properties = new Properties();
        properties.load(ApiBuilder.class.getClassLoader().getResourceAsStream("config.properties"));
        String version = properties.getProperty("VERSION");

        if (new DefaultArtifactVersion(version).compareTo(new DefaultArtifactVersion(latest)) < 0){
            ReportPrinter.print(new String[]{"WARNING: A newer version of visualtest-java SDK is available. Your version ", version, ". Latest version ", latest, ". See https://central.sonatype.com/artifact/com.smartbear/visualtest for more information.", }, "", ReportPrinter.ANSI_YELLOW);
        }
    }
}





© 2015 - 2024 Weber Informatics LLC | Privacy Policy