diff --git a/pom.xml b/pom.xml
index 3dd0a26..58203a1 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
com.github.aquality-automation
aquality-appium-mobile
- 2.0.0
+ 2.1.0
jar
Aquality Appium Mobile
diff --git a/src/main/java/aquality/appium/mobile/actions/IActionsModule.java b/src/main/java/aquality/appium/mobile/actions/IActionsModule.java
new file mode 100644
index 0000000..12ac05a
--- /dev/null
+++ b/src/main/java/aquality/appium/mobile/actions/IActionsModule.java
@@ -0,0 +1,16 @@
+package aquality.appium.mobile.actions;
+
+import aquality.appium.mobile.configuration.IConfigurationsModule;
+
+/**
+ * Describes implementations of actions services to be registered in DI container.
+ */
+public interface IActionsModule extends IConfigurationsModule {
+
+ /**
+ * @return class which implements {@link ITouchActions}
+ */
+ default Class extends ITouchActions> getTouchActionsImplementation() {
+ return TouchActions.class;
+ }
+}
diff --git a/src/main/java/aquality/appium/mobile/actions/ITouchActions.java b/src/main/java/aquality/appium/mobile/actions/ITouchActions.java
new file mode 100644
index 0000000..6f4c624
--- /dev/null
+++ b/src/main/java/aquality/appium/mobile/actions/ITouchActions.java
@@ -0,0 +1,25 @@
+package aquality.appium.mobile.actions;
+
+import org.openqa.selenium.Point;
+
+/**
+ * Describes general Touch Actions.
+ */
+public interface ITouchActions {
+
+ /**
+ * Swipes from start point to end point using TouchAction.
+ *
+ * @param startPoint point on screen to swipe from.
+ * @param endPoint point on screen to swipe to.
+ */
+ void swipe(Point startPoint, Point endPoint);
+
+ /**
+ * Performs long press action and moves cursor from a start point to an end point imitating the swipe action.
+ *
+ * @param startPoint point on screen to swipe from.
+ * @param endPoint point on screen to swipe to.
+ */
+ void swipeWithLongPress(Point startPoint, Point endPoint);
+}
diff --git a/src/main/java/aquality/appium/mobile/actions/SwipeDirection.java b/src/main/java/aquality/appium/mobile/actions/SwipeDirection.java
new file mode 100644
index 0000000..888610b
--- /dev/null
+++ b/src/main/java/aquality/appium/mobile/actions/SwipeDirection.java
@@ -0,0 +1,11 @@
+package aquality.appium.mobile.actions;
+
+/**
+ * The enum describing the possible swipe directions.
+ */
+public enum SwipeDirection {
+ UP,
+ DOWN,
+ LEFT,
+ RIGHT;
+}
diff --git a/src/main/java/aquality/appium/mobile/actions/TouchActions.java b/src/main/java/aquality/appium/mobile/actions/TouchActions.java
new file mode 100644
index 0000000..848b30c
--- /dev/null
+++ b/src/main/java/aquality/appium/mobile/actions/TouchActions.java
@@ -0,0 +1,44 @@
+package aquality.appium.mobile.actions;
+
+import aquality.appium.mobile.application.AqualityServices;
+import aquality.appium.mobile.configuration.ITouchActionsConfiguration;
+import aquality.selenium.core.utilities.IElementActionRetrier;
+import io.appium.java_client.TouchAction;
+import io.appium.java_client.touch.offset.PointOption;
+import org.openqa.selenium.Point;
+import java.util.function.UnaryOperator;
+import static io.appium.java_client.touch.WaitOptions.waitOptions;
+
+public class TouchActions implements ITouchActions {
+
+ @Override
+ public void swipe(Point startPoint, Point endPoint) {
+ AqualityServices.getLocalizedLogger().info(
+ "loc.action.swipe",
+ startPoint.getX(),
+ startPoint.getY(),
+ endPoint.getX(),
+ endPoint.getY());
+ performTouchAction(touchAction -> touchAction
+ .press(PointOption.point(startPoint))
+ .waitAction(waitOptions(AqualityServices.get(ITouchActionsConfiguration.class).getSwipeDuration())),
+ endPoint);
+ }
+
+ @Override
+ public void swipeWithLongPress(Point startPoint, Point endPoint) {
+ AqualityServices.getLocalizedLogger().info(
+ "loc.action.swipeLongPress",
+ startPoint.getX(),
+ startPoint.getY(),
+ endPoint.getX(),
+ endPoint.getY());
+ performTouchAction(touchAction -> touchAction.longPress(PointOption.point(startPoint)), endPoint);
+ }
+
+ protected void performTouchAction(UnaryOperator> function, Point endPoint) {
+ TouchAction> touchAction = new TouchAction<>(AqualityServices.getApplication().getDriver());
+ AqualityServices.get(IElementActionRetrier.class).doWithRetry(() ->
+ function.apply(touchAction).moveTo(PointOption.point(endPoint)).release().perform());
+ }
+}
diff --git a/src/main/java/aquality/appium/mobile/application/AqualityServices.java b/src/main/java/aquality/appium/mobile/application/AqualityServices.java
index b36be72..6c7c3d9 100644
--- a/src/main/java/aquality/appium/mobile/application/AqualityServices.java
+++ b/src/main/java/aquality/appium/mobile/application/AqualityServices.java
@@ -1,5 +1,6 @@
package aquality.appium.mobile.application;
+import aquality.appium.mobile.actions.ITouchActions;
import aquality.appium.mobile.configuration.IApplicationProfile;
import aquality.appium.mobile.configuration.IConfiguration;
import aquality.appium.mobile.configuration.ILocalServiceSettings;
@@ -190,4 +191,13 @@ public static ILocalServiceSettings getLocalServiceSettings() {
public static IConfiguration getConfiguration() {
return get(IConfiguration.class);
}
+
+ /**
+ * Gets the the utility used to perform touch actions.
+ *
+ * @return instance of touch actions.
+ */
+ public static ITouchActions getTouchActions() {
+ return get(ITouchActions.class);
+ }
}
diff --git a/src/main/java/aquality/appium/mobile/application/MobileModule.java b/src/main/java/aquality/appium/mobile/application/MobileModule.java
index 74c342c..6932974 100644
--- a/src/main/java/aquality/appium/mobile/application/MobileModule.java
+++ b/src/main/java/aquality/appium/mobile/application/MobileModule.java
@@ -1,9 +1,12 @@
package aquality.appium.mobile.application;
+import aquality.appium.mobile.actions.IActionsModule;
+import aquality.appium.mobile.actions.ITouchActions;
import aquality.appium.mobile.configuration.IApplicationProfile;
import aquality.appium.mobile.configuration.IConfiguration;
import aquality.appium.mobile.configuration.IConfigurationsModule;
import aquality.appium.mobile.configuration.ILocalServiceSettings;
+import aquality.appium.mobile.configuration.ITouchActionsConfiguration;
import aquality.appium.mobile.elements.IElementsModule;
import aquality.appium.mobile.elements.interfaces.IElementFactory;
import aquality.appium.mobile.screens.screenfactory.IScreenFactory;
@@ -12,7 +15,7 @@
import com.google.inject.Provider;
import com.google.inject.Singleton;
-public class MobileModule extends AqualityModule implements IConfigurationsModule, IElementsModule, IScreensModule {
+public class MobileModule extends AqualityModule implements IConfigurationsModule, IElementsModule, IScreensModule, IActionsModule {
public MobileModule(Provider applicationProvider) {
super(applicationProvider);
@@ -26,5 +29,7 @@ protected void configure() {
bind(IConfiguration.class).to(getConfigurationImplementation());
bind(IElementFactory.class).to(getElementFactoryImplementation());
bind(IScreenFactory.class).to(getScreenFactoryImplementation());
+ bind(ITouchActionsConfiguration.class).to(getTouchActionsConfigurationImplementation());
+ bind(ITouchActions.class).to(getTouchActionsImplementation());
}
}
diff --git a/src/main/java/aquality/appium/mobile/configuration/Configuration.java b/src/main/java/aquality/appium/mobile/configuration/Configuration.java
index 8ce2ce7..4a78722 100644
--- a/src/main/java/aquality/appium/mobile/configuration/Configuration.java
+++ b/src/main/java/aquality/appium/mobile/configuration/Configuration.java
@@ -13,16 +13,19 @@ public class Configuration implements IConfiguration {
private final IApplicationProfile applicationProfile;
private final ILoggerConfiguration loggerConfiguration;
private final IElementCacheConfiguration elementCacheConfiguration;
+ private final ITouchActionsConfiguration touchActionsConfiguration;
@Inject
public Configuration(ITimeoutConfiguration timeoutConfiguration, IRetryConfiguration retryConfiguration,
IApplicationProfile applicationProfile, ILoggerConfiguration loggerConfiguration,
- IElementCacheConfiguration elementCacheConfiguration) {
+ IElementCacheConfiguration elementCacheConfiguration,
+ ITouchActionsConfiguration touchActionsConfiguration) {
this.timeoutConfiguration = timeoutConfiguration;
this.retryConfiguration = retryConfiguration;
this.applicationProfile = applicationProfile;
this.loggerConfiguration = loggerConfiguration;
this.elementCacheConfiguration = elementCacheConfiguration;
+ this.touchActionsConfiguration = touchActionsConfiguration;
}
@Override
@@ -49,4 +52,9 @@ public ILoggerConfiguration getLoggerConfiguration() {
public IElementCacheConfiguration getElementCacheConfiguration() {
return elementCacheConfiguration;
}
+
+ @Override
+ public ITouchActionsConfiguration getTouchActionsConfiguration() {
+ return touchActionsConfiguration;
+ }
}
\ 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 5e997f1..10369e1 100644
--- a/src/main/java/aquality/appium/mobile/configuration/IConfiguration.java
+++ b/src/main/java/aquality/appium/mobile/configuration/IConfiguration.java
@@ -41,4 +41,11 @@ public interface IConfiguration {
* @return Configuration of element caching.
*/
IElementCacheConfiguration getElementCacheConfiguration();
+
+ /**
+ * Gets configuration of touch actions.
+ *
+ * @return Configuration of touch actions.
+ */
+ ITouchActionsConfiguration getTouchActionsConfiguration();
}
\ No newline at end of file
diff --git a/src/main/java/aquality/appium/mobile/configuration/IConfigurationsModule.java b/src/main/java/aquality/appium/mobile/configuration/IConfigurationsModule.java
index 0cf797b..2b1a6eb 100644
--- a/src/main/java/aquality/appium/mobile/configuration/IConfigurationsModule.java
+++ b/src/main/java/aquality/appium/mobile/configuration/IConfigurationsModule.java
@@ -26,4 +26,10 @@ default Class extends IConfiguration> getConfigurationImplementation() {
return Configuration.class;
}
+ /**
+ * @return class which implements {@link ITouchActionsConfiguration}
+ */
+ default Class extends ITouchActionsConfiguration> getTouchActionsConfigurationImplementation() {
+ return TouchActionsConfiguration.class;
+ }
}
diff --git a/src/main/java/aquality/appium/mobile/configuration/ITouchActionsConfiguration.java b/src/main/java/aquality/appium/mobile/configuration/ITouchActionsConfiguration.java
new file mode 100644
index 0000000..e9c6a66
--- /dev/null
+++ b/src/main/java/aquality/appium/mobile/configuration/ITouchActionsConfiguration.java
@@ -0,0 +1,56 @@
+package aquality.appium.mobile.configuration;
+
+import java.time.Duration;
+
+/**
+ * Describes Touch Actions settings.
+ */
+public interface ITouchActionsConfiguration {
+ /**
+ * Gets number of retries to perform swipe.
+ *
+ * @return arguments map.
+ */
+ int getSwipeRetries();
+
+ /**
+ * Gets the number of seconds required to perform a swipe action.
+ *
+ * @return number of seconds required to perform a swipe action.
+ */
+ Duration getSwipeDuration();
+
+ /**
+ * Gets the offset coefficient to adjust the start/end point for swipe action relatively to the parallel screen edge.
+ * Example for swipe down action:
+ * The offset coefficient is used to calculate start/end point's Y coordinate.
+ * If offset coefficient == 0.2, then the start point's Y coordinate == screen's length * (1 - 0.2).
+ * If offset coefficient == 0.2, then the end point's Y coordinate == screen's length * 0.2.
+ * The vice versa for swipe up action.
+ * Example for swipe left action:
+ * The offset coefficient is used to calculate start/end point's X coordinate.
+ * If offset coefficient == 0.2, then the start point's X coordinate == screen's width * (1 - 0.2).
+ * If offset coefficient == 0.2, then the end point's X coordinate == screen's width * 0.2.
+ * The vice versa for swipe right action.
+ *
+ * @return offset coefficient to adjust the start/end point for swipe action relatively to the parallel screen edge
+ */
+ double getSwipeVerticalOffset();
+
+ /**
+ * Gets the offset coefficient to adjust the start/end point for swipe action relatively to the perpendicular screen edge.
+ * Example for swipe down action:
+ * The offset coefficient is used to calculate start/end point's X coordinate.
+ * If offset coefficient == 0.5, then the start point's X coordinate == screen's width * (1 - 0.5).
+ * If offset coefficient == 0.5, then the end point's X coordinate == screen's width * 0.5.
+ * The vice versa for swipe up action.
+ * Example for swipe left action:
+ * The offset coefficient is used to calculate start/end point's X coordinate.
+ * If offset coefficient == 0.5, then the start point's Y coordinate == screen's length * (1 - 0.5).
+ * If offset coefficient == 0.5, then the end point's Y coordinate == screen's length * 0.5.
+ * The vice versa for swipe right action.
+ *
+ * @return offset coefficient to adjust the start/end point for swipe action relatively to the perpendicular screen edge
+ */
+ double getSwipeHorizontalOffset();
+}
diff --git a/src/main/java/aquality/appium/mobile/configuration/TouchActionsConfiguration.java b/src/main/java/aquality/appium/mobile/configuration/TouchActionsConfiguration.java
new file mode 100644
index 0000000..57827db
--- /dev/null
+++ b/src/main/java/aquality/appium/mobile/configuration/TouchActionsConfiguration.java
@@ -0,0 +1,41 @@
+package aquality.appium.mobile.configuration;
+
+import aquality.selenium.core.utilities.ISettingsFile;
+import com.google.inject.Inject;
+
+import java.time.Duration;
+
+public class TouchActionsConfiguration implements ITouchActionsConfiguration {
+ private final Duration swipeDuration;
+ private final int swipeRetries;
+ private final double swipeVerticalOffset;
+ private final double swipeHorizontalOffset;
+
+ @Inject
+ public TouchActionsConfiguration(ISettingsFile settingsFile) {
+ this.swipeDuration = Duration.ofSeconds(Long.parseLong(settingsFile.getValue("/touchActions/swipe/duration").toString()));
+ this.swipeRetries = (int) settingsFile.getValue("/touchActions/swipe/retries");
+ this.swipeVerticalOffset = (double) settingsFile.getValue("/touchActions/swipe/verticalOffset");
+ this.swipeHorizontalOffset = (double) settingsFile.getValue("/touchActions/swipe/horizontalOffset");
+ }
+
+ @Override
+ public int getSwipeRetries() {
+ return this.swipeRetries;
+ }
+
+ @Override
+ public Duration getSwipeDuration() {
+ return this.swipeDuration;
+ }
+
+ @Override
+ public double getSwipeVerticalOffset() {
+ return this.swipeVerticalOffset;
+ }
+
+ @Override
+ public double getSwipeHorizontalOffset() {
+ return this.swipeHorizontalOffset;
+ }
+}
diff --git a/src/main/java/aquality/appium/mobile/elements/Element.java b/src/main/java/aquality/appium/mobile/elements/Element.java
index d4462fb..96a48a6 100644
--- a/src/main/java/aquality/appium/mobile/elements/Element.java
+++ b/src/main/java/aquality/appium/mobile/elements/Element.java
@@ -2,6 +2,8 @@
import aquality.appium.mobile.application.Application;
import aquality.appium.mobile.application.AqualityServices;
+import aquality.appium.mobile.elements.actions.ElementTouchActions;
+import aquality.appium.mobile.elements.actions.IElementTouchActions;
import aquality.appium.mobile.elements.interfaces.IElement;
import aquality.appium.mobile.elements.interfaces.IElementFactory;
import aquality.selenium.core.configurations.IElementCacheConfiguration;
@@ -86,4 +88,9 @@ public void sendKeys(Keys key) {
logElementAction("loc.text.sending.keys", Keys.class.getSimpleName().concat(".").concat(key.name()));
doWithRetry(() -> getElement().sendKeys(key));
}
+
+ @Override
+ public IElementTouchActions getTouchActions() {
+ return new ElementTouchActions(this);
+ }
}
diff --git a/src/main/java/aquality/appium/mobile/elements/actions/ElementTouchActions.java b/src/main/java/aquality/appium/mobile/elements/actions/ElementTouchActions.java
new file mode 100644
index 0000000..9f9b6fe
--- /dev/null
+++ b/src/main/java/aquality/appium/mobile/elements/actions/ElementTouchActions.java
@@ -0,0 +1,114 @@
+package aquality.appium.mobile.elements.actions;
+
+import aquality.appium.mobile.actions.ITouchActions;
+import aquality.appium.mobile.actions.SwipeDirection;
+import aquality.appium.mobile.application.AqualityServices;
+import aquality.appium.mobile.configuration.ITouchActionsConfiguration;
+import aquality.appium.mobile.elements.interfaces.IElement;
+import org.openqa.selenium.Dimension;
+import org.openqa.selenium.Point;
+
+public class ElementTouchActions implements IElementTouchActions {
+ private IElement element;
+ private Point scrollDownStartPoint;
+ private Point scrollDownEndPoint;
+ private Point swipeLeftStartPoint;
+ private Point swipeLeftEndPoint;
+ private Point scrollUpStartPoint;
+ private Point scrollUpEndPoint;
+ private Point swipeRightStartPoint;
+ private Point swipeRightEndPoint;
+
+ public ElementTouchActions(IElement element) {
+ this.element = element;
+ this.scrollDownStartPoint = recalculatePointCoordinates(
+ getBottomRightCornerPoint(),
+ (1 - getConfiguration().getSwipeHorizontalOffset()),
+ (1 - getConfiguration().getSwipeVerticalOffset()));
+ this.scrollDownEndPoint = recalculatePointCoordinates(
+ getBottomRightCornerPoint(),
+ getConfiguration().getSwipeHorizontalOffset(),
+ getConfiguration().getSwipeVerticalOffset());
+ this.swipeLeftStartPoint = recalculatePointCoordinates(
+ getBottomRightCornerPoint(),
+ (1 - getConfiguration().getSwipeVerticalOffset()),
+ (1 - getConfiguration().getSwipeHorizontalOffset()));
+ this.swipeLeftEndPoint = recalculatePointCoordinates(
+ getBottomRightCornerPoint(),
+ getConfiguration().getSwipeVerticalOffset(),
+ getConfiguration().getSwipeHorizontalOffset());
+ this.scrollUpStartPoint = this.scrollDownEndPoint;
+ this.scrollUpEndPoint = this.scrollDownStartPoint;
+ this.swipeRightStartPoint = this.swipeLeftEndPoint;
+ this.swipeRightEndPoint = this.swipeLeftStartPoint;
+ }
+
+ @Override
+ public void swipe(Point endPoint) {
+ AqualityServices.getTouchActions().swipe(element.getElement().getCenter(), endPoint);
+ }
+
+ @Override
+ public void swipeWithLongPress(Point endPoint) {
+ AqualityServices.getTouchActions().swipeWithLongPress(element.getElement().getCenter(), endPoint);
+ }
+
+ @Override
+ public void scrollToElement(SwipeDirection direction) {
+ int numberOfRetries = AqualityServices.get(ITouchActionsConfiguration.class).getSwipeRetries();
+ ITouchActions touchActions = AqualityServices.getTouchActions();
+ while (numberOfRetries > 0) {
+ if (!element.state().isDisplayed()) {
+ switch (direction) {
+ case DOWN:
+ touchActions.swipe(scrollDownStartPoint, scrollDownEndPoint);
+ break;
+ case UP:
+ touchActions.swipe(scrollUpStartPoint, scrollUpEndPoint);
+ break;
+ case LEFT:
+ touchActions.swipe(swipeLeftStartPoint, swipeLeftEndPoint);
+ break;
+ case RIGHT:
+ touchActions.swipe(swipeRightStartPoint, swipeRightEndPoint);
+ break;
+ default:
+ throw new IllegalArgumentException(
+ String.format("'%s' direction does not exist", direction.toString()));
+ }
+ }
+ numberOfRetries--;
+ }
+ }
+
+ /**
+ * Returns Point in the bottom right corner of the screen.
+ */
+ private Point getBottomRightCornerPoint() {
+ Dimension screenSize = AqualityServices.getApplication().getDriver().manage().window().getSize();
+ return new Point(screenSize.width, screenSize.height);
+ }
+
+ /**
+ * Returns the point with recalculated coordinates.
+ *
+ * @param point point to recalculate coordinates
+ * @param horizontalOffset coefficient to recalculate the point with horizontal offset.
+ * @param verticalOffset coefficient to recalculate the point with vertical offset.
+ * @return point with recalculated coordinates with horizontal and vertical offset.
+ */
+ private Point recalculatePointCoordinates(Point point, double horizontalOffset, double verticalOffset) {
+ return new Point(
+ (int) (point.getX() * horizontalOffset),
+ (int) (point.getY() * verticalOffset));
+ }
+
+ /**
+ * Returns ITouchActionsConfiguration class.
+ *
+ * @return ITouchActionsConfiguration class
+ */
+ private ITouchActionsConfiguration getConfiguration() {
+ return AqualityServices.get(ITouchActionsConfiguration.class);
+ }
+}
diff --git a/src/main/java/aquality/appium/mobile/elements/actions/IElementTouchActions.java b/src/main/java/aquality/appium/mobile/elements/actions/IElementTouchActions.java
new file mode 100644
index 0000000..6727a9a
--- /dev/null
+++ b/src/main/java/aquality/appium/mobile/elements/actions/IElementTouchActions.java
@@ -0,0 +1,31 @@
+package aquality.appium.mobile.elements.actions;
+
+import aquality.appium.mobile.actions.SwipeDirection;
+import org.openqa.selenium.Point;
+
+/**
+ * Describes Touch Actions for elements.
+ */
+public interface IElementTouchActions {
+
+ /**
+ * Swipes from element to end point using TouchAction.
+ *
+ * @param endPoint point on screen to swipe to.
+ */
+ void swipe(final Point endPoint);
+
+ /**
+ * Swipes from element to end point using LongPress.
+ *
+ * @param endPoint point on screen to swipe to.
+ */
+ void swipeWithLongPress(final Point endPoint);
+
+ /**
+ * Scrolls current screen in provided direction until element is displayed.
+ *
+ * @param direction direction to swipe.
+ */
+ void scrollToElement(final SwipeDirection direction);
+}
diff --git a/src/main/java/aquality/appium/mobile/elements/interfaces/IElement.java b/src/main/java/aquality/appium/mobile/elements/interfaces/IElement.java
index 5d7ab6f..7069fa0 100644
--- a/src/main/java/aquality/appium/mobile/elements/interfaces/IElement.java
+++ b/src/main/java/aquality/appium/mobile/elements/interfaces/IElement.java
@@ -2,6 +2,7 @@
import aquality.appium.mobile.elements.Attributes;
import aquality.appium.mobile.elements.ElementType;
+import aquality.appium.mobile.elements.actions.IElementTouchActions;
import aquality.selenium.core.elements.ElementState;
import io.appium.java_client.MobileElement;
import org.openqa.selenium.By;
@@ -99,4 +100,11 @@ default MobileElement getElement() {
default String getAttribute(Attributes attribute) {
return getAttribute(attribute.toString());
}
+
+ /**
+ * Gets the the utility used to perform touch actions for element.
+ *
+ * @return instance of element touch actions.
+ */
+ IElementTouchActions getTouchActions();
}
diff --git a/src/main/resources/localization/be.json b/src/main/resources/localization/be.json
index df07dab..5956638 100644
--- a/src/main/resources/localization/be.json
+++ b/src/main/resources/localization/be.json
@@ -37,5 +37,7 @@
"loc.text.typing" : "Уводзім '%s'",
"loc.text.focusing": "Факусуемся на полі",
"loc.text.unfocusing": "Адводзім фокус з поля",
- "loc.text.masked_value": "********"
+ "loc.text.masked_value": "********",
+ "loc.action.swipe": "Праводзім па экране з каардынатаў (x:%1$s; y:%2$s) у (x:%3$s; y:%4$s)",
+ "loc.action.swipeLongPress": "Праводзім па экране доўгім націскам з каардынатаў (x:%1$s; y:%2$s) у (x:%3$s; y:%4$s)"
}
diff --git a/src/main/resources/localization/en.json b/src/main/resources/localization/en.json
index ccead49..3cbea6d 100644
--- a/src/main/resources/localization/en.json
+++ b/src/main/resources/localization/en.json
@@ -37,5 +37,7 @@
"loc.text.typing": "Typing '%s'",
"loc.text.focusing": "Focusing on field",
"loc.text.unfocusing": "Unfocusing from field",
- "loc.text.masked_value": "********"
+ "loc.text.masked_value": "********",
+ "loc.action.swipe": "Swiping from coordinates (x:%1$s; y:%2$s) to (x:%3$s; y:%4$s)",
+ "loc.action.swipeLongPress": "Swiping using long press from coordinates (x:%1$s; y:%2$s) to (x:%3$s; y:%4$s)"
}
diff --git a/src/main/resources/localization/ru.json b/src/main/resources/localization/ru.json
index 4686ab9..6ce8c03 100644
--- a/src/main/resources/localization/ru.json
+++ b/src/main/resources/localization/ru.json
@@ -37,5 +37,7 @@
"loc.text.typing": "Ввод текста '%s'",
"loc.text.focusing": "Наведение курсора на поле",
"loc.text.unfocusing": "Сдвиг курсора с поля",
- "loc.text.masked_value": "********"
+ "loc.text.masked_value": "********",
+ "loc.action.swipe": "Проводим по экрану из координат (x:%1$s; y:%2$s) в (x:%3$s; y:%4$s)",
+ "loc.action.swipeLongPress": "Проводим по экрану долгим нажатием из координат (x:%1$s; y:%2$s) в (x:%3$s; y:%4$s)"
}
diff --git a/src/main/resources/settings.json b/src/main/resources/settings.json
index bae900f..f427ceb 100644
--- a/src/main/resources/settings.json
+++ b/src/main/resources/settings.json
@@ -1,9 +1,8 @@
{
- "platformName" : "android",
+ "platformName": "android",
"isRemote": false,
"remoteConnectionUrl": "http://127.0.0.1:4723/wd/hub",
"screensLocation": "",
-
"driverSettings": {
"android": {
"deviceKey": "",
@@ -44,5 +43,13 @@
},
"elementCache": {
"isEnabled": true
+ },
+ "touchActions": {
+ "swipe": {
+ "duration": 1,
+ "retries": 5,
+ "verticalOffset": 0.2,
+ "horizontalOffset": 0.5
+ }
}
}
\ 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 c9c9de5..2fcf8dd 100644
--- a/src/test/java/samples/android/nativeapp/AndroidBasicInteractionsTest.java
+++ b/src/test/java/samples/android/nativeapp/AndroidBasicInteractionsTest.java
@@ -12,10 +12,7 @@
import samples.android.ITestCheckBox;
import samples.android.ITestRadioButton;
import samples.android.nativeapp.apidemos.ApplicationActivity;
-import samples.android.nativeapp.apidemos.screens.AlertsMenuScreen;
-import samples.android.nativeapp.apidemos.screens.InvokeSearchScreen;
-import samples.android.nativeapp.apidemos.screens.TwoButtonsAlert;
-import samples.android.nativeapp.apidemos.screens.ViewControlsScreen;
+import samples.android.nativeapp.apidemos.screens.*;
import testreport.ScreenshotListener;
@Listeners(ScreenshotListener.class)
@@ -88,6 +85,38 @@ public void testOpensAlert() {
alertDialog.close();
}
+ @Test
+ public void testVerticalSwipeToElement() {
+ ViewControlsScreen viewControlsScreen = new ViewControlsScreen();
+ openRadioButtonsScreen();
+ viewControlsScreen.scrollToAllInsideScrollViewLabel();
+ Assert.assertEquals(
+ viewControlsScreen.getAllInsideScrollViewLabelText(),
+ "(And all inside of a ScrollView!)",
+ "Label text does not match expected");
+ viewControlsScreen.scrollToDisabledButton();
+ Assert.assertFalse(viewControlsScreen.isDisabledButtonClickable());
+ }
+
+ @Test
+ public void testHorizontalSwipeToElement() {
+ ViewTabsScrollableScreen viewTabsScrollableScreen = ApplicationActivity.VIEW_TABS_SCROLLABLE.open();
+ Assert.assertTrue(viewTabsScrollableScreen.state().isDisplayed(),
+ String.format("%s screen should be opened", viewTabsScrollableScreen.getName()));
+ viewTabsScrollableScreen.swipeTab(4, 1);
+ viewTabsScrollableScreen.selectTab(7);
+ Assert.assertEquals(
+ viewTabsScrollableScreen.getTabContentText(7),
+ "Content for tab with tag Tab 7",
+ "Label text does not match expected");
+ viewTabsScrollableScreen.swipeTab(5, 7);
+ viewTabsScrollableScreen.selectTab(4);
+ Assert.assertEquals(
+ viewTabsScrollableScreen.getTabContentText(4),
+ "Content for tab with tag Tab 4",
+ "Label text does not match expected");
+ }
+
private void logStep(String step) {
AqualityServices.getLogger().info(step);
}
diff --git a/src/test/java/samples/android/nativeapp/apidemos/ApplicationActivity.java b/src/test/java/samples/android/nativeapp/apidemos/ApplicationActivity.java
index 6f0dd96..9b2f289 100644
--- a/src/test/java/samples/android/nativeapp/apidemos/ApplicationActivity.java
+++ b/src/test/java/samples/android/nativeapp/apidemos/ApplicationActivity.java
@@ -8,6 +8,7 @@
import samples.android.nativeapp.apidemos.screens.AndroidScreen;
import samples.android.nativeapp.apidemos.screens.InvokeSearchScreen;
import samples.android.nativeapp.apidemos.screens.ViewControlsScreen;
+import samples.android.nativeapp.apidemos.screens.ViewTabsScrollableScreen;
import java.lang.reflect.InvocationTargetException;
@@ -15,7 +16,8 @@ public enum ApplicationActivity {
SEARCH(".app.SearchInvoke", InvokeSearchScreen.class),
ALERT_DIALOGS(".app.AlertDialogSamples", AlertsMenuScreen.class),
- VIEW_CONTROLS(".view.Controls1", ViewControlsScreen.class);
+ VIEW_CONTROLS(".view.Controls1", ViewControlsScreen.class),
+ VIEW_TABS_SCROLLABLE(".view.Tabs5", ViewTabsScrollableScreen.class);
private static final String PACKAGE = "io.appium.android.apis";
diff --git a/src/test/java/samples/android/nativeapp/apidemos/screens/ViewControlsScreen.java b/src/test/java/samples/android/nativeapp/apidemos/screens/ViewControlsScreen.java
index de41f45..590c55d 100644
--- a/src/test/java/samples/android/nativeapp/apidemos/screens/ViewControlsScreen.java
+++ b/src/test/java/samples/android/nativeapp/apidemos/screens/ViewControlsScreen.java
@@ -1,24 +1,50 @@
package samples.android.nativeapp.apidemos.screens;
+import aquality.appium.mobile.actions.SwipeDirection;
+import aquality.appium.mobile.elements.interfaces.IButton;
import aquality.appium.mobile.elements.interfaces.ICheckBox;
+import aquality.appium.mobile.elements.interfaces.ILabel;
import aquality.appium.mobile.elements.interfaces.IRadioButton;
import io.appium.java_client.MobileBy;
import org.openqa.selenium.By;
public class ViewControlsScreen extends AndroidScreen {
- public ViewControlsScreen() {
- super(By.id("android:id/content"), "View/Controls");
- }
- public IRadioButton getRadioButton(int number){
+ public IRadioButton getRadioButton(int number) {
return getElementFactory().getRadioButton(
MobileBy.AccessibilityId(String.format("RadioButton %d", number)),
String.valueOf(number));
}
- public ICheckBox getCheckBox(int number){
+ public ICheckBox getCheckBox(int number) {
return getElementFactory().getCheckBox(
MobileBy.AccessibilityId(String.format("Checkbox %d", number)),
String.valueOf(number));
}
+
+ private final IButton btnDisabled = getElementFactory().getButton(MobileBy.id("button_disabled"), "Disabled");
+
+ public ViewControlsScreen() {
+ super(By.id("android:id/content"), "View/Controls");
+ }
+
+ public void scrollToAllInsideScrollViewLabel() {
+ lblAllInsideScrollView.getTouchActions().scrollToElement(SwipeDirection.DOWN);
+ }
+
+ public String getAllInsideScrollViewLabelText() {
+ return lblAllInsideScrollView.getText();
+ }
+
+ public void scrollToDisabledButton() {
+ btnDisabled.getTouchActions().scrollToElement(SwipeDirection.UP);
+ }
+
+ public boolean isDisabledButtonClickable() {
+ return btnDisabled.state().isClickable();
+ }
+
+ private final ILabel lblAllInsideScrollView = getElementFactory().getLabel(
+ MobileBy.AccessibilityId("(And all inside of a ScrollView!)"),
+ "All inside of Scroll View");
}
diff --git a/src/test/java/samples/android/nativeapp/apidemos/screens/ViewTabsScrollableScreen.java b/src/test/java/samples/android/nativeapp/apidemos/screens/ViewTabsScrollableScreen.java
new file mode 100644
index 0000000..9b24b76
--- /dev/null
+++ b/src/test/java/samples/android/nativeapp/apidemos/screens/ViewTabsScrollableScreen.java
@@ -0,0 +1,45 @@
+package samples.android.nativeapp.apidemos.screens;
+
+import aquality.appium.mobile.elements.interfaces.IButton;
+import aquality.appium.mobile.elements.interfaces.ILabel;
+import io.appium.java_client.MobileBy;
+import org.openqa.selenium.By;
+import org.openqa.selenium.Point;
+
+public class ViewTabsScrollableScreen extends AndroidScreen {
+
+ private static final String TAB_TEXT = "Content for tab with tag Tab %s";
+
+ public IButton getTab(int tabNumber) {
+ return getElementFactory().getButton(
+ MobileBy.xpath(String.format("//*[@text='TAB %s' and @resource-id = 'android:id/title']", tabNumber)),
+ String.valueOf(tabNumber));
+ }
+
+ public ILabel getTabContent(int tabNumber) {
+ return getElementFactory().getLabel(
+ MobileBy.xpath(String.format("//*[@text='%s']", generateTabText(tabNumber))),
+ String.valueOf(tabNumber));
+ }
+
+ public ViewTabsScrollableScreen() {
+ super(By.id("android:id/content"), "View/Tabs/Scrollable");
+ }
+
+ public void swipeTab(int startTabNumber, int endTabNumber) {
+ Point endTabPoint = getTab(endTabNumber).getElement().getCenter();
+ getTab(startTabNumber).getTouchActions().swipe(endTabPoint);
+ }
+
+ public String getTabContentText(int tabNumber) {
+ return getTabContent(tabNumber).getText();
+ }
+
+ public void selectTab(int tabNumber) {
+ getTab(tabNumber).click();
+ }
+
+ private String generateTabText(int tabNumber) {
+ return String.format(TAB_TEXT, tabNumber);
+ }
+}
diff --git a/src/test/resources/settings.androidwebsession.json b/src/test/resources/settings.androidwebsession.json
index af2dc16..1c9af04 100644
--- a/src/test/resources/settings.androidwebsession.json
+++ b/src/test/resources/settings.androidwebsession.json
@@ -1,9 +1,8 @@
{
- "platformName" : "android",
+ "platformName": "android",
"isRemote": true,
"remoteConnectionUrl": "http://127.0.0.1:4723/wd/hub",
"screensLocation": "integration",
-
"driverSettings": {
"android": {
"capabilities": {
@@ -22,10 +21,10 @@
}
},
"timeouts": {
- "timeoutImplicit" : 0,
- "timeoutCondition" : 15,
+ "timeoutImplicit": 0,
+ "timeoutCondition": 15,
"timeoutPollingInterval": 300,
- "timeoutCommand":120
+ "timeoutCommand": 120
},
"retry": {
"number": 2,
@@ -36,5 +35,13 @@
},
"elementCache": {
"isEnabled": true
+ },
+ "touchActions": {
+ "swipe": {
+ "duration": 1,
+ "retries": 5,
+ "verticalOffset": 0.2,
+ "horizontalOffset": 0.5
+ }
}
}
\ No newline at end of file
diff --git a/src/test/resources/settings.json b/src/test/resources/settings.json
index bd61397..f04bb75 100644
--- a/src/test/resources/settings.json
+++ b/src/test/resources/settings.json
@@ -1,9 +1,8 @@
{
- "platformName" : "android",
+ "platformName": "android",
"isRemote": true,
"remoteConnectionUrl": "http://127.0.0.1:4723/wd/hub",
"screensLocation": "integration",
-
"driverSettings": {
"android": {
"deviceKey": "Android_Emulator",
@@ -32,10 +31,10 @@
}
},
"timeouts": {
- "timeoutImplicit" : 0,
- "timeoutCondition" : 15,
+ "timeoutImplicit": 0,
+ "timeoutCondition": 15,
"timeoutPollingInterval": 300,
- "timeoutCommand":120
+ "timeoutCommand": 120
},
"retry": {
"number": 2,
@@ -46,5 +45,13 @@
},
"elementCache": {
"isEnabled": true
+ },
+ "touchActions": {
+ "swipe": {
+ "duration": 1,
+ "retries": 5,
+ "verticalOffset": 0.2,
+ "horizontalOffset": 0.5
+ }
}
}
\ No newline at end of file