com.applitools.eyes.EyesBase Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of eyes-sdk-core-java3 Show documentation
Show all versions of eyes-sdk-core-java3 Show documentation
Applitools Eyes SDK base for Java
The newest version!
package com.applitools.eyes;
import com.applitools.ICheckSettings;
import com.applitools.connectivity.ServerConnector;
import com.applitools.eyes.capture.AppOutputProvider;
import com.applitools.eyes.capture.ScreenshotProvider;
import com.applitools.eyes.config.Configuration;
import com.applitools.eyes.debug.DebugScreenshotsProvider;
import com.applitools.eyes.debug.FileDebugScreenshotsProvider;
import com.applitools.eyes.debug.NullDebugScreenshotProvider;
import com.applitools.eyes.events.ValidationInfo;
import com.applitools.eyes.exceptions.DiffsFoundException;
import com.applitools.eyes.exceptions.NewTestException;
import com.applitools.eyes.exceptions.TestFailedException;
import com.applitools.eyes.fluent.CheckSettings;
import com.applitools.eyes.fluent.ICheckSettingsInternal;
import com.applitools.eyes.locators.BaseOcrRegion;
import com.applitools.eyes.locators.TextRegion;
import com.applitools.eyes.locators.TextRegionSettings;
import com.applitools.eyes.logging.Stage;
import com.applitools.eyes.logging.TraceLevel;
import com.applitools.eyes.logging.Type;
import com.applitools.eyes.positioning.InvalidPositionProvider;
import com.applitools.eyes.positioning.PositionProvider;
import com.applitools.eyes.scaling.FixedScaleProvider;
import com.applitools.eyes.scaling.NullScaleProvider;
import com.applitools.eyes.selenium.ClassicRunner0;
import com.applitools.eyes.triggers.MouseAction;
import com.applitools.eyes.triggers.MouseTrigger;
import com.applitools.eyes.triggers.TextTrigger;
import com.applitools.eyes.visualgrid.model.DeviceSize;
import com.applitools.eyes.visualgrid.model.RenderingInfo;
import com.applitools.utils.*;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.lang3.tuple.Pair;
import java.awt.image.BufferedImage;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.*;
/**
* Applitools Eyes Base for Java API .
*/
public abstract class EyesBase implements IEyesBase {
protected static final int USE_DEFAULT_TIMEOUT = -1;
private boolean shouldMatchWindowRunOnceOnTimeout;
private MatchWindowTask matchWindowTask;
private String testId = UUID.randomUUID().toString();
protected String agentRunId = null;
protected ClassicRunner0 runner;
protected ServerConnector serverConnector;
protected RunningSession runningSession;
protected SessionStartInfo sessionStartInfo;
protected TestResultContainer testResultContainer;
protected EyesScreenshot lastScreenshot;
protected PropertyHandler scaleProviderHandler;
protected PropertyHandler cutProviderHandler;
protected PropertyHandler positionProviderHandler;
private boolean isScaleProviderSetByUser = false;
// Will be checked before any argument validation. If true,
// all method will immediately return without performing any action.
private boolean isDisabled;
protected Logger logger;
protected boolean isOpen;
private final Queue userInputs;
private final List properties = new ArrayList<>();
private boolean isViewportSizeSet;
private int validationId;
protected DebugScreenshotsProvider debugScreenshotsProvider;
public EyesBase() {
this(null);
}
public EyesBase(ClassicRunner0 runner) {
this.runner = runner != null ? runner : new ClassicRunner0();
logger = new Logger();
initProviders();
//setServerConnector(new ServerConnector());
runningSession = null;
userInputs = new ArrayDeque<>();
lastScreenshot = null;
debugScreenshotsProvider = new NullDebugScreenshotProvider();
}
/**
* @param hardReset If false, init providers only if they're not initialized.
*/
private void initProviders(boolean hardReset) {
if (scaleProviderHandler == null || hardReset) {
scaleProviderHandler = new SimplePropertyHandler<>();
scaleProviderHandler.set(new NullScaleProvider(logger));
}
if (cutProviderHandler == null || hardReset) {
cutProviderHandler = new SimplePropertyHandler<>();
cutProviderHandler.set(new NullCutProvider());
}
if (positionProviderHandler == null || hardReset) {
positionProviderHandler = new SimplePropertyHandler<>();
positionProviderHandler.set(new InvalidPositionProvider());
}
}
/**
* Same as {@link #initProviders(boolean)}, setting {@code hardReset} to {@code false}.
*/
private void initProviders() {
initProviders(false);
}
public String getTestId() {
return testId;
}
public void setTestId(String testId) {
this.testId = testId;
}
/**
* Sets the server connector to use. MUST BE SET IN ORDER FOR THE EYES OBJECT TO WORK!
* @param serverConnector The server connector object to use.
*/
public void setServerConnector(ServerConnector serverConnector) {
ArgumentGuard.notNull(serverConnector, "serverConnector");
this.serverConnector = serverConnector;
serverConnector.setLogger(logger);
runner.setServerConnector(serverConnector);
}
public ServerConnector getServerConnector() {
if (serverConnector != null && serverConnector.getAgentId() == null) {
serverConnector.setAgentId(getFullAgentId());
runner.setServerConnector(serverConnector);
logger.setAgentId(serverConnector.getAgentId());
}
return serverConnector;
}
/**
* Sets the API key of your applitools Eyes account.
* @param apiKey The api key to set.
*/
public Configuration setApiKey(String apiKey) {
ArgumentGuard.notNull(apiKey, "apiKey");
getConfigurationInstance().setApiKey(apiKey);
if (getServerConnector() == null) {
throw new EyesException("server connector not set.");
}
getServerConnector().setApiKey(apiKey);
runner.setApiKey(apiKey);
return this.getConfigurationInstance();
}
/**
* @return The currently set API key or {@code null} if no key is set.
*/
public String getApiKey() {
if (getServerConnector() == null) {
throw new EyesException("server connector not set.");
}
return getServerConnector().getApiKey();
}
/**
* Sets the current server URL used by the rest client.
* @param serverUrl The URI of the rest server, or {@code null} to use
* the default server.
*/
public Configuration setServerUrl(String serverUrl) {
setServerUrl(URI.create(serverUrl));
return this.getConfigurationInstance();
}
/**
* Sets the current server URL used by the rest client.
* @param serverUrl The URI of the rest server, or {@code null} to use
* the default server.
*/
public Configuration setServerUrl(URI serverUrl) {
if (getServerConnector() == null) {
throw new EyesException("server connector not set.");
}
if (serverUrl == null) {
getServerConnector().setServerUrl(getDefaultServerUrl());
} else {
getServerConnector().setServerUrl(serverUrl);
}
runner.setServerUrl(getServerConnector().getServerUrl().toString());
return this.getConfigurationInstance();
}
/**
* @return The URI of the eyes server.
*/
public URI getServerUrl() {
if (getServerConnector() == null) {
throw new EyesException("server connector not set.");
}
return getServerConnector().getServerUrl();
}
/**
* Sets the proxy settings to be used by the rest client.
* @param abstractProxySettings The proxy settings to be used by the rest client.
* If {@code null} then no proxy is set.
*/
public Configuration setProxy(AbstractProxySettings abstractProxySettings) {
if (getServerConnector() == null) {
throw new EyesException("server connector not set.");
}
getServerConnector().setProxy(abstractProxySettings);
runner.setProxy(abstractProxySettings);
return getConfigurationInstance();
}
/**
* @return The current proxy settings used by the server connector,
* or {@code null} if no proxy is set.
*/
public AbstractProxySettings getProxy() {
if (getServerConnector() == null) {
throw new EyesException("server connector not set.");
}
return getServerConnector().getProxy();
}
/**
* @param isDisabled If true, all interactions with this API will be
* silently ignored.
*/
public void setIsDisabled(boolean isDisabled) {
this.isDisabled = isDisabled;
}
/**
* @return Whether eyes is disabled.
*/
public Boolean getIsDisabled() {
return isDisabled;
}
/**
* Clears the user inputs list.
*/
protected void clearUserInputs() {
if (isDisabled) {
return;
}
userInputs.clear();
}
/**
* @return User inputs collected between {@code checkWindowBase} invocations.
*/
protected Trigger[] getUserInputs() {
if (isDisabled) {
return null;
}
Trigger[] result = new Trigger[userInputs.size()];
return userInputs.toArray(result);
}
/**
* @return The base agent id of the SDK.
*/
protected abstract String getBaseAgentId();
/**
* @return The full agent id composed of both the base agent id and the
* user given agent id.
*/
public String getFullAgentId() {
String agentId = getConfigurationInstance().getAgentId();
if (agentId == null) {
return getBaseAgentId();
}
return String.format("%s [%s]", agentId, getBaseAgentId());
}
/**
* @return Whether a session is open.
*/
public boolean getIsOpen() {
return isOpen;
}
public static URI getDefaultServerUrl() {
try {
return new URI("https://eyesapi.applitools.com");
} catch (URISyntaxException ex) {
throw new EyesException(ex.getMessage(), ex);
}
}
/**
* Sets a handler of log messages generated by this API.
* @param logHandler Handles log messages generated by this API.
*/
public void setLogHandler(LogHandler logHandler) {
logger.setLogHandler(logHandler);
serverConnector.setLogger(logger);
runner.setLogHandler(logHandler);
}
/**
* @return The currently set log handler.
*/
public LogHandler getLogHandler() {
return logger.getLogHandler();
}
public Logger getLogger() {
return logger;
}
/**
* Manually set the the sizes to cut from an image before it's validated.
* @param cutProvider the provider doing the cut.
*/
public void setImageCut(CutProvider cutProvider) {
if (cutProvider != null) {
cutProvider.setLogger(logger);
cutProviderHandler = new ReadOnlyPropertyHandler<>(
cutProvider);
} else {
cutProviderHandler = new SimplePropertyHandler<>();
cutProviderHandler.set(new NullCutProvider());
}
}
public boolean getIsCutProviderExplicitlySet() {
return cutProviderHandler != null && !(cutProviderHandler.get() instanceof NullCutProvider);
}
public boolean getIsScaleProviderExplicitlySet() {
return isScaleProviderSetByUser;
}
/**
* Manually set the scale ratio for the images being validated.
* @param scaleRatio The scale ratio to use, or {@code null} to reset
* back to automatic scaling.
*/
public void setScaleRatio(Double scaleRatio) {
if (scaleRatio != null) {
isScaleProviderSetByUser = true;
FixedScaleProvider scaleProvider = new FixedScaleProvider(logger, scaleRatio);
scaleProviderHandler = new ReadOnlyPropertyHandler(
scaleProvider);
} else {
isScaleProviderSetByUser = false;
scaleProviderHandler = new SimplePropertyHandler<>();
scaleProviderHandler.set(new NullScaleProvider(logger));
}
}
/**
* @return The ratio used to scale the images being validated.
*/
public double getScaleRatio() {
return scaleProviderHandler.get().getScaleRatio();
}
/**
* Adds a property to be sent to the server.
* @param name The property name.
* @param value The property value.
*/
public void addProperty(String name, String value) {
PropertyData pd = new PropertyData(name, value);
properties.add(pd);
}
protected void addProperty(PropertyData property) {
properties.add(property);
}
/**
* Clears the list of custom properties.
*/
public void clearProperties() {
properties.clear();
}
/**
* @param saveDebugScreenshots If true, will save all screenshots to local directory.
*/
public void setSaveDebugScreenshots(boolean saveDebugScreenshots) {
DebugScreenshotsProvider prev = debugScreenshotsProvider;
if (saveDebugScreenshots) {
debugScreenshotsProvider = new FileDebugScreenshotsProvider(logger);
} else {
debugScreenshotsProvider = new NullDebugScreenshotProvider();
}
debugScreenshotsProvider.setPrefix(prev.getPrefix());
debugScreenshotsProvider.setPath(prev.getPath());
}
/**
* @return True if screenshots saving enabled.
*/
public boolean getSaveDebugScreenshots() {
return !(debugScreenshotsProvider instanceof NullDebugScreenshotProvider);
}
/**
* @param pathToSave Path where you want to save the debug screenshots.
*/
public void setDebugScreenshotsPath(String pathToSave) {
debugScreenshotsProvider.setPath(pathToSave);
}
/**
* @return The path where you want to save the debug screenshots.
*/
public String getDebugScreenshotsPath() {
return debugScreenshotsProvider.getPath();
}
/**
* @param prefix The prefix for the screenshots' names.
*/
public void setDebugScreenshotsPrefix(String prefix) {
debugScreenshotsProvider.setPrefix(prefix);
}
/**
* @return The prefix for the screenshots' names.
*/
public String getDebugScreenshotsPrefix() {
return debugScreenshotsProvider.getPrefix();
}
public DebugScreenshotsProvider getDebugScreenshotsProvider() {
return debugScreenshotsProvider;
}
public SessionStopInfo prepareStopSession(boolean isAborted) {
if (runningSession == null || !isOpen) {
logger.log(getTestId(), Stage.CLOSE, "Tried to close a non opened test");
return null;
}
isOpen = false;
lastScreenshot = null;
clearUserInputs();
initProviders(true);
final boolean isNewSession = runningSession.getIsNew();
boolean save = (isNewSession && getConfigurationInstance().getSaveNewTests())
|| (!isNewSession && getConfigurationInstance().getSaveFailedTests());
return new SessionStopInfo(runningSession, isAborted, save);
}
/**
* See {@link #close(boolean)}.
* {@code throwEx} defaults to {@code true}.
* @return The test results.
*/
public TestResults close() {
return close(true);
}
public TestResults abort() {
return abortIfNotClosed();
}
/**
* Ends the test.
* @param throwEx If true, an exception will be thrown for failed/new tests.
* @return The test results.
* @throws TestFailedException if a mismatch was found and throwEx is true.
* @throws NewTestException if this is a new test was found and throwEx
* is true.
*/
public TestResults close(boolean throwEx) {
TestResults results = stopSession(false);
logSessionResultsAndThrowException(throwEx, results);
return results;
}
public TestResults abortIfNotClosed() {
logger.log(getTestId(), Stage.CLOSE, Type.CALLED);
return stopSession(true);
}
protected TestResults stopSession(boolean isAborted) {
if (isDisabled) {
TestResults testResults = new TestResults();
testResults.setStatus(TestResultsStatus.Disabled);
return testResults;
}
SessionStopInfo sessionStopInfo = prepareStopSession(isAborted);
if (sessionStopInfo == null) {
TestResults testResults = new TestResults();
testResults.setStatus(TestResultsStatus.NotOpened);
return testResults;
}
TestResults testResults = runner.close(getTestId(), sessionStopInfo);
runningSession = null;
if (testResults == null) {
throw new EyesException("Failed stopping session");
}
return testResults;
}
public void logSessionResultsAndThrowException(boolean throwEx, TestResults results) {
TestResultsStatus status = results.getStatus();
String sessionResultsUrl = results.getUrl();
String scenarioIdOrName = results.getName();
String appIdOrName = results.getAppName();
if (status == null) {
throw new EyesException("Status is null in the test results");
}
logger.log(getTestId(), Stage.CLOSE, Type.TEST_RESULTS, Pair.of("status", status), Pair.of("url", sessionResultsUrl));
switch (status) {
case Failed:
if (throwEx) {
throw new TestFailedException(results, scenarioIdOrName, appIdOrName);
}
break;
case Passed:
break;
case NotOpened:
if (throwEx) {
throw new EyesException("Called close before calling open");
}
break;
case Unresolved:
if (results.isNew()) {
if (throwEx) {
throw new NewTestException(results, scenarioIdOrName, appIdOrName);
}
} else {
if (throwEx) {
throw new DiffsFoundException(results, scenarioIdOrName, appIdOrName);
}
}
break;
}
}
protected void openLogger() {
logger.getLogHandler().open();
}
/**
* @return The currently set position provider.
*/
public PositionProvider getPositionProvider() {
return positionProviderHandler.get();
}
/**
* @param positionProvider The position provider to be used.
*/
public void setPositionProvider(PositionProvider positionProvider) {
if (positionProvider != null) {
positionProviderHandler = new ReadOnlyPropertyHandler<>(
positionProvider);
} else {
positionProviderHandler = new SimplePropertyHandler<>();
positionProviderHandler.set(new InvalidPositionProvider());
}
}
public List extractText(BaseOcrRegion... ocrRegions) {
ArgumentGuard.notNull(ocrRegions, "ocrRegions");
ArgumentGuard.notContainsNull(ocrRegions, "ocrRegions");
List result = new ArrayList<>();
for (BaseOcrRegion ocrRegion : ocrRegions) {
logger.log(getTestId(), Stage.OCR, Pair.of("ocrRegion", ocrRegion));
getAppOutputForOcr(ocrRegion);
if (ocrRegion.getAppOutput() == null) {
return Collections.emptyList();
}
debugScreenshotsProvider.save(ocrRegion.getAppOutput().getScreenshot().getImage(), "ocr_regions");
SyncTaskListener listener = new SyncTaskListener<>(logger, "getTextRegions");
serverConnector.uploadImage(listener, ocrRegion.getAppOutput().getScreenshotBytes());
String screenshotUrl = listener.get();
if (screenshotUrl == null) {
throw new EyesException("Failed posting image");
}
logger.log(getTestId(), Stage.OCR, Pair.of("screenshotUrl", screenshotUrl));
ocrRegion.getAppOutput().setScreenshotUrl(screenshotUrl);
SyncTaskListener> postListener = new SyncTaskListener<>(logger, "getText");
serverConnector.postOcrRegions(postListener, ocrRegion);
List serverResult = postListener.get();
if (serverResult == null) {
throw new EyesException("Failed posting ocr region");
}
logger.log(testId, Stage.OCR, Pair.of("result", result));
if (serverResult.isEmpty()) {
result.add(null);
} else {
result.add(serverResult.get(0));
}
}
return result;
}
protected abstract void getAppOutputForOcr(BaseOcrRegion ocrRegion);
public Map> extractTextRegions(TextRegionSettings textRegionSettings) {
ArgumentGuard.notNull(textRegionSettings, "textRegionSettings");
ScreenshotProvider screenshotProvider = getScreenshotProvider();
BufferedImage viewPortScreenshot;
if (textRegionSettings.getImage() != null) {
viewPortScreenshot = textRegionSettings.getImage();
} else if (screenshotProvider != null) {
viewPortScreenshot = screenshotProvider.getViewPortScreenshot(Stage.OCR);
} else {
throw new IllegalArgumentException("No image for the text region settings");
}
logger.log(getTestId(), Stage.OCR,
Pair.of("textRegionSettings", textRegionSettings),
Pair.of("scaledImageSize", new RectangleSize(viewPortScreenshot.getWidth(), viewPortScreenshot.getHeight())));
debugScreenshotsProvider.save(viewPortScreenshot, "text_regions_final");
byte[] image = ImageUtils.encodeAsPng(viewPortScreenshot);
SyncTaskListener listener = new SyncTaskListener<>(logger, "getTextRegions");
serverConnector.uploadImage(listener, image);
String viewportScreenshotUrl = listener.get();
if (viewportScreenshotUrl == null) {
throw new EyesException("Failed posting viewport image");
}
logger.log(getTestId(), Stage.OCR, Pair.of("screenshotUrl", viewportScreenshotUrl));
String domUrl = null;
if (shouldCaptureDom(null)) {
domUrl = tryCaptureAndPostDom();
}
textRegionSettings.setAppOutput(new AppOutput(getTitle(), null, domUrl, viewportScreenshotUrl, null));
SyncTaskListener