
com.applitools.eyes.selenium.EyesSeleniumUtils Maven / Gradle / Ivy
/*
* Applitools software.
*/
package com.applitools.eyes.selenium;
import com.applitools.eyes.EyesException;
import com.applitools.eyes.Logger;
import com.applitools.eyes.UserAgent;
import com.applitools.eyes.logging.Stage;
import com.applitools.eyes.logging.TraceLevel;
import com.applitools.eyes.logging.Type;
import com.applitools.eyes.selenium.fluent.FrameLocator;
import com.applitools.eyes.selenium.fluent.IScrollRootElementContainer;
import com.applitools.eyes.selenium.frames.Frame;
import com.applitools.eyes.selenium.frames.FrameChain;
import com.applitools.eyes.selenium.wrappers.EyesRemoteWebElement;
import com.applitools.eyes.selenium.wrappers.EyesSeleniumDriver;
import com.applitools.eyes.selenium.wrappers.EyesWebDriver;
import com.applitools.utils.GeneralUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.lang3.tuple.Pair;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* We named this class EyesSeleniumUtils because there's a SeleniumUtils
* class, and it caused collision.
*/
public class EyesSeleniumUtils {
private static final long DOM_EXTRACTION_TIMEOUT = 5 * 60 * 1000;
private static final String DOM_SCRIPTS_WRAPPER = "return (%s)(%s);";
private static class TimeoutTask extends TimerTask {
private final AtomicBoolean isCheckTimerTimedOut;
public TimeoutTask(AtomicBoolean isCheckTimerTimedOut) {
this.isCheckTimerTimedOut = isCheckTimerTimedOut;
}
@Override
public void run() {
isCheckTimerTimedOut.set(true);
}
}
/**
* #internal
* This method gets the default root element of the page. It will be "html" or "body".
*/
public static WebElement getDefaultRootElement(Logger logger, EyesSeleniumDriver driver) {
EyesRemoteWebElement chosenElement;
WebElement scrollingElement;
try {
scrollingElement = (WebElement) driver.executeScript("return document.scrollingElement");
} catch (Throwable t) {
GeneralUtils.logExceptionStackTrace(logger, Stage.GENERAL, t);
scrollingElement = null;
}
EyesRemoteWebElement eyesScrollingElement = null;
if (scrollingElement != null) {
eyesScrollingElement = new EyesRemoteWebElement(logger, driver, scrollingElement);
}
WebElement html = driver.findElement(By.tagName("html"));
EyesRemoteWebElement htmlElement = new EyesRemoteWebElement(logger, driver, html);
if (eyesScrollingElement != null && eyesScrollingElement.canScrollVertically()) {
// If document.scrollingElement exists and can scroll vertically then it's the element we are looking for
chosenElement = eyesScrollingElement;
} else if (!doesBodyExist(logger, driver)) {
chosenElement = htmlElement;
} else {
WebElement body = driver.findElement(By.tagName("body"));
EyesRemoteWebElement bodyElement = new EyesRemoteWebElement(logger, driver, body);
boolean scrollableHtml = htmlElement.canScrollVertically();
boolean scrollableBody = bodyElement.canScrollVertically();
// If only one of the elements is scrollable, we return the scrollable one
if (scrollableHtml && !scrollableBody) {
chosenElement = htmlElement;
} else if (!scrollableHtml && scrollableBody) {
chosenElement = bodyElement;
} else if (scrollingElement != null) {
// If both of the elements are scrollable or both aren't scrollable, we choose document.scrollingElement which is always one of them
chosenElement = eyesScrollingElement;
} else {
// If document.scrollingElement, we choose html
chosenElement = htmlElement;
}
}
logger.log(new HashSet(), Stage.GENERAL, Pair.of("defaultRootElement", chosenElement.getTagName()));
return chosenElement;
}
private static boolean doesBodyExist(Logger logger, EyesSeleniumDriver driver) {
try {
driver.findElement(By.tagName("body"));
return true;
} catch (Throwable t) {
GeneralUtils.logExceptionStackTrace(logger, Stage.GENERAL, t);
return false;
}
}
/**
* #internal
*/
public static WebElement getScrollRootElement(Logger logger, EyesSeleniumDriver driver, IScrollRootElementContainer scrollRootElementContainer) {
if (EyesDriverUtils.isMobileDevice(driver)) {
return null;
}
if (scrollRootElementContainer == null) {
return EyesSeleniumUtils.getDefaultRootElement(logger, driver);
}
WebElement scrollRootElement = scrollRootElementContainer.getScrollRootElement();
if (scrollRootElement != null) {
return scrollRootElement;
}
By scrollRootSelector = scrollRootElementContainer.getScrollRootSelector();
if (scrollRootSelector != null) {
return driver.findElement(scrollRootSelector);
}
return EyesSeleniumUtils.getDefaultRootElement(logger, driver);
}
public static WebElement findFrameByFrameCheckTarget(FrameLocator frameTarget, EyesSeleniumDriver driver) {
if (frameTarget.getFrameIndex() != null) {
return driver.findElement(By.xpath("IFRAME[" + frameTarget.getFrameIndex() + "]"));
}
String nameOrId = frameTarget.getFrameNameOrId();
if (nameOrId != null) {
List byId = driver.findElements(By.id(nameOrId));
if (byId.size() > 0) {
return byId.get(0);
}
return driver.findElement(By.name(nameOrId));
}
WebElement reference = frameTarget.getFrameReference();
if (reference != null) {
return reference;
}
By selector = frameTarget.getFrameSelector();
if (selector != null) {
return driver.findElement(selector);
}
return null;
}
public static WebElement getCurrentFrameScrollRootElement(Logger logger, EyesSeleniumDriver driver, WebElement userDefinedSRE) {
WebElement scrollRootElement = tryGetCurrentFrameScrollRootElement(driver);
if (scrollRootElement == null)
{
scrollRootElement = userDefinedSRE != null ? userDefinedSRE : getDefaultRootElement(logger, driver);
}
return scrollRootElement;
}
public static WebElement tryGetCurrentFrameScrollRootElement(EyesSeleniumDriver driver)
{
FrameChain fc = driver.getFrameChain().clone();
Frame currentFrame = fc.peek();
WebElement scrollRootElement = null;
if (currentFrame != null)
{
scrollRootElement = currentFrame.getScrollRootElement();
}
return scrollRootElement;
}
public static String runDomScript(Logger logger, EyesWebDriver driver, UserAgent userAgent, Set testIds, String domScript,
Map domScriptArguments, String pollingScript) throws Exception {
if (domScriptArguments == null) {
domScriptArguments = new HashMap<>();
}
Map pollingScriptArguments = new HashMap<>();
int chunkByteLength = userAgent.getOS().toLowerCase().contains("ios") ? 10 * 1024 * 1024 : 240 * 1024 * 1024;
domScriptArguments.put("chunkByteLength", chunkByteLength);
pollingScriptArguments.put("chunkByteLength", chunkByteLength);
ObjectMapper mapper = new ObjectMapper();
String domScriptWrapped = String.format(DOM_SCRIPTS_WRAPPER, domScript, mapper.writeValueAsString(domScriptArguments));
String pollingScriptWrapped = String.format(DOM_SCRIPTS_WRAPPER, pollingScript, mapper.writeValueAsString(pollingScriptArguments));
AtomicBoolean isCheckTimerTimedOut = new AtomicBoolean(false);
Timer timer = new Timer("VG_Check_StopWatch", true);
timer.schedule(new TimeoutTask(isCheckTimerTimedOut), DOM_EXTRACTION_TIMEOUT);
try {
String resultAsString = (String) driver.executeScript(domScriptWrapped);
ScriptResponse scriptResponse = GeneralUtils.parseJsonToObject(resultAsString, ScriptResponse.class);
ScriptResponse.Status status = scriptResponse.getStatus();
logger.log(TraceLevel.Info, testIds, Stage.CHECK, Type.DOM_SCRIPT, Pair.of("message", "Starting dom script"));
while (status == ScriptResponse.Status.WIP && !isCheckTimerTimedOut.get()) {
resultAsString = (String) driver.executeScript(pollingScriptWrapped);
scriptResponse = GeneralUtils.parseJsonToObject(resultAsString, ScriptResponse.class);
status = scriptResponse.getStatus();
Thread.sleep(200);
}
if (status == ScriptResponse.Status.ERROR) {
throw new EyesException("DomSnapshot Error: " + scriptResponse.getError());
}
if (isCheckTimerTimedOut.get()) {
throw new EyesException("Domsnapshot Timed out");
}
if (status == ScriptResponse.Status.SUCCESS) {
return scriptResponse.getValue().toString();
}
logger.log(TraceLevel.Info, testIds, Stage.CHECK, Type.DOM_SCRIPT, Pair.of("message", "Collecting chunks"));
StringBuilder value = new StringBuilder();
while (status == ScriptResponse.Status.SUCCESS_CHUNKED && !scriptResponse.isDone() && !isCheckTimerTimedOut.get()) {
value.append(GeneralUtils.parseJsonToObject(scriptResponse.getValue().toString(), String.class));
resultAsString = (String) driver.executeScript(pollingScriptWrapped);
scriptResponse = GeneralUtils.parseJsonToObject(resultAsString, ScriptResponse.class);
status = scriptResponse.getStatus();
Thread.sleep(200);
}
if (status == ScriptResponse.Status.ERROR) {
throw new EyesException("DomSnapshot Error: " + scriptResponse.getError());
}
if (isCheckTimerTimedOut.get()) {
throw new EyesException("Domsnapshot Timed out");
}
value.append(GeneralUtils.parseJsonToObject(scriptResponse.getValue().toString(), String.class));
return value.toString();
} finally {
timer.cancel();
logger.log(TraceLevel.Info, testIds, Stage.CHECK, Type.DOM_SCRIPT, Pair.of("message", "Finished dom script"));
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy