diff --git a/README.md b/README.md
index 40a8167..02e2245 100644
--- a/README.md
+++ b/README.md
@@ -17,7 +17,7 @@ We use interfaces where is possible, so you can implement your own version of ta
### Quick start
-To start the project using Aquality.Selenium framework, you can [download our template BDD project by this link.](https://github.com/aquality-automation/aquality-appium-mobile-java-template)
+To start the project using aquality.appium.mobile framework, you can [download our template BDD project by this link.](https://github.com/aquality-automation/aquality-appium-mobile-java-template)
Alternatively, you can follow the steps below:
diff --git a/pom.xml b/pom.xml
index 15e1d18..efe712a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
com.github.aquality-automation
aquality-appium-mobile
- 3.1.2
+ 4.0.0
jar
Aquality Appium Mobile
@@ -172,7 +172,7 @@
com.github.aquality-automation
aquality-selenium-core
- 2.0.5
+ 3.0.0
diff --git a/src/main/java/aquality/appium/mobile/configuration/Configuration.java b/src/main/java/aquality/appium/mobile/configuration/Configuration.java
index 4a78722..cac74af 100644
--- a/src/main/java/aquality/appium/mobile/configuration/Configuration.java
+++ b/src/main/java/aquality/appium/mobile/configuration/Configuration.java
@@ -1,9 +1,6 @@
package aquality.appium.mobile.configuration;
-import aquality.selenium.core.configurations.IElementCacheConfiguration;
-import aquality.selenium.core.configurations.ILoggerConfiguration;
-import aquality.selenium.core.configurations.IRetryConfiguration;
-import aquality.selenium.core.configurations.ITimeoutConfiguration;
+import aquality.selenium.core.configurations.*;
import com.google.inject.Inject;
public class Configuration implements IConfiguration {
@@ -14,18 +11,20 @@ public class Configuration implements IConfiguration {
private final ILoggerConfiguration loggerConfiguration;
private final IElementCacheConfiguration elementCacheConfiguration;
private final ITouchActionsConfiguration touchActionsConfiguration;
+ private final IVisualizationConfiguration visualizationConfiguration;
@Inject
public Configuration(ITimeoutConfiguration timeoutConfiguration, IRetryConfiguration retryConfiguration,
IApplicationProfile applicationProfile, ILoggerConfiguration loggerConfiguration,
IElementCacheConfiguration elementCacheConfiguration,
- ITouchActionsConfiguration touchActionsConfiguration) {
+ ITouchActionsConfiguration touchActionsConfiguration, IVisualizationConfiguration visualizationConfiguration) {
this.timeoutConfiguration = timeoutConfiguration;
this.retryConfiguration = retryConfiguration;
this.applicationProfile = applicationProfile;
this.loggerConfiguration = loggerConfiguration;
this.elementCacheConfiguration = elementCacheConfiguration;
this.touchActionsConfiguration = touchActionsConfiguration;
+ this.visualizationConfiguration = visualizationConfiguration;
}
@Override
@@ -57,4 +56,9 @@ public IElementCacheConfiguration getElementCacheConfiguration() {
public ITouchActionsConfiguration getTouchActionsConfiguration() {
return touchActionsConfiguration;
}
+
+ @Override
+ public IVisualizationConfiguration getVisualizationConfiguration() {
+ return visualizationConfiguration;
+ }
}
\ No newline at end of file
diff --git a/src/main/java/aquality/appium/mobile/configuration/IConfiguration.java b/src/main/java/aquality/appium/mobile/configuration/IConfiguration.java
index 10369e1..768cf96 100644
--- a/src/main/java/aquality/appium/mobile/configuration/IConfiguration.java
+++ b/src/main/java/aquality/appium/mobile/configuration/IConfiguration.java
@@ -1,10 +1,10 @@
package aquality.appium.mobile.configuration;
-import aquality.selenium.core.configurations.IElementCacheConfiguration;
-import aquality.selenium.core.configurations.ILoggerConfiguration;
-import aquality.selenium.core.configurations.IRetryConfiguration;
-import aquality.selenium.core.configurations.ITimeoutConfiguration;
+import aquality.selenium.core.configurations.*;
+/**
+ * Describes tools configuration.
+ */
public interface IConfiguration {
/**
@@ -48,4 +48,11 @@ public interface IConfiguration {
* @return Configuration of touch actions.
*/
ITouchActionsConfiguration getTouchActionsConfiguration();
+
+ /**
+ * Gets configuration of VisualStateProvider and Dump manager.
+ *
+ * @return Visualization configuration.
+ */
+ IVisualizationConfiguration getVisualizationConfiguration();
}
\ No newline at end of file
diff --git a/src/main/java/aquality/appium/mobile/elements/Element.java b/src/main/java/aquality/appium/mobile/elements/Element.java
index f112017..ccebf02 100644
--- a/src/main/java/aquality/appium/mobile/elements/Element.java
+++ b/src/main/java/aquality/appium/mobile/elements/Element.java
@@ -12,6 +12,7 @@
import aquality.selenium.core.localization.ILocalizationManager;
import aquality.selenium.core.localization.ILocalizedLogger;
import aquality.selenium.core.utilities.IElementActionRetrier;
+import aquality.selenium.core.visualization.IImageComparator;
import aquality.selenium.core.waitings.IConditionalWait;
import org.openqa.selenium.*;
@@ -45,6 +46,11 @@ protected IElementFinder getElementFinder() {
return AqualityServices.get(IElementFinder.class);
}
+ @Override
+ protected IImageComparator getImageComparator() {
+ return AqualityServices.get(IImageComparator.class);
+ }
+
@Override
protected IElementCacheConfiguration getElementCacheConfiguration() {
return AqualityServices.get(IElementCacheConfiguration.class);
diff --git a/src/main/java/aquality/appium/mobile/screens/IScreen.java b/src/main/java/aquality/appium/mobile/screens/IScreen.java
index 8531c96..08da550 100644
--- a/src/main/java/aquality/appium/mobile/screens/IScreen.java
+++ b/src/main/java/aquality/appium/mobile/screens/IScreen.java
@@ -1,10 +1,16 @@
package aquality.appium.mobile.screens;
import aquality.selenium.core.elements.interfaces.IElementStateProvider;
+import aquality.selenium.core.forms.IForm;
+import aquality.selenium.core.visualization.IDumpManager;
import org.openqa.selenium.By;
-import org.openqa.selenium.Dimension;
-public interface IScreen {
+import java.awt.*;
+
+/**
+ * Defines interface for any UI form.
+ */
+public interface IScreen extends IForm {
/**
* Locator for specified screen
*/
@@ -26,4 +32,13 @@ public interface IScreen {
* @return provider to define element's state
*/
IElementStateProvider state();
+
+
+ /**
+ * Gets dump manager for the current form that could be used for visualization purposes,
+ * such as saving and comparing dumps.
+ *
+ * @return form's dump manager.
+ */
+ IDumpManager dump();
}
diff --git a/src/main/java/aquality/appium/mobile/screens/Screen.java b/src/main/java/aquality/appium/mobile/screens/Screen.java
index 0a86a2c..66466e1 100644
--- a/src/main/java/aquality/appium/mobile/screens/Screen.java
+++ b/src/main/java/aquality/appium/mobile/screens/Screen.java
@@ -1,44 +1,84 @@
package aquality.appium.mobile.screens;
import aquality.appium.mobile.application.AqualityServices;
+import aquality.appium.mobile.elements.interfaces.IElement;
import aquality.appium.mobile.elements.interfaces.IElementFactory;
-import aquality.appium.mobile.elements.interfaces.ILabel;
+import aquality.selenium.core.configurations.IVisualizationConfiguration;
import aquality.selenium.core.elements.interfaces.IElementStateProvider;
+import aquality.selenium.core.forms.Form;
+import aquality.selenium.core.localization.ILocalizedLogger;
import org.openqa.selenium.By;
-import org.openqa.selenium.Dimension;
-public abstract class Screen implements IScreen {
+import java.awt.*;
+/**
+ * Defines base class for any UI form.
+ */
+public abstract class Screen extends Form implements IScreen {
+ /**
+ * Locator for specified form
+ */
private final By locator;
+ /**
+ * Name of specified form
+ */
private final String name;
- private final ILabel screenLabel;
+ /**
+ * Screen element defined by its locator and name.
+ */
+ private final IElement screenElement;
/**
* Constructor with parameters
*/
protected Screen(By locator, String name) {
+ super(IElement.class);
this.locator = locator;
this.name = name;
- this.screenLabel = getElementFactory().getLabel(locator, name);
+ this.screenElement = getElementFactory().getLabel(locator, name);
}
+ @Override
public By getLocator() {
return locator;
}
+ @Override
public String getName() {
return name;
}
+ @Override
public Dimension getSize() {
- return screenLabel.getElement().getSize();
+ return screenElement.visual().getSize();
}
+ @Override
public IElementStateProvider state() {
- return screenLabel.state();
+ return screenElement.state();
+ }
+
+ /**
+ * Gets form element defined by its locator and name.
+ * Could be used to find child elements relative to form element.
+ *
+ * @return form element.
+ */
+ protected IElement getScreenElement() {
+ return screenElement;
}
protected IElementFactory getElementFactory(){
return AqualityServices.getElementFactory();
}
+
+ @Override
+ protected IVisualizationConfiguration getVisualizationConfiguration() {
+ return AqualityServices.getConfiguration().getVisualizationConfiguration();
+ }
+
+ @Override
+ protected ILocalizedLogger getLocalizedLogger() {
+ return AqualityServices.getLocalizedLogger();
+ }
}
diff --git a/src/main/resources/settings.json b/src/main/resources/settings.json
index f427ceb..71111e0 100644
--- a/src/main/resources/settings.json
+++ b/src/main/resources/settings.json
@@ -51,5 +51,13 @@
"verticalOffset": 0.2,
"horizontalOffset": 0.5
}
+ },
+ "visualization": {
+ "imageExtension": "png",
+ "maxFullFileNameLength": 255,
+ "defaultThreshold": 0.012,
+ "comparisonWidth": 16,
+ "comparisonHeight": 16,
+ "pathToDumps": "./src/test/resources/visualDumps/"
}
}
\ No newline at end of file
diff --git a/src/test/java/samples/android/nativeapp/AndroidBasicInteractionsTest.java b/src/test/java/samples/android/nativeapp/AndroidBasicInteractionsTest.java
index 15e9d43..8cea72f 100644
--- a/src/test/java/samples/android/nativeapp/AndroidBasicInteractionsTest.java
+++ b/src/test/java/samples/android/nativeapp/AndroidBasicInteractionsTest.java
@@ -63,6 +63,19 @@ public void testSendKeys() {
Assert.assertEquals(searchScreen.getSearchResult(), query, "Search result don't match to entered query");
}
+ @Test
+ public void testSaveAndCompareScreenDump()
+ {
+ InvokeSearchScreen searchScreen = ApplicationActivity.SEARCH.open();
+ Assert.assertTrue(searchScreen.state().isDisplayed(), String.format("%s should be opened", searchScreen.getName()));
+ final String customDumpName = String.format("my dump of %s", searchScreen.getName());
+ searchScreen.dump().save(customDumpName);
+ Assert.assertEquals(searchScreen.dump().compare(customDumpName), 0, "Current screen should have no visual difference comparing to just saved dump");
+ final String query = "Hello world!";
+ searchScreen.typeQuery(query);
+ Assert.assertTrue(searchScreen.dump().compare() > 0, "Current screen after the search should have visual difference comparing to dump saved");
+ }
+
@Test
public void testRadioButton() {
ITestRadioButton.super.testRadioButton();
diff --git a/src/test/java/samples/android/nativeapp/apidemos/screens/AndroidScreen.java b/src/test/java/samples/android/nativeapp/apidemos/screens/AndroidScreen.java
index d4ee26c..67222ba 100644
--- a/src/test/java/samples/android/nativeapp/apidemos/screens/AndroidScreen.java
+++ b/src/test/java/samples/android/nativeapp/apidemos/screens/AndroidScreen.java
@@ -12,7 +12,6 @@ protected AndroidScreen(By locator, String name) {
super(locator, name);
}
- @SuppressWarnings("unchecked")
protected void startActivity(Activity activity) {
AqualityServices.getLocalizedLogger().info("loc.application.android.activity.start",
activity.getAppActivity(),
diff --git a/src/test/java/samples/android/nativeapp/apidemos/screens/InvokeSearchScreen.java b/src/test/java/samples/android/nativeapp/apidemos/screens/InvokeSearchScreen.java
index 4342e1b..b805733 100644
--- a/src/test/java/samples/android/nativeapp/apidemos/screens/InvokeSearchScreen.java
+++ b/src/test/java/samples/android/nativeapp/apidemos/screens/InvokeSearchScreen.java
@@ -16,10 +16,14 @@ public InvokeSearchScreen() {
}
public void submitSearch(String query) {
- txbSearch.clearAndType(query);
+ typeQuery(query);
btnStartSearch.click();
}
+ public void typeQuery(String query) {
+ txbSearch.clearAndType(query);
+ }
+
public String getSearchResult() {
return lblSearchResult.getText();
}
diff --git a/src/test/resources/settings.json b/src/test/resources/settings.json
index f04bb75..bc76c3b 100644
--- a/src/test/resources/settings.json
+++ b/src/test/resources/settings.json
@@ -53,5 +53,13 @@
"verticalOffset": 0.2,
"horizontalOffset": 0.5
}
+ },
+ "visualization": {
+ "imageExtension": "png",
+ "maxFullFileNameLength": 255,
+ "defaultThreshold": 0.012,
+ "comparisonWidth": 16,
+ "comparisonHeight": 16,
+ "pathToDumps": "./src/test/resources/visualDumps/"
}
}
\ No newline at end of file
diff --git a/src/test/resources/visualDumps/Invoke Search/btnStartSearch.png b/src/test/resources/visualDumps/Invoke Search/btnStartSearch.png
new file mode 100644
index 0000000..7453c46
Binary files /dev/null and b/src/test/resources/visualDumps/Invoke Search/btnStartSearch.png differ
diff --git a/src/test/resources/visualDumps/Invoke Search/screenElement.png b/src/test/resources/visualDumps/Invoke Search/screenElement.png
new file mode 100644
index 0000000..c03b3d8
Binary files /dev/null and b/src/test/resources/visualDumps/Invoke Search/screenElement.png differ
diff --git a/src/test/resources/visualDumps/Invoke Search/txbSearch.png b/src/test/resources/visualDumps/Invoke Search/txbSearch.png
new file mode 100644
index 0000000..e2cdb99
Binary files /dev/null and b/src/test/resources/visualDumps/Invoke Search/txbSearch.png differ