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

com.codacy.scoobydoo.web.WebElementWrapper Maven / Gradle / Ivy

package com.codacy.scoobydoo.web;

import com.codacy.scoobydoo.Constant;
import com.codacy.scoobydoo.LoggingHelper;
import com.codacy.scoobydoo.configuration.Configuration;
import com.codacy.scoobydoo.utils.WebUtils;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.Keys;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.Point;
import org.openqa.selenium.StaleElementReferenceException;
import org.openqa.selenium.TimeoutException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.remote.RemoteWebDriver;
import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.ExpectedConditions;

import java.time.Duration;

import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.emptyOrNullString;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.matchesRegex;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;

public class WebElementWrapper {

    private final Configuration config;
    private final RemoteWebDriver driver;
    private final WebElement element;
    private final boolean isHighlightEnabled;
    private final By locator;
    private final ScreenShotHelper screenShotHelper;
    private final WebUtils webUtils;

    public WebElementWrapper(RemoteWebDriver driver, Configuration configuration, By locator) {
        this(driver, configuration, locator,
                configuration.getTimeout().FIND_ELEMENT_WAIT_TIMEOUT, configuration.getTimeout().DEFAULT_POLLING);
    }

    public WebElementWrapper(RemoteWebDriver driver, Configuration configuration, By locator, Duration timeout, Duration polling) {
        config = configuration;
        this.driver = driver;
        isHighlightEnabled = isHighlightEnabled();
        this.locator = locator;
        screenShotHelper = new ScreenShotHelper(driver, configuration);
        webUtils = new WebUtils(driver, configuration);

        try {
            webUtils.waitForCondition(timeout, polling, ExpectedConditions.presenceOfElementLocated(locator));
        } catch(TimeoutException e) {
            throw new NoSuchElementException("Could not find element [" + locator + "].", e);
        }
        element = driver.findElement(locator);

        turnOnHighlight();
    }

    public WebElementWrapper assertElementLinkIsReachable() {

        String urlLink = this.getAttribute("href").trim();
        assertThat("Element [" + this.locator + "] has no valid hyperlink attribute.", urlLink, is(not(emptyOrNullString())));

        int statusCode = webUtils.requestLinkHeadStatusCode(urlLink);
        assertThat("Link of element [" + this.locator + "] is not reachable (status code: [" + statusCode + "]).", statusCode, is(equalTo(200)));

        return this;
    }

    // NOTE: For elements where the text is stored on the value field, like input fields, use assertHasExactValue instead.
    public WebElementWrapper assertHasExactText(String expectedText) {
        assertIsDisplayed();
        final String actualText = element.getText();
        assertEquals(actualText, expectedText,
                "Element with locator [" + this.locator + "] should have text [" + expectedText
                        + "] but it has text [" + actualText + "] instead.");
        return this;
    }

    // The difference from this method to assertHasExactText is that it extracts the value field instead of the text.
    // Use this for elements like input fields.
    public WebElementWrapper assertHasExactValue(String expectedValue) {
        assertIsDisplayed();
        final String actualValue = element.getAttribute("value");
        assertEquals(actualValue, expectedValue,
                "Element with locator [" + this.locator + "] should have value [" + expectedValue
                        + "] but it has value [" + actualValue + "] instead.");
        return this;
    }

    public WebElementWrapper assertIsDisplayed() {
        assertTrue(isDisplayed(), "Element with locator [" + this.locator + "] should be displayed but it isn't.");
        return this;
    }

    public WebElementWrapper assertIsNotDisplayed() {
        assertTrue(isNotDisplayed(), "Element with locator [" + this.locator + "] should NOT be displayed but it is.");
        return this;
    }

    public WebElementWrapper assertTextContainsString(String targetString) {
        assertIsDisplayed();
        assertThat("Element with locator [" + this.locator + "] does not contain the expected text.",
                element.getText(), containsString(targetString));
        return this;
    }

