com.codacy.scoobydoo.web.WebElementWrapper Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of scooby-doo-fwk Show documentation
Show all versions of scooby-doo-fwk Show documentation
Automated testing framework
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()));
}
}