Skip to content

Commit 12e470b

Browse files
Merge pull request #77 from aquality-automation/feature/visualization
[Feature] Visualization
2 parents e024d1b + 53983fa commit 12e470b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+1634
-23
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
# Log file
55
*.log
66

7+
# Visualization
8+
visualDumps/
9+
710
# BlueJ files
811
*.ctxt
912

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
<groupId>com.github.aquality-automation</groupId>
88
<artifactId>aquality-selenium-core</artifactId>
9-
<version>2.0.6</version>
9+
<version>3.0.0</version>
1010

1111
<packaging>jar</packaging>
1212
<name>Aquality Selenium Core</name>

src/main/java/aquality/selenium/core/applications/AqualityModule.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
import aquality.selenium.core.utilities.IElementActionRetrier;
1313
import aquality.selenium.core.utilities.ISettingsFile;
1414
import aquality.selenium.core.utilities.IUtilitiesModule;
15+
import aquality.selenium.core.visualization.IImageComparator;
16+
import aquality.selenium.core.visualization.IVisualizationModule;
1517
import aquality.selenium.core.waitings.IConditionalWait;
1618
import aquality.selenium.core.waitings.IWaitingsModule;
1719
import com.google.inject.AbstractModule;
@@ -22,7 +24,8 @@
2224
* Describes all dependencies which is registered for the project.
2325
*/
2426
public class AqualityModule<T extends IApplication> extends AbstractModule
25-
implements IConfigurationsModule, IElementsModule, ILocalizationModule, IUtilitiesModule, IWaitingsModule {
27+
implements IConfigurationsModule, IElementsModule, ILocalizationModule, IUtilitiesModule, IWaitingsModule,
28+
IVisualizationModule {
2629

2730
private final Provider<T> applicationProvider;
2831

@@ -42,12 +45,14 @@ protected void configure() {
4245
bind(ITimeoutConfiguration.class).to(getTimeoutConfigurationImplementation()).in(Singleton.class);
4346
bind(IRetryConfiguration.class).to(getRetryConfigurationImplementation()).in(Singleton.class);
4447
bind(IElementCacheConfiguration.class).to(getElementCacheConfigurationImplementation()).in(Singleton.class);
48+
bind(IVisualizationConfiguration.class).to(getVisualConfigurationImplementation()).in(Singleton.class);
4549
bind(IElementActionRetrier.class).to(getElementActionRetrierImplementation()).in(Singleton.class);
4650
bind(IActionRetrier.class).to(getActionRetrierImplementation()).in(Singleton.class);
4751
bind(ILocalizationManager.class).to(getLocalizationManagerImplementation()).in(Singleton.class);
4852
bind(ILocalizedLogger.class).to(getLocalizedLoggerImplementation()).in(Singleton.class);
4953
bind(IConditionalWait.class).to(getConditionalWaitImplementation());
5054
bind(IElementFinder.class).to(getElementFinderImplementation());
5155
bind(IElementFactory.class).to(getElementFactoryImplementation());
56+
bind(IImageComparator.class).to(getImageComparatorImplementation());
5257
}
5358
}

src/main/java/aquality/selenium/core/configurations/IConfigurationsModule.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,13 @@
44
* Describes implementations of configurations to be registered in DI container.
55
*/
66
public interface IConfigurationsModule {
7+
/**
8+
* @return class which implements {@link IVisualizationConfiguration}
9+
*/
10+
default Class<? extends IVisualizationConfiguration> getVisualConfigurationImplementation() {
11+
return VisualizationConfiguration.class;
12+
}
13+
714
/**
815
* @return class which implements {@link IElementCacheConfiguration}
916
*/
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package aquality.selenium.core.configurations;
2+
3+
/**
4+
* Represents visualization configuration, used for image comparison.
5+
*/
6+
public interface IVisualizationConfiguration {
7+
/**
8+
* Image format for comparison.
9+
* @return image format.
10+
*/
11+
String getImageFormat();
12+
13+
/**
14+
* Gets maximum length of full file name with path for image comparison.
15+
* @return maximum symbols count in file path.
16+
*/
17+
int getMaxFullFileNameLength();
18+
19+
/**
20+
* Gets default threshold used for image comparison.
21+
* @return The default threshold value.
22+
*/
23+
float getDefaultThreshold();
24+
25+
/**
26+
* Gets width of the image resized for comparison.
27+
* @return comparison width.
28+
*/
29+
int getComparisonWidth();
30+
31+
/**
32+
* Gets height of the image resized for comparison.
33+
* @return comparison height.
34+
*/
35+
int getComparisonHeight();
36+
37+
/**
38+
* Gets path used to save and load page dumps.
39+
* @return path to dumps.
40+
*/
41+
String getPathToDumps();
42+
}
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
package aquality.selenium.core.configurations;
2+
3+
import aquality.selenium.core.logging.Logger;
4+
import aquality.selenium.core.utilities.ISettingsFile;
5+
import com.google.inject.Inject;
6+
7+
import java.io.File;
8+
import java.io.IOException;
9+
10+
/**
11+
* Represents visualization configuration, used for image comparison.
12+
* Uses {@link ISettingsFile} as source for configuration values.
13+
*/
14+
public class VisualizationConfiguration implements IVisualizationConfiguration {
15+
private String imageFormat;
16+
private Integer maxFullFileNameLength;
17+
private Float defaultThreshold;
18+
private Integer comparisonWidth;
19+
private Integer comparisonHeight;
20+
private String pathToDumps;
21+
22+
private final ISettingsFile settingsFile;
23+
24+
/**
25+
* Instantiates class using {@link ISettingsFile} with visualization settings.
26+
* @param settingsFile settings file.
27+
*/
28+
@Inject
29+
public VisualizationConfiguration(ISettingsFile settingsFile) {
30+
this.settingsFile = settingsFile;
31+
}
32+
33+
@Override
34+
public String getImageFormat() {
35+
if (imageFormat == null) {
36+
String valueFromConfig = settingsFile.getValueOrDefault("/visualization/imageExtension", "png").toString();
37+
imageFormat = valueFromConfig.startsWith(".") ? valueFromConfig.substring(1) : valueFromConfig;
38+
}
39+
return imageFormat;
40+
}
41+
42+
@Override
43+
public int getMaxFullFileNameLength() {
44+
if (maxFullFileNameLength == null) {
45+
maxFullFileNameLength = Integer.valueOf(
46+
settingsFile.getValueOrDefault("/visualization/maxFullFileNameLength", 255).toString());
47+
}
48+
return maxFullFileNameLength;
49+
}
50+
51+
@Override
52+
public float getDefaultThreshold() {
53+
if (defaultThreshold == null) {
54+
defaultThreshold = Float.valueOf(
55+
settingsFile.getValueOrDefault("/visualization/defaultThreshold", 0.012f).toString());
56+
}
57+
return defaultThreshold;
58+
}
59+
60+
@Override
61+
public int getComparisonWidth() {
62+
if (comparisonWidth == null) {
63+
comparisonWidth = Integer.valueOf(
64+
settingsFile.getValueOrDefault("/visualization/comparisonWidth", 16).toString());
65+
}
66+
return comparisonWidth;
67+
}
68+
69+
@Override
70+
public int getComparisonHeight() {
71+
if (comparisonHeight == null) {
72+
comparisonHeight = Integer.valueOf(
73+
settingsFile.getValueOrDefault("/visualization/comparisonHeight", 16).toString());
74+
}
75+
return comparisonHeight;
76+
}
77+
78+
@Override
79+
public String getPathToDumps() {
80+
if (pathToDumps == null) {
81+
pathToDumps = settingsFile.getValueOrDefault("/visualization/pathToDumps", "./src/test/resources/visualDumps/").toString();
82+
if (pathToDumps.startsWith(".")) {
83+
try {
84+
pathToDumps = new File(pathToDumps).getCanonicalPath();
85+
} catch (IOException e) {
86+
String errorMessage = "Failed to resolve path to dumps: " + e.getMessage();
87+
Logger.getInstance().fatal(errorMessage, e);
88+
throw new IllegalArgumentException(errorMessage, e);
89+
}
90+
}
91+
}
92+
return pathToDumps;
93+
}
94+
}

src/main/java/aquality/selenium/core/elements/CachedElementStateProvider.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package aquality.selenium.core.elements;
22

33
import aquality.selenium.core.elements.interfaces.IElementCacheHandler;
4-
import aquality.selenium.core.elements.interfaces.ILogElementState;
4+
import aquality.selenium.core.logging.ILogElementState;
55
import aquality.selenium.core.waitings.IConditionalWait;
66
import org.openqa.selenium.By;
77
import org.openqa.selenium.NoSuchElementException;

src/main/java/aquality/selenium/core/elements/DefaultElementStateProvider.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package aquality.selenium.core.elements;
22

33
import aquality.selenium.core.elements.interfaces.IElementFinder;
4-
import aquality.selenium.core.elements.interfaces.ILogElementState;
4+
import aquality.selenium.core.logging.ILogElementState;
55
import aquality.selenium.core.waitings.IConditionalWait;
66
import org.openqa.selenium.By;
77

src/main/java/aquality/selenium/core/elements/Element.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,13 @@
66
import aquality.selenium.core.elements.interfaces.*;
77
import aquality.selenium.core.localization.ILocalizationManager;
88
import aquality.selenium.core.localization.ILocalizedLogger;
9+
import aquality.selenium.core.logging.ILogElementState;
10+
import aquality.selenium.core.logging.ILogVisualState;
911
import aquality.selenium.core.logging.Logger;
1012
import aquality.selenium.core.utilities.IElementActionRetrier;
13+
import aquality.selenium.core.visualization.IImageComparator;
14+
import aquality.selenium.core.visualization.IVisualStateProvider;
15+
import aquality.selenium.core.visualization.VisualStateProvider;
1116
import aquality.selenium.core.waitings.IConditionalWait;
1217
import org.openqa.selenium.By;
1318
import org.openqa.selenium.NoSuchElementException;
@@ -37,6 +42,8 @@ protected Element(final By loc, final String name, final ElementState state) {
3742

3843
protected abstract IElementFinder getElementFinder();
3944

45+
protected abstract IImageComparator getImageComparator();
46+
4047
protected abstract IElementCacheConfiguration getElementCacheConfiguration();
4148

4249
protected abstract IElementActionRetrier getElementActionRetrier();
@@ -70,6 +77,10 @@ protected ILogElementState logElementState() {
7077
getLocalizationManager().getLocalizedMessage(stateKey)));
7178
}
7279

80+
protected ILogVisualState logVisualState() {
81+
return this::logElementAction;
82+
}
83+
7384
@Override
7485
public By getLocator() {
7586
return locator;
@@ -87,6 +98,11 @@ public IElementStateProvider state() {
8798
: new DefaultElementStateProvider(locator, getConditionalWait(), getElementFinder(), logElementState());
8899
}
89100

101+
@Override
102+
public IVisualStateProvider visual() {
103+
return new VisualStateProvider(getImageComparator(), getElementActionRetrier(), this::getElement, logVisualState());
104+
}
105+
90106
@Override
91107
public RemoteWebElement getElement(Duration timeout) {
92108
try {

src/main/java/aquality/selenium/core/elements/ElementFactory.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ protected void waitForElementsCount(By locator, ElementsCount count, ElementStat
106106
localizationManager.getLocalizedMessage("loc.elements.found.but.should.not",
107107
locator.toString(), state.toString()));
108108
break;
109-
case MORE_THEN_ZERO:
109+
case MORE_THAN_ZERO:
110110
conditionalWait.waitForTrue(() -> !elementFinder.findElements(locator, state, ZERO_TIMEOUT).isEmpty(),
111111
localizationManager.getLocalizedMessage("loc.no.elements.found.by.locator",
112112
locator.toString(), state.toString()));

0 commit comments

Comments
 (0)