    public WebElementWrapper assertTextMatchesRegEx(String regex) {
        assertIsDisplayed();
        assertThat("Element with locator [" + this.locator + "] does not contain the expected text.",
                element.getText(), matchesRegex(regex));
        return this;
    }

    public WebElementWrapper clear() {
        try {
            screenShotHelper.takesScreenshotOnAction("Clear element [" + locator.toString() + "].");
            element.clear();
        } catch (Exception e) {
            screenShotHelper.takesScreenshotOnError("Failed to clear element [" + locator.toString() + "].", e);
            throw e;
        } finally {
            turnOffHighlight();
        }
        return this;
    }

    public WebElementWrapper clearAndSendKeys(CharSequence... keys) {
        return this
                .clear()
                .sendKeys(keys);
    }

    public WebElementWrapper click() {
        try {
            screenShotHelper.takesScreenshotOnAction("Click on element [" + locator.toString() + "].");
            webUtils.waitForFunction(x -> {
                try {
                    waitToBeClickable();
                    element.click();
                    return true;
                } catch (Exception e) {
                    LoggingHelper.warn("Failed to click on element [" + locator.toString() + "] due to " + e.getMessage());
                    return false;
                }
            },
            config.getTimeout().FIND_ELEMENT_WAIT_TIMEOUT,
            config.getTimeout().LONG_POLLING);

        } catch (Exception e) {
            screenShotHelper.takesScreenshotOnError("Failed to click on element [" + locator.toString() + "].", e);
            throw e;
        } finally {
            turnOffHighlight();
        }

        return this;
    }

    @Deprecated
    public void deleteElement() {
        delete();
    }

    public WebElementWrapper delete() {
        try {
            turnOffHighlight();
            screenShotHelper.takesScreenshotOnAction("Delete element [" + locator.toString() + "] with javascript executor.");
            scriptExecutor(driver, element, "arguments[0].parentNode.removeChild(arguments[0])");
        } catch (Exception e) {
            screenShotHelper.takesScreenshotOnError("Failed to delete element [" + locator.toString() + "].", e);
            throw e;
        }
        return this;
    }

    // Use this only when default method clear() doesn't work.
    public WebElementWrapper forceClear() {
        element.sendKeys(Keys.chord(Keys.CONTROL, "a", Keys.DELETE));
        return this;
    }

    public String getAttribute(String attribute) {
        try {
            screenShotHelper.takesScreenshotOnAction("Get attribute [" + attribute + "] from element [" + locator.toString() + "].");
            return element.getAttribute(attribute);
        } catch (Exception e) {
            screenShotHelper.takesScreenshotOnError("Failed to get attribute [" + attribute + "] from element [" + locator.toString() + "].", e);
            throw e;
        } finally {
            turnOffHighlight();
        }
    }

    @Deprecated
    public WebElement getElement() {
        return getWebElement();
    }

    public WebElement getWebElement() {
        return element;
    }

    public String getText() {
        try {
            screenShotHelper.takesScreenshotOnAction("Get text from element [" + locator.toString() + "]." );
            return element.getText();
        } catch (Exception e) {
            screenShotHelper.takesScreenshotOnError("Failed to get text from element [" + locator.toString() + "].", e);
            throw e;
        } finally {
            turnOffHighlight();
        }
    }

    public boolean isDisplayed() {
        try {
            screenShotHelper.takesScreenshotOnAction("Check if element [" + locator.toString() + "] is displayed.");
            try {
                webUtils.waitForCondition(ExpectedConditions.visibilityOf(element));
                return true;
            } catch(TimeoutException e) {
                return false;
            }
        } catch (Exception e) {
            screenShotHelper.takesScreenshotOnError("Failed to check if element [" + locator.toString() + "] is displayed.", e);
            throw e;
        } finally {
            turnOffHighlight();
        }
    }

