Skip to content

Commit

Permalink
Merge pull request #77 from aquality-automation/feature/visualization
Browse files Browse the repository at this point in the history
[Feature] Visualization
  • Loading branch information
aqualityAutomation authored Mar 14, 2023
2 parents e024d1b + 53983fa commit 12e470b
Show file tree
Hide file tree
Showing 44 changed files with 1,634 additions and 23 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
# Log file
*.log

# Visualization
visualDumps/

# BlueJ files
*.ctxt

Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>com.github.aquality-automation</groupId>
<artifactId>aquality-selenium-core</artifactId>
<version>2.0.6</version>
<version>3.0.0</version>

<packaging>jar</packaging>
<name>Aquality Selenium Core</name>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
import aquality.selenium.core.utilities.IElementActionRetrier;
import aquality.selenium.core.utilities.ISettingsFile;
import aquality.selenium.core.utilities.IUtilitiesModule;
import aquality.selenium.core.visualization.IImageComparator;
import aquality.selenium.core.visualization.IVisualizationModule;
import aquality.selenium.core.waitings.IConditionalWait;
import aquality.selenium.core.waitings.IWaitingsModule;
import com.google.inject.AbstractModule;
Expand All @@ -22,7 +24,8 @@
* Describes all dependencies which is registered for the project.
*/
public class AqualityModule<T extends IApplication> extends AbstractModule
implements IConfigurationsModule, IElementsModule, ILocalizationModule, IUtilitiesModule, IWaitingsModule {
implements IConfigurationsModule, IElementsModule, ILocalizationModule, IUtilitiesModule, IWaitingsModule,
IVisualizationModule {

private final Provider<T> applicationProvider;

Expand All @@ -42,12 +45,14 @@ protected void configure() {
bind(ITimeoutConfiguration.class).to(getTimeoutConfigurationImplementation()).in(Singleton.class);
bind(IRetryConfiguration.class).to(getRetryConfigurationImplementation()).in(Singleton.class);
bind(IElementCacheConfiguration.class).to(getElementCacheConfigurationImplementation()).in(Singleton.class);
bind(IVisualizationConfiguration.class).to(getVisualConfigurationImplementation()).in(Singleton.class);
bind(IElementActionRetrier.class).to(getElementActionRetrierImplementation()).in(Singleton.class);
bind(IActionRetrier.class).to(getActionRetrierImplementation()).in(Singleton.class);
bind(ILocalizationManager.class).to(getLocalizationManagerImplementation()).in(Singleton.class);
bind(ILocalizedLogger.class).to(getLocalizedLoggerImplementation()).in(Singleton.class);
bind(IConditionalWait.class).to(getConditionalWaitImplementation());
bind(IElementFinder.class).to(getElementFinderImplementation());
bind(IElementFactory.class).to(getElementFactoryImplementation());
bind(IImageComparator.class).to(getImageComparatorImplementation());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@
* Describes implementations of configurations to be registered in DI container.
*/
public interface IConfigurationsModule {
/**
* @return class which implements {@link IVisualizationConfiguration}
*/
default Class<? extends IVisualizationConfiguration> getVisualConfigurationImplementation() {
return VisualizationConfiguration.class;
}

/**
* @return class which implements {@link IElementCacheConfiguration}
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package aquality.selenium.core.configurations;

/**
* Represents visualization configuration, used for image comparison.
*/
public interface IVisualizationConfiguration {
/**
* Image format for comparison.
* @return image format.
*/
String getImageFormat();

/**
* Gets maximum length of full file name with path for image comparison.
* @return maximum symbols count in file path.
*/
int getMaxFullFileNameLength();

/**
* Gets default threshold used for image comparison.
* @return The default threshold value.
*/
float getDefaultThreshold();

/**
* Gets width of the image resized for comparison.
* @return comparison width.
*/
int getComparisonWidth();

/**
* Gets height of the image resized for comparison.
* @return comparison height.
*/
int getComparisonHeight();

/**
* Gets path used to save and load page dumps.
* @return path to dumps.
*/
String getPathToDumps();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package aquality.selenium.core.configurations;

import aquality.selenium.core.logging.Logger;
import aquality.selenium.core.utilities.ISettingsFile;
import com.google.inject.Inject;

import java.io.File;
import java.io.IOException;

/**
* Represents visualization configuration, used for image comparison.
* Uses {@link ISettingsFile} as source for configuration values.
*/
public class VisualizationConfiguration implements IVisualizationConfiguration {
private String imageFormat;
private Integer maxFullFileNameLength;
private Float defaultThreshold;
private Integer comparisonWidth;
private Integer comparisonHeight;
private String pathToDumps;

private final ISettingsFile settingsFile;

/**
* Instantiates class using {@link ISettingsFile} with visualization settings.
* @param settingsFile settings file.
*/
@Inject
public VisualizationConfiguration(ISettingsFile settingsFile) {
this.settingsFile = settingsFile;
}

@Override
public String getImageFormat() {
if (imageFormat == null) {
String valueFromConfig = settingsFile.getValueOrDefault("/visualization/imageExtension", "png").toString();
imageFormat = valueFromConfig.startsWith(".") ? valueFromConfig.substring(1) : valueFromConfig;
}
return imageFormat;
}

@Override
public int getMaxFullFileNameLength() {
if (maxFullFileNameLength == null) {
maxFullFileNameLength = Integer.valueOf(
settingsFile.getValueOrDefault("/visualization/maxFullFileNameLength", 255).toString());
}
return maxFullFileNameLength;
}

@Override
public float getDefaultThreshold() {
if (defaultThreshold == null) {
defaultThreshold = Float.valueOf(
settingsFile.getValueOrDefault("/visualization/defaultThreshold", 0.012f).toString());
}
return defaultThreshold;
}

@Override
public int getComparisonWidth() {
if (comparisonWidth == null) {
comparisonWidth = Integer.valueOf(
settingsFile.getValueOrDefault("/visualization/comparisonWidth", 16).toString());
}
return comparisonWidth;
}

@Override
public int getComparisonHeight() {
if (comparisonHeight == null) {
comparisonHeight = Integer.valueOf(
settingsFile.getValueOrDefault("/visualization/comparisonHeight", 16).toString());
}
return comparisonHeight;
}

@Override
public String getPathToDumps() {
if (pathToDumps == null) {
pathToDumps = settingsFile.getValueOrDefault("/visualization/pathToDumps", "./src/test/resources/visualDumps/").toString();
if (pathToDumps.startsWith(".")) {
try {
pathToDumps = new File(pathToDumps).getCanonicalPath();
} catch (IOException e) {
String errorMessage = "Failed to resolve path to dumps: " + e.getMessage();
Logger.getInstance().fatal(errorMessage, e);
throw new IllegalArgumentException(errorMessage, e);
}
}
}
return pathToDumps;
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package aquality.selenium.core.elements;

import aquality.selenium.core.elements.interfaces.IElementCacheHandler;
import aquality.selenium.core.elements.interfaces.ILogElementState;
import aquality.selenium.core.logging.ILogElementState;
import aquality.selenium.core.waitings.IConditionalWait;
import org.openqa.selenium.By;
import org.openqa.selenium.NoSuchElementException;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package aquality.selenium.core.elements;

import aquality.selenium.core.elements.interfaces.IElementFinder;
import aquality.selenium.core.elements.interfaces.ILogElementState;
import aquality.selenium.core.logging.ILogElementState;
import aquality.selenium.core.waitings.IConditionalWait;
import org.openqa.selenium.By;

Expand Down
16 changes: 16 additions & 0 deletions src/main/java/aquality/selenium/core/elements/Element.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,13 @@
import aquality.selenium.core.elements.interfaces.*;
import aquality.selenium.core.localization.ILocalizationManager;
import aquality.selenium.core.localization.ILocalizedLogger;
import aquality.selenium.core.logging.ILogElementState;
import aquality.selenium.core.logging.ILogVisualState;
import aquality.selenium.core.logging.Logger;
import aquality.selenium.core.utilities.IElementActionRetrier;
import aquality.selenium.core.visualization.IImageComparator;
import aquality.selenium.core.visualization.IVisualStateProvider;
import aquality.selenium.core.visualization.VisualStateProvider;
import aquality.selenium.core.waitings.IConditionalWait;
import org.openqa.selenium.By;
import org.openqa.selenium.NoSuchElementException;
Expand Down Expand Up @@ -37,6 +42,8 @@ protected Element(final By loc, final String name, final ElementState state) {

protected abstract IElementFinder getElementFinder();

protected abstract IImageComparator getImageComparator();

protected abstract IElementCacheConfiguration getElementCacheConfiguration();

protected abstract IElementActionRetrier getElementActionRetrier();
Expand Down Expand Up @@ -70,6 +77,10 @@ protected ILogElementState logElementState() {
getLocalizationManager().getLocalizedMessage(stateKey)));
}

protected ILogVisualState logVisualState() {
return this::logElementAction;
}

@Override
public By getLocator() {
return locator;
Expand All @@ -87,6 +98,11 @@ public IElementStateProvider state() {
: new DefaultElementStateProvider(locator, getConditionalWait(), getElementFinder(), logElementState());
}

@Override
public IVisualStateProvider visual() {
return new VisualStateProvider(getImageComparator(), getElementActionRetrier(), this::getElement, logVisualState());
}

@Override
public RemoteWebElement getElement(Duration timeout) {
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ protected void waitForElementsCount(By locator, ElementsCount count, ElementStat
localizationManager.getLocalizedMessage("loc.elements.found.but.should.not",
locator.toString(), state.toString()));
break;
case MORE_THEN_ZERO:
case MORE_THAN_ZERO:
conditionalWait.waitForTrue(() -> !elementFinder.findElements(locator, state, ZERO_TIMEOUT).isEmpty(),
localizationManager.getLocalizedMessage("loc.no.elements.found.by.locator",
locator.toString(), state.toString()));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package aquality.selenium.core.elements;

import aquality.selenium.core.elements.interfaces.IElementStateProvider;
import aquality.selenium.core.elements.interfaces.ILogElementState;
import aquality.selenium.core.logging.ILogElementState;
import org.openqa.selenium.WebElement;

public abstract class ElementStateProvider implements IElementStateProvider {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@

public enum ElementsCount {
ZERO,
MORE_THEN_ZERO,
MORE_THAN_ZERO,
ANY
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package aquality.selenium.core.elements.interfaces;

import aquality.selenium.core.visualization.IVisualStateProvider;
import org.openqa.selenium.By;
import org.openqa.selenium.remote.RemoteWebElement;

Expand Down Expand Up @@ -27,6 +28,12 @@ public interface IElement extends IParent {
*/
IElementStateProvider state();

/**
* Gets element visual state.
* @return provider to define element's visual state.
*/
IVisualStateProvider visual();

/**
* Gets current element by specified {@link #getLocator()}
* Default timeout is provided in {@link aquality.selenium.core.configurations.ITimeoutConfiguration}
Expand Down
Loading

0 comments on commit 12e470b

Please sign in to comment.