    public boolean isNotDisplayed() {
        try {
            screenShotHelper.takesScreenshotOnAction("Check if element [" + locator.toString() + "] is NOT displayed.");
            try {
                webUtils.waitForCondition(ExpectedConditions.invisibilityOf(element));
                return true;
            } catch (TimeoutException e) {
                return false;
            }
        } catch (Exception e) {
            screenShotHelper.takesScreenshotOnError("Failed to check if element [" + locator.toString() + "] is NOT displayed.", e);
            throw e;
        } finally {
            turnOffHighlight();
        }
    }

    public void jsClick() {
        try {
            screenShotHelper.takesScreenshotOnAction("Click on element [" + locator.toString() + "] with javascript executor.");
            scriptExecutor(driver, element, "arguments[0].click()");
        } catch (Exception e) {
            screenShotHelper.takesScreenshotOnError("Failed to click on element [" + locator.toString() + "].", e);
            throw e;
        } finally {
            turnOffHighlight();
        }
    }

    public WebElementWrapper sendKeys(CharSequence... key) {
        try {
            screenShotHelper.takesScreenshotOnAction("Send keys to element [" + locator.toString() + "].");
            element.sendKeys(key);
        } catch (Exception e) {
            screenShotHelper.takesScreenshotOnError("Failed to send keys to element [" + locator.toString() + "].", e);
            throw e;
        } finally {
            turnOffHighlight();
        }
        return this;
    }



    private ExpectedCondition elementAnimationEnded(final By locator) {

        return new ExpectedCondition<>() {

            private WebElement element = null;
            private Point location = null;

            @Override
            public WebElement apply(WebDriver driver) {
                if(element == null) {
                    try {
                        element = driver.findElement(locator);
                    } catch (NoSuchElementException e) {
                        return null;
                    }
                }

                try {
                    if(element.isDisplayed()){
                        Point currentLocation = element.getLocation();
                        if(currentLocation.equals(location)) {
                            return element;
                        }
                        location = currentLocation;
                    }
                } catch (StaleElementReferenceException e) {
                    element = null;
                }

                return null;
            }

            @Override
            public String toString() {
                return "End of animation of element located by [" + locator + "].";
            }
        };
    }

    private boolean isHighlightEnabled() {

        final String valueName = "highlightElements";
        String highlightElements = config.getProperty(valueName);

        if(highlightElements == null || highlightElements.isBlank()) {
            return false;
        } else {
            switch (highlightElements) {
                case Constant.Status.ENABLED -> { return true; }
                case Constant.Status.DISABLED -> { return false; }
                default -> {
                    final String errorMessage = "Invalid value [" + highlightElements + "] for parameter [" + valueName
                            + "]. It should be [" + Constant.Status.ENABLED + "] or [" + Constant.Status.DISABLED + "].";
                    IllegalArgumentException exception = new IllegalArgumentException(errorMessage);
                    LoggingHelper.error(errorMessage, exception);
                    throw exception;
                }
            }
        }
    }

    private void scriptExecutor(WebDriver driver, WebElement element, String script) {
        ((JavascriptExecutor) driver).executeScript(script, element);
    }

    private void turnOffHighlight() {
        if(isHighlightEnabled) {
            try {
                scriptExecutor(driver, element, "arguments[0].style.border='none'");
            } catch (Exception ignored) {
            }
        }
    }

    private void turnOnHighlight() {
        if(isHighlightEnabled) {
            scriptExecutor(driver, element, "arguments[0].style.border='3px solid red'");
        }
    }

    public WebElementWrapper waitForAnimationToEnd(){
        screenShotHelper.takesScreenshotOnAction("Waiting for animation of element located by [" + locator.toString() + "] to end.");
        webUtils.waitForCondition(
                config.getTimeout().FIND_ELEMENT_WAIT_TIMEOUT,
                config.getTimeout().DEFAULT_POLLING,
                elementAnimationEnded(locator));
        return this;
    }

    private void waitToBeClickable() {

        webUtils.waitForCondition(
                config.getTimeout().FIND_ELEMENT_WAIT_TIMEOUT,
                ExpectedConditions.elementToBeClickable(this.getWebElement()));
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy