diff --git a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/Clear.java b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/Clear.java index 206769c9b..1d6fb8c0e 100644 --- a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/Clear.java +++ b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/Clear.java @@ -16,11 +16,10 @@ package io.appium.espressoserver.lib.handlers; -import androidx.test.espresso.PerformException; -import androidx.test.espresso.ViewInteraction; - import javax.annotation.Nullable; +import androidx.test.espresso.PerformException; +import androidx.test.espresso.ViewInteraction; import io.appium.espressoserver.lib.handlers.exceptions.AppiumException; import io.appium.espressoserver.lib.handlers.exceptions.InvalidElementStateException; import io.appium.espressoserver.lib.model.AppiumParams; diff --git a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/Click.java b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/Click.java index 3b2fa3b60..b6681cfbd 100644 --- a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/Click.java +++ b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/Click.java @@ -16,11 +16,10 @@ package io.appium.espressoserver.lib.handlers; -import androidx.test.espresso.PerformException; -import androidx.test.espresso.ViewInteraction; - import javax.annotation.Nullable; +import androidx.test.espresso.PerformException; +import androidx.test.espresso.ViewInteraction; import io.appium.espressoserver.lib.handlers.exceptions.AppiumException; import io.appium.espressoserver.lib.handlers.exceptions.InvalidElementStateException; import io.appium.espressoserver.lib.model.AppiumParams; diff --git a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/DrawerActionHandler.java b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/DrawerActionHandler.java index 5dc29b760..2b55f663c 100644 --- a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/DrawerActionHandler.java +++ b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/DrawerActionHandler.java @@ -16,22 +16,12 @@ package io.appium.espressoserver.lib.handlers; -import java.util.regex.Pattern; - import androidx.test.espresso.EspressoException; import androidx.test.espresso.ViewInteraction; import androidx.test.espresso.contrib.DrawerActions; import io.appium.espressoserver.lib.handlers.exceptions.AppiumException; import io.appium.espressoserver.lib.model.DrawerActionParams; import io.appium.espressoserver.lib.model.Element; -import io.appium.espressoserver.lib.model.ToastLookupParams; -import io.appium.espressoserver.lib.viewmatcher.ToastMatcher; - -import static androidx.test.espresso.Espresso.onView; -import static androidx.test.espresso.assertion.ViewAssertions.matches; -import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; -import static androidx.test.espresso.matcher.ViewMatchers.withText; -import static io.appium.espressoserver.lib.viewmatcher.RegexpTextMatcher.withRegexp; public class DrawerActionHandler implements RequestHandler { private final boolean isOpenAction; diff --git a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/ElementValue.java b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/ElementValue.java index 24aed518c..7ddeb6084 100644 --- a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/ElementValue.java +++ b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/ElementValue.java @@ -1,10 +1,10 @@ package io.appium.espressoserver.lib.handlers; -import androidx.test.espresso.ViewInteraction; import android.view.View; import android.widget.NumberPicker; import android.widget.ProgressBar; +import androidx.test.espresso.ViewInteraction; import io.appium.espressoserver.lib.handlers.exceptions.AppiumException; import io.appium.espressoserver.lib.handlers.exceptions.InvalidArgumentException; import io.appium.espressoserver.lib.model.Element; diff --git a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/GetAttribute.java b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/GetAttribute.java index 865e12547..48672e576 100644 --- a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/GetAttribute.java +++ b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/GetAttribute.java @@ -1,6 +1,5 @@ package io.appium.espressoserver.lib.handlers; -import androidx.test.espresso.ViewInteraction; import android.view.View; import java.util.ArrayList; @@ -8,6 +7,7 @@ import javax.annotation.Nullable; +import androidx.test.espresso.ViewInteraction; import io.appium.espressoserver.lib.handlers.exceptions.AppiumException; import io.appium.espressoserver.lib.handlers.exceptions.NotYetImplementedException; import io.appium.espressoserver.lib.model.AppiumParams; diff --git a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/GetEnabled.java b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/GetEnabled.java index ff38fc1fc..5f40c994e 100644 --- a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/GetEnabled.java +++ b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/GetEnabled.java @@ -20,7 +20,6 @@ import androidx.test.espresso.NoMatchingViewException; import androidx.test.espresso.ViewInteraction; - import io.appium.espressoserver.lib.handlers.exceptions.AppiumException; import io.appium.espressoserver.lib.model.AppiumParams; import io.appium.espressoserver.lib.model.Element; diff --git a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/GetSelected.java b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/GetSelected.java index f5f0fe3b6..698918640 100644 --- a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/GetSelected.java +++ b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/GetSelected.java @@ -20,7 +20,6 @@ import androidx.test.espresso.NoMatchingViewException; import androidx.test.espresso.ViewInteraction; - import io.appium.espressoserver.lib.handlers.exceptions.AppiumException; import io.appium.espressoserver.lib.model.AppiumParams; import io.appium.espressoserver.lib.model.Element; diff --git a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/HideKeyboard.java b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/HideKeyboard.java index 8e5817344..2b105987b 100644 --- a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/HideKeyboard.java +++ b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/HideKeyboard.java @@ -17,7 +17,6 @@ package io.appium.espressoserver.lib.handlers; import androidx.test.espresso.Espresso; - import io.appium.espressoserver.lib.handlers.exceptions.AppiumException; import io.appium.espressoserver.lib.model.AppiumParams; diff --git a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/Keys.java b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/Keys.java index 15e5530ac..56c045f94 100644 --- a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/Keys.java +++ b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/Keys.java @@ -16,12 +16,11 @@ package io.appium.espressoserver.lib.handlers; -import androidx.test.espresso.UiController; - import java.util.ArrayList; import java.util.Collections; import java.util.List; +import androidx.test.espresso.UiController; import io.appium.espressoserver.lib.handlers.exceptions.AppiumException; import io.appium.espressoserver.lib.helpers.w3c.adapter.espresso.EspressoW3CActionAdapter; import io.appium.espressoserver.lib.helpers.w3c.models.Actions; diff --git a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/MobileClickAction.kt b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/MobileClickAction.kt index cc63bd36f..20fb6e5e2 100644 --- a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/MobileClickAction.kt +++ b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/MobileClickAction.kt @@ -18,8 +18,8 @@ package io.appium.espressoserver.lib.handlers import androidx.test.espresso.action.GeneralClickAction import io.appium.espressoserver.lib.handlers.exceptions.AppiumException -import io.appium.espressoserver.lib.model.MobileClickActionParams import io.appium.espressoserver.lib.model.Element +import io.appium.espressoserver.lib.model.MobileClickActionParams import io.appium.espressoserver.lib.viewaction.UiControllerPerformer import io.appium.espressoserver.lib.viewaction.UiControllerRunnable diff --git a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/MobileSwipe.kt b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/MobileSwipe.kt index cea20ab34..0275eed63 100644 --- a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/MobileSwipe.kt +++ b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/MobileSwipe.kt @@ -17,17 +17,12 @@ package io.appium.espressoserver.lib.handlers import androidx.test.espresso.action.GeneralSwipeAction - +import androidx.test.espresso.action.ViewActions.* import io.appium.espressoserver.lib.handlers.exceptions.AppiumException import io.appium.espressoserver.lib.handlers.exceptions.InvalidArgumentException +import io.appium.espressoserver.lib.helpers.AndroidLogger.logger import io.appium.espressoserver.lib.model.Element import io.appium.espressoserver.lib.model.MobileSwipeParams - -import androidx.test.espresso.action.ViewActions.swipeDown -import androidx.test.espresso.action.ViewActions.swipeLeft -import androidx.test.espresso.action.ViewActions.swipeRight -import androidx.test.espresso.action.ViewActions.swipeUp -import io.appium.espressoserver.lib.helpers.AndroidLogger.logger import io.appium.espressoserver.lib.model.MobileSwipeParams.Direction.* import io.appium.espressoserver.lib.viewaction.UiControllerPerformer import io.appium.espressoserver.lib.viewaction.UiControllerRunnable diff --git a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/MoveTo.java b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/MoveTo.java index d100b0574..8b09d1f28 100644 --- a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/MoveTo.java +++ b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/MoveTo.java @@ -18,7 +18,6 @@ import androidx.test.espresso.PerformException; import androidx.test.espresso.ViewInteraction; - import io.appium.espressoserver.lib.handlers.exceptions.AppiumException; import io.appium.espressoserver.lib.model.Element; import io.appium.espressoserver.lib.model.MoveToParams; diff --git a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/MultiTouchAction.java b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/MultiTouchAction.java index 8b65cdba4..ac73c6d83 100644 --- a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/MultiTouchAction.java +++ b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/MultiTouchAction.java @@ -1,9 +1,8 @@ package io.appium.espressoserver.lib.handlers; -import androidx.test.espresso.UiController; - import java.util.List; +import androidx.test.espresso.UiController; import io.appium.espressoserver.lib.handlers.exceptions.AppiumException; import io.appium.espressoserver.lib.helpers.w3c.adapter.espresso.EspressoW3CActionAdapter; import io.appium.espressoserver.lib.helpers.w3c.models.Actions; diff --git a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/NavigateTo.java b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/NavigateTo.java index 75ab605f9..59868c806 100644 --- a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/NavigateTo.java +++ b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/NavigateTo.java @@ -19,13 +19,9 @@ import androidx.test.espresso.EspressoException; import androidx.test.espresso.ViewInteraction; import androidx.test.espresso.contrib.NavigationViewActions; -import androidx.test.espresso.contrib.PickerActions; import io.appium.espressoserver.lib.handlers.exceptions.AppiumException; -import io.appium.espressoserver.lib.helpers.AndroidLogger; import io.appium.espressoserver.lib.model.Element; import io.appium.espressoserver.lib.model.NavigateToParams; -import io.appium.espressoserver.lib.model.ScrollToPageParams; -import io.appium.espressoserver.lib.model.SetTimeParams; public class NavigateTo implements RequestHandler { diff --git a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/PerformAction.java b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/PerformAction.java index 827d9ea95..f104ca23b 100644 --- a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/PerformAction.java +++ b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/PerformAction.java @@ -1,7 +1,6 @@ package io.appium.espressoserver.lib.handlers; import androidx.test.espresso.UiController; - import io.appium.espressoserver.lib.handlers.exceptions.AppiumException; import io.appium.espressoserver.lib.helpers.w3c.adapter.espresso.EspressoW3CActionAdapter; import io.appium.espressoserver.lib.helpers.w3c.models.Actions; diff --git a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/PressKeyCode.java b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/PressKeyCode.java index 82c4dd58c..301310d41 100644 --- a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/PressKeyCode.java +++ b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/PressKeyCode.java @@ -17,12 +17,12 @@ package io.appium.espressoserver.lib.handlers; import android.os.SystemClock; -import androidx.test.espresso.InjectEventSecurityException; -import androidx.test.espresso.UiController; import android.view.KeyCharacterMap; import android.view.KeyEvent; import android.view.ViewConfiguration; +import androidx.test.espresso.InjectEventSecurityException; +import androidx.test.espresso.UiController; import io.appium.espressoserver.lib.handlers.exceptions.AppiumException; import io.appium.espressoserver.lib.handlers.exceptions.InvalidArgumentException; import io.appium.espressoserver.lib.model.KeyEventParams; diff --git a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/ReleaseActions.java b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/ReleaseActions.java index cfd56b813..b30be4ed7 100644 --- a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/ReleaseActions.java +++ b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/ReleaseActions.java @@ -1,7 +1,6 @@ package io.appium.espressoserver.lib.handlers; import androidx.test.espresso.UiController; - import io.appium.espressoserver.lib.handlers.exceptions.AppiumException; import io.appium.espressoserver.lib.helpers.w3c.models.Actions; import io.appium.espressoserver.lib.model.AppiumParams; diff --git a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/ScreenshotHandler.java b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/ScreenshotHandler.java index d12d78ea6..2f2d0bc4c 100644 --- a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/ScreenshotHandler.java +++ b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/ScreenshotHandler.java @@ -16,13 +16,6 @@ package io.appium.espressoserver.lib.handlers; -import android.graphics.Bitmap; -import android.util.Base64; - -import java.io.ByteArrayOutputStream; - -import androidx.test.runner.screenshot.ScreenCapture; -import androidx.test.runner.screenshot.Screenshot; import io.appium.espressoserver.lib.handlers.exceptions.AppiumException; import io.appium.espressoserver.lib.helpers.ScreenshotsHelper; import io.appium.espressoserver.lib.model.AppiumParams; diff --git a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/SendKeys.java b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/SendKeys.java index 2e881c8dc..6fe44135c 100644 --- a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/SendKeys.java +++ b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/SendKeys.java @@ -16,12 +16,12 @@ package io.appium.espressoserver.lib.handlers; -import androidx.test.espresso.PerformException; -import androidx.test.espresso.ViewInteraction; import android.view.View; import android.widget.NumberPicker; import android.widget.ProgressBar; +import androidx.test.espresso.PerformException; +import androidx.test.espresso.ViewInteraction; import io.appium.espressoserver.lib.handlers.exceptions.AppiumException; import io.appium.espressoserver.lib.handlers.exceptions.InvalidArgumentException; import io.appium.espressoserver.lib.handlers.exceptions.InvalidElementStateException; diff --git a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/SetOrientation.java b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/SetOrientation.java index 85772bfa7..6d922219e 100644 --- a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/SetOrientation.java +++ b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/SetOrientation.java @@ -16,19 +16,19 @@ package io.appium.espressoserver.lib.handlers; -import androidx.test.espresso.ViewInteraction; -import static androidx.test.espresso.matcher.ViewMatchers.isRoot; -import static androidx.test.espresso.Espresso.onView; - import java.util.Arrays; import javax.annotation.Nullable; +import androidx.test.espresso.ViewInteraction; import io.appium.espressoserver.lib.handlers.exceptions.AppiumException; import io.appium.espressoserver.lib.model.Element; import io.appium.espressoserver.lib.model.OrientationParams; import io.appium.espressoserver.lib.viewaction.OrientationChange; +import static androidx.test.espresso.Espresso.onView; +import static androidx.test.espresso.matcher.ViewMatchers.isRoot; + public class SetOrientation implements RequestHandler { @Override diff --git a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/Text.java b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/Text.java index c2682d339..8bed67044 100644 --- a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/Text.java +++ b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/Text.java @@ -16,10 +16,9 @@ package io.appium.espressoserver.lib.handlers; -import androidx.test.espresso.ViewInteraction; - import javax.annotation.Nullable; +import androidx.test.espresso.ViewInteraction; import io.appium.espressoserver.lib.handlers.exceptions.AppiumException; import io.appium.espressoserver.lib.model.AppiumParams; import io.appium.espressoserver.lib.model.Element; diff --git a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/TouchAction.java b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/TouchAction.java index 949a1b93c..f6def965e 100644 --- a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/TouchAction.java +++ b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/TouchAction.java @@ -1,10 +1,9 @@ package io.appium.espressoserver.lib.handlers; -import androidx.test.espresso.UiController; - import java.util.Collections; import java.util.List; +import androidx.test.espresso.UiController; import io.appium.espressoserver.lib.handlers.exceptions.AppiumException; import io.appium.espressoserver.lib.helpers.w3c.adapter.espresso.EspressoW3CActionAdapter; import io.appium.espressoserver.lib.helpers.w3c.models.Actions; diff --git a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/WebAtoms.kt b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/WebAtoms.kt index 5ffdf39c8..704bb6f9b 100644 --- a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/WebAtoms.kt +++ b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/handlers/WebAtoms.kt @@ -17,15 +17,15 @@ package io.appium.espressoserver.lib.handlers import androidx.test.espresso.web.sugar.Web.WebInteraction -import io.appium.espressoserver.lib.handlers.exceptions.AppiumException -import io.appium.espressoserver.lib.model.web.WebAtomsParams import androidx.test.espresso.web.sugar.Web.onWebView import androidx.test.espresso.web.webdriver.DriverAtoms +import io.appium.espressoserver.lib.handlers.exceptions.AppiumException import io.appium.espressoserver.lib.handlers.exceptions.InvalidArgumentException import io.appium.espressoserver.lib.helpers.AndroidLogger.logger import io.appium.espressoserver.lib.helpers.KReflectionUtils.invokeInstanceMethod import io.appium.espressoserver.lib.helpers.KReflectionUtils.invokeMethod import io.appium.espressoserver.lib.model.Element +import io.appium.espressoserver.lib.model.web.WebAtomsParams import io.appium.espressoserver.lib.viewmatcher.WithView.withView class WebAtoms : RequestHandler { @@ -38,7 +38,7 @@ class WebAtoms : RequestHandler { // Initialize onWebView with web view matcher (if webviewEl provided) webAtomsParams.webviewElement.let{ - logger.info("Initializing webView interaction on webview with el: '${it}") + logger.info("Initializing webView interaction on webview with el: '${it}'") val matcher = withView(Element.getViewById(it)) webViewInteraction = onWebView(matcher) } @@ -50,11 +50,11 @@ class WebAtoms : RequestHandler { // Iterate through methodsChain and call the atoms for (method in webAtomsParams.methodChain) { - val atom = invokeMethod(DriverAtoms::class, method.atom.name, *method.atom.args.toTypedArray()); + val atom = invokeMethod(DriverAtoms::class, method.atom.name, *method.atom.args); logger.info("Calling interaction '${method.name}' with the atom '${method.atom}'") - val args = if (atom == null) emptyList() else atom; - val res = invokeInstanceMethod(webViewInteraction, method.name, args); + val args: Array = if (atom == null) emptyArray() else arrayOf(atom) + val res = invokeInstanceMethod(webViewInteraction, method.name, *args) if (!(res is WebInteraction<*>)) { throw InvalidArgumentException("'${method.name}' does not return a 'WebViewInteraction' object"); diff --git a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/helpers/AlertHelpers.java b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/helpers/AlertHelpers.java index 4eb9aa3d4..80d884f4a 100644 --- a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/helpers/AlertHelpers.java +++ b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/helpers/AlertHelpers.java @@ -16,7 +16,6 @@ package io.appium.espressoserver.lib.helpers; -import androidx.annotation.Nullable; import android.util.Log; import java.util.ArrayList; @@ -28,6 +27,7 @@ import java.util.Objects; import java.util.regex.Pattern; +import androidx.annotation.Nullable; import androidx.test.uiautomator.By; import androidx.test.uiautomator.UiObject2; import io.appium.espressoserver.lib.handlers.exceptions.InvalidElementStateException; diff --git a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/helpers/DeviceInfoHelper.java b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/helpers/DeviceInfoHelper.java index f8988bc2e..03e1b835d 100644 --- a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/helpers/DeviceInfoHelper.java +++ b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/helpers/DeviceInfoHelper.java @@ -20,12 +20,13 @@ import android.content.Context; import android.os.Build; import android.provider.Settings.Secure; -import androidx.annotation.Nullable; import android.telephony.TelephonyManager; import android.util.DisplayMetrics; import android.view.Display; import android.view.WindowManager; +import androidx.annotation.Nullable; + public class DeviceInfoHelper { private final Context context; diff --git a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/helpers/GsonParserHelpers.kt b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/helpers/GsonParserHelpers.kt index 2e8999b0a..302decbaf 100644 --- a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/helpers/GsonParserHelpers.kt +++ b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/helpers/GsonParserHelpers.kt @@ -16,11 +16,12 @@ package io.appium.espressoserver.lib.helpers +import com.google.gson.JsonArray import com.google.gson.JsonObject import com.google.gson.JsonParseException -import java.lang.IllegalArgumentException +import com.google.gson.JsonPrimitive -class GsonParserHelpers { +object GsonParserHelpers { inline fun > parseEnum(jsonObj: JsonObject, propName: String, helperMessage: String = "", defaultValue: T? = null): T? { @@ -37,4 +38,26 @@ class GsonParserHelpers { } return defaultValue } + + fun parsePrimitive(jsonPrimitive: JsonPrimitive): Any = when { + jsonPrimitive.isNumber -> { + val hasDecimal = jsonPrimitive.asString.contains(".") // this returns true or false + if (hasDecimal) jsonPrimitive.asDouble else jsonPrimitive.asLong + } + jsonPrimitive.isBoolean -> jsonPrimitive.asBoolean + jsonPrimitive.isString -> jsonPrimitive.asString + else -> throw JsonParseException("Could not parse primitive '${jsonPrimitive}'"); + } + + fun asArray (jsonObj: JsonObject, key: String): JsonArray { + jsonObj.get(key)?.let { + if (it.isJsonArray) { + return it.asJsonArray + } + val jsonArr = JsonArray() + jsonArr.add(it) + return jsonArr + } + return JsonArray(); + } } diff --git a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/helpers/KReflectionUtils.kt b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/helpers/KReflectionUtils.kt index b0ee009cb..df3e8e83f 100644 --- a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/helpers/KReflectionUtils.kt +++ b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/helpers/KReflectionUtils.kt @@ -1,19 +1,17 @@ package io.appium.espressoserver.lib.helpers +import com.google.gson.internal.LazilyParsedNumber import io.appium.espressoserver.lib.handlers.exceptions.AppiumException -import java.lang.ClassCastException -import java.lang.IllegalArgumentException -import java.lang.reflect.InvocationTargetException import kotlin.reflect.KClass import kotlin.reflect.KFunction -import kotlin.reflect.full.createType import kotlin.reflect.full.functions +import kotlin.reflect.full.isSubclassOf import kotlin.reflect.full.memberFunctions import kotlin.reflect.jvm.javaType object KReflectionUtils { - fun invokeMethod(functions: Collection>, methodName: String, vararg providedParams: Any): Any? { + fun invokeMethod(functions: Collection>, methodName: String, vararg providedParams: Any?): Any? { val treatedParams = providedParams.clone().toMutableList() for (func in functions) { // Look for function names that match provided methodName @@ -29,10 +27,11 @@ object KReflectionUtils { funcParams.forEachIndexed { index, funcParam -> val providedParam = providedParams.get(index) - // Hack Enum Case + // Handle the Enum Case // If function param is Enum and provided param is String, try `enumValueOf` on that String value + val type = funcParam.type; try { - val jFuncType = funcParam.type.javaType as Class<*> + val jFuncType = type.javaType as Class<*> if (jFuncType.isEnum && providedParam is String) { val enumValueOf = jFuncType.getDeclaredMethod("valueOf", String::class.java) treatedParams.set(index, enumValueOf(null, providedParam.toUpperCase())) @@ -42,6 +41,30 @@ object KReflectionUtils { } catch (e:ClassCastException) { // Ignore class cast exceptions and don't try matching String to Enum } + + // Handle the Class case + val classifier = type.classifier; + if (classifier is KClass<*> && classifier.isSubclassOf(Class::class)) { + var className: String = providedParam.toString() + val classExtension = ".class"; + if (className.endsWith(classExtension)) { + className = className.take(className.length - classExtension.length) + } + + try { + val clazz = Class.forName(className) + treatedParams.set(index, clazz) + } catch (e: ClassNotFoundException) { } + + try { + val clazz = Class.forName("java.lang.${className}") + treatedParams.set(index, clazz) + } catch (e: ClassNotFoundException) { } + } + + if (providedParam is LazilyParsedNumber) { + treatedParams.set(index, providedParam.toDouble()) + } } // Attempt to call this function. If it fails, try the next function definition. @@ -53,15 +76,24 @@ object KReflectionUtils { } } - throw AppiumException("Could not invoke method: " + + throw AppiumException("Could not find method that matches " + "methodName=[${methodName}] args=[${providedParams.joinToString(", ")}]") } - fun invokeMethod(kclass: KClass<*>, methodName: String, vararg providedParams: Any): Any? { - return invokeMethod(kclass.functions, methodName, *providedParams) + fun invokeMethod(kclass: KClass<*>, methodName: String, vararg providedParams: Any?): Any? { + try { + return invokeMethod(kclass.functions, methodName, *providedParams) + } catch (e:AppiumException) { + throw AppiumException("Cannot execute method on '${kclass.qualifiedName}'. Reason: ${e.message}'"); + } } - fun invokeInstanceMethod (instance: Any, methodName: String, vararg providedParams: Any): Any? { - return invokeMethod(instance::class.memberFunctions, methodName, instance, *providedParams) + fun invokeInstanceMethod (instance: Any, methodName: String, vararg providedParams: Any?): Any? { + try { + return invokeMethod(instance::class.memberFunctions, methodName, instance, *providedParams) + } catch (e:AppiumException) { + throw AppiumException("Cannot execute method for instance of " + + "'${instance::class.qualifiedName}'. Reason: ${e.message}'"); + } } } diff --git a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/helpers/ViewFinder.java b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/helpers/ViewFinder.java index f5c2dced1..b95536999 100644 --- a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/helpers/ViewFinder.java +++ b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/helpers/ViewFinder.java @@ -20,8 +20,10 @@ import androidx.test.espresso.DataInteraction; import androidx.test.espresso.EspressoException; +import androidx.test.espresso.PerformException; import androidx.test.espresso.ViewInteraction; import android.view.View; +import android.view.ViewParent; import android.widget.AdapterView; import org.hamcrest.Description; @@ -38,6 +40,7 @@ import io.appium.espressoserver.lib.handlers.exceptions.AppiumException; import io.appium.espressoserver.lib.handlers.exceptions.InvalidStrategyException; import io.appium.espressoserver.lib.handlers.exceptions.XPathLookupException; +import io.appium.espressoserver.lib.model.DataMatcherJson; import io.appium.espressoserver.lib.model.Strategy; import io.appium.espressoserver.lib.viewaction.ViewGetter; @@ -189,6 +192,10 @@ private static List findAllBy(@Nullable View root, Strategy strategy, case VIEW_TAG: views = getViews(root, withTagValue(allOf(instanceOf(String.class), equalTo((Object) selector))), findOne); break; + case DATAMATCHER: + DataMatcherJson matcher = DataMatcherJson.Companion.fromJson(selector); + views = getViewsFromDataInteraction(root, matcher.invoke()); + break; default: throw new InvalidStrategyException(String.format("Strategy is not implemented: %s", strategy.getStrategyName())); } @@ -222,6 +229,30 @@ private static boolean canScrollToViewWithContentDescription(@Nullable final Vie return true; } + private static List getViewsFromDataInteraction( + @Nullable View root, DataInteraction dataInteraction + ) { + // Defensive copy + DataInteraction dataInteractionCopy = dataInteraction; + + // Look up the view hierarchy to find the closest ancestor AdapterView + View ancestorAdapterView = root; + while (ancestorAdapterView != null && !(ancestorAdapterView instanceof AdapterView)) { + ViewParent parent = ancestorAdapterView.getParent(); + ancestorAdapterView = parent == null ? null : (View) parent; + } + if (ancestorAdapterView != null) { + dataInteractionCopy = dataInteractionCopy.inAdapterView(withView(ancestorAdapterView)); + } + + try { + return Collections.singletonList(new ViewGetter().getView(dataInteractionCopy)); + } catch (PerformException e) { + // Perform Exception means nothing was found. Return empty list + return Collections.emptyList(); + } + } + private static List getViews( @Nullable View root, Matcher matcher, boolean findOne) { // If it's just one view we want, return a singleton list diff --git a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/helpers/XMLHelpers.java b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/helpers/XMLHelpers.java index 0564aac7c..485539f3e 100644 --- a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/helpers/XMLHelpers.java +++ b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/helpers/XMLHelpers.java @@ -16,10 +16,10 @@ package io.appium.espressoserver.lib.helpers; -import androidx.annotation.Nullable; - import java.util.regex.Pattern; +import androidx.annotation.Nullable; + public abstract class XMLHelpers { // XML 1.0 Legal Characters (http://stackoverflow.com/a/4237934/347155) // #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF] diff --git a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/helpers/w3c/adapter/espresso/AndroidKeyEvent.java b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/helpers/w3c/adapter/espresso/AndroidKeyEvent.java index 4dcc798ac..47111e72a 100644 --- a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/helpers/w3c/adapter/espresso/AndroidKeyEvent.java +++ b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/helpers/w3c/adapter/espresso/AndroidKeyEvent.java @@ -17,8 +17,118 @@ import io.appium.espressoserver.lib.helpers.AndroidLogger; import io.appium.espressoserver.lib.helpers.w3c.dispatcher.W3CKeyEvent; -import static android.view.KeyEvent.*; -import static io.appium.espressoserver.lib.helpers.w3c.dispatcher.constants.NormalizedKeys.*; +import static android.view.KeyEvent.ACTION_DOWN; +import static android.view.KeyEvent.ACTION_UP; +import static android.view.KeyEvent.KEYCODE_0; +import static android.view.KeyEvent.KEYCODE_1; +import static android.view.KeyEvent.KEYCODE_2; +import static android.view.KeyEvent.KEYCODE_3; +import static android.view.KeyEvent.KEYCODE_4; +import static android.view.KeyEvent.KEYCODE_5; +import static android.view.KeyEvent.KEYCODE_6; +import static android.view.KeyEvent.KEYCODE_7; +import static android.view.KeyEvent.KEYCODE_8; +import static android.view.KeyEvent.KEYCODE_9; +import static android.view.KeyEvent.KEYCODE_ALT_LEFT; +import static android.view.KeyEvent.KEYCODE_BREAK; +import static android.view.KeyEvent.KEYCODE_CLEAR; +import static android.view.KeyEvent.KEYCODE_COMMA; +import static android.view.KeyEvent.KEYCODE_CTRL_LEFT; +import static android.view.KeyEvent.KEYCODE_DEL; +import static android.view.KeyEvent.KEYCODE_DPAD_DOWN; +import static android.view.KeyEvent.KEYCODE_DPAD_LEFT; +import static android.view.KeyEvent.KEYCODE_DPAD_RIGHT; +import static android.view.KeyEvent.KEYCODE_ENTER; +import static android.view.KeyEvent.KEYCODE_EQUALS; +import static android.view.KeyEvent.KEYCODE_ESCAPE; +import static android.view.KeyEvent.KEYCODE_F1; +import static android.view.KeyEvent.KEYCODE_F10; +import static android.view.KeyEvent.KEYCODE_F11; +import static android.view.KeyEvent.KEYCODE_F12; +import static android.view.KeyEvent.KEYCODE_F2; +import static android.view.KeyEvent.KEYCODE_F3; +import static android.view.KeyEvent.KEYCODE_F4; +import static android.view.KeyEvent.KEYCODE_F5; +import static android.view.KeyEvent.KEYCODE_F6; +import static android.view.KeyEvent.KEYCODE_F7; +import static android.view.KeyEvent.KEYCODE_F8; +import static android.view.KeyEvent.KEYCODE_F9; +import static android.view.KeyEvent.KEYCODE_FORWARD_DEL; +import static android.view.KeyEvent.KEYCODE_HELP; +import static android.view.KeyEvent.KEYCODE_HOME; +import static android.view.KeyEvent.KEYCODE_INSERT; +import static android.view.KeyEvent.KEYCODE_META_LEFT; +import static android.view.KeyEvent.KEYCODE_MINUS; +import static android.view.KeyEvent.KEYCODE_MOVE_END; +import static android.view.KeyEvent.KEYCODE_NUMPAD_ADD; +import static android.view.KeyEvent.KEYCODE_PAGE_DOWN; +import static android.view.KeyEvent.KEYCODE_PAGE_UP; +import static android.view.KeyEvent.KEYCODE_PERIOD; +import static android.view.KeyEvent.KEYCODE_SEMICOLON; +import static android.view.KeyEvent.KEYCODE_SHIFT_LEFT; +import static android.view.KeyEvent.KEYCODE_SLASH; +import static android.view.KeyEvent.KEYCODE_SPACE; +import static android.view.KeyEvent.KEYCODE_STAR; +import static android.view.KeyEvent.KEYCODE_TAB; +import static android.view.KeyEvent.KEYCODE_UNKNOWN; +import static android.view.KeyEvent.KEYCODE_ZENKAKU_HANKAKU; +import static android.view.KeyEvent.META_ALT_MASK; +import static android.view.KeyEvent.META_CTRL_MASK; +import static android.view.KeyEvent.META_SHIFT_MASK; +import static io.appium.espressoserver.lib.helpers.w3c.dispatcher.constants.NormalizedKeys.ALT; +import static io.appium.espressoserver.lib.helpers.w3c.dispatcher.constants.NormalizedKeys.ARROW_DOWN; +import static io.appium.espressoserver.lib.helpers.w3c.dispatcher.constants.NormalizedKeys.ARROW_LEFT; +import static io.appium.espressoserver.lib.helpers.w3c.dispatcher.constants.NormalizedKeys.ARROW_RIGHT; +import static io.appium.espressoserver.lib.helpers.w3c.dispatcher.constants.NormalizedKeys.ARROW_UP; +import static io.appium.espressoserver.lib.helpers.w3c.dispatcher.constants.NormalizedKeys.ASTERISK; +import static io.appium.espressoserver.lib.helpers.w3c.dispatcher.constants.NormalizedKeys.BACKSPACE; +import static io.appium.espressoserver.lib.helpers.w3c.dispatcher.constants.NormalizedKeys.CLEAR; +import static io.appium.espressoserver.lib.helpers.w3c.dispatcher.constants.NormalizedKeys.COMMA; +import static io.appium.espressoserver.lib.helpers.w3c.dispatcher.constants.NormalizedKeys.CONTROL; +import static io.appium.espressoserver.lib.helpers.w3c.dispatcher.constants.NormalizedKeys.DELETE; +import static io.appium.espressoserver.lib.helpers.w3c.dispatcher.constants.NormalizedKeys.EIGHT; +import static io.appium.espressoserver.lib.helpers.w3c.dispatcher.constants.NormalizedKeys.END; +import static io.appium.espressoserver.lib.helpers.w3c.dispatcher.constants.NormalizedKeys.EQUALS; +import static io.appium.espressoserver.lib.helpers.w3c.dispatcher.constants.NormalizedKeys.ESCAPE; +import static io.appium.espressoserver.lib.helpers.w3c.dispatcher.constants.NormalizedKeys.F1; +import static io.appium.espressoserver.lib.helpers.w3c.dispatcher.constants.NormalizedKeys.F10; +import static io.appium.espressoserver.lib.helpers.w3c.dispatcher.constants.NormalizedKeys.F11; +import static io.appium.espressoserver.lib.helpers.w3c.dispatcher.constants.NormalizedKeys.F12; +import static io.appium.espressoserver.lib.helpers.w3c.dispatcher.constants.NormalizedKeys.F2; +import static io.appium.espressoserver.lib.helpers.w3c.dispatcher.constants.NormalizedKeys.F3; +import static io.appium.espressoserver.lib.helpers.w3c.dispatcher.constants.NormalizedKeys.F4; +import static io.appium.espressoserver.lib.helpers.w3c.dispatcher.constants.NormalizedKeys.F5; +import static io.appium.espressoserver.lib.helpers.w3c.dispatcher.constants.NormalizedKeys.F6; +import static io.appium.espressoserver.lib.helpers.w3c.dispatcher.constants.NormalizedKeys.F7; +import static io.appium.espressoserver.lib.helpers.w3c.dispatcher.constants.NormalizedKeys.F8; +import static io.appium.espressoserver.lib.helpers.w3c.dispatcher.constants.NormalizedKeys.F9; +import static io.appium.espressoserver.lib.helpers.w3c.dispatcher.constants.NormalizedKeys.FIVE; +import static io.appium.espressoserver.lib.helpers.w3c.dispatcher.constants.NormalizedKeys.FORWARD_SLASH; +import static io.appium.espressoserver.lib.helpers.w3c.dispatcher.constants.NormalizedKeys.FOUR; +import static io.appium.espressoserver.lib.helpers.w3c.dispatcher.constants.NormalizedKeys.HELP; +import static io.appium.espressoserver.lib.helpers.w3c.dispatcher.constants.NormalizedKeys.HOME; +import static io.appium.espressoserver.lib.helpers.w3c.dispatcher.constants.NormalizedKeys.HYPHEN; +import static io.appium.espressoserver.lib.helpers.w3c.dispatcher.constants.NormalizedKeys.INSERT; +import static io.appium.espressoserver.lib.helpers.w3c.dispatcher.constants.NormalizedKeys.META; +import static io.appium.espressoserver.lib.helpers.w3c.dispatcher.constants.NormalizedKeys.NINE; +import static io.appium.espressoserver.lib.helpers.w3c.dispatcher.constants.NormalizedKeys.ONE; +import static io.appium.espressoserver.lib.helpers.w3c.dispatcher.constants.NormalizedKeys.PAGEDOWN; +import static io.appium.espressoserver.lib.helpers.w3c.dispatcher.constants.NormalizedKeys.PAGEUP; +import static io.appium.espressoserver.lib.helpers.w3c.dispatcher.constants.NormalizedKeys.PAUSE; +import static io.appium.espressoserver.lib.helpers.w3c.dispatcher.constants.NormalizedKeys.PERIOD; +import static io.appium.espressoserver.lib.helpers.w3c.dispatcher.constants.NormalizedKeys.PLUS; +import static io.appium.espressoserver.lib.helpers.w3c.dispatcher.constants.NormalizedKeys.RETURN; +import static io.appium.espressoserver.lib.helpers.w3c.dispatcher.constants.NormalizedKeys.SEMICOLON; +import static io.appium.espressoserver.lib.helpers.w3c.dispatcher.constants.NormalizedKeys.SEVEN; +import static io.appium.espressoserver.lib.helpers.w3c.dispatcher.constants.NormalizedKeys.SHIFT; +import static io.appium.espressoserver.lib.helpers.w3c.dispatcher.constants.NormalizedKeys.SIX; +import static io.appium.espressoserver.lib.helpers.w3c.dispatcher.constants.NormalizedKeys.TAB; +import static io.appium.espressoserver.lib.helpers.w3c.dispatcher.constants.NormalizedKeys.THREE; +import static io.appium.espressoserver.lib.helpers.w3c.dispatcher.constants.NormalizedKeys.TWO; +import static io.appium.espressoserver.lib.helpers.w3c.dispatcher.constants.NormalizedKeys.UNIDENTIFIED; +import static io.appium.espressoserver.lib.helpers.w3c.dispatcher.constants.NormalizedKeys.WHITESPACE; +import static io.appium.espressoserver.lib.helpers.w3c.dispatcher.constants.NormalizedKeys.ZENKAKU_HANKAKU; +import static io.appium.espressoserver.lib.helpers.w3c.dispatcher.constants.NormalizedKeys.ZERO; public class AndroidKeyEvent { diff --git a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/helpers/w3c/adapter/espresso/AndroidMotionEvent.java b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/helpers/w3c/adapter/espresso/AndroidMotionEvent.java index 709120fab..221b17638 100644 --- a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/helpers/w3c/adapter/espresso/AndroidMotionEvent.java +++ b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/helpers/w3c/adapter/espresso/AndroidMotionEvent.java @@ -1,7 +1,5 @@ package io.appium.espressoserver.lib.helpers.w3c.adapter.espresso; -import androidx.annotation.Nullable; -import androidx.test.espresso.UiController; import android.view.KeyEvent; import android.view.MotionEvent; @@ -9,6 +7,8 @@ import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import androidx.annotation.Nullable; +import androidx.test.espresso.UiController; import io.appium.espressoserver.lib.handlers.exceptions.AppiumException; import io.appium.espressoserver.lib.helpers.w3c.models.InputSource.PointerType; import io.appium.espressoserver.lib.helpers.w3c.state.KeyInputState; diff --git a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/helpers/w3c/adapter/espresso/EspressoW3CActionAdapter.java b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/helpers/w3c/adapter/espresso/EspressoW3CActionAdapter.java index 3188fa6ed..89918647b 100644 --- a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/helpers/w3c/adapter/espresso/EspressoW3CActionAdapter.java +++ b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/helpers/w3c/adapter/espresso/EspressoW3CActionAdapter.java @@ -1,8 +1,6 @@ package io.appium.espressoserver.lib.helpers.w3c.adapter.espresso; import android.graphics.Point; - -import androidx.test.espresso.UiController; import android.util.DisplayMetrics; import android.view.View; @@ -10,6 +8,7 @@ import java.util.List; import java.util.Set; +import androidx.test.espresso.UiController; import androidx.test.espresso.action.GeneralLocation; import io.appium.espressoserver.lib.handlers.exceptions.AppiumException; import io.appium.espressoserver.lib.helpers.AndroidLogger; diff --git a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/helpers/w3c/adapter/espresso/Helpers.java b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/helpers/w3c/adapter/espresso/Helpers.java index b7787c42a..8466fc4d3 100644 --- a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/helpers/w3c/adapter/espresso/Helpers.java +++ b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/helpers/w3c/adapter/espresso/Helpers.java @@ -2,9 +2,9 @@ import android.graphics.Point; import android.os.Build; -import androidx.annotation.Nullable; import android.view.MotionEvent; +import androidx.annotation.Nullable; import io.appium.espressoserver.lib.handlers.exceptions.AppiumException; import io.appium.espressoserver.lib.helpers.AndroidLogger; import io.appium.espressoserver.lib.helpers.w3c.models.InputSource.PointerType; diff --git a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/helpers/w3c/adapter/espresso/MultiTouchState.java b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/helpers/w3c/adapter/espresso/MultiTouchState.java index a682e6da2..ef1fea830 100644 --- a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/helpers/w3c/adapter/espresso/MultiTouchState.java +++ b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/helpers/w3c/adapter/espresso/MultiTouchState.java @@ -1,7 +1,6 @@ package io.appium.espressoserver.lib.helpers.w3c.adapter.espresso; import android.os.SystemClock; -import androidx.test.espresso.UiController; import android.view.MotionEvent; import java.util.ArrayList; @@ -11,6 +10,7 @@ import javax.annotation.Nullable; +import androidx.test.espresso.UiController; import io.appium.espressoserver.lib.handlers.exceptions.AppiumException; import io.appium.espressoserver.lib.helpers.w3c.state.KeyInputState; diff --git a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/helpers/w3c/models/Actions.java b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/helpers/w3c/models/Actions.java index 60a59e649..85e762a1a 100644 --- a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/helpers/w3c/models/Actions.java +++ b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/helpers/w3c/models/Actions.java @@ -16,11 +16,10 @@ package io.appium.espressoserver.lib.helpers.w3c.models; -import androidx.annotation.Nullable; - import java.util.List; import java.util.concurrent.ExecutionException; +import androidx.annotation.Nullable; import io.appium.espressoserver.lib.handlers.exceptions.AppiumException; import io.appium.espressoserver.lib.helpers.w3c.adapter.W3CActionAdapter; import io.appium.espressoserver.lib.helpers.w3c.state.ActiveInputSources; diff --git a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/helpers/w3c_actions/ActionsHelpers.java b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/helpers/w3c_actions/ActionsHelpers.java index a15f04b1e..311ba3d28 100644 --- a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/helpers/w3c_actions/ActionsHelpers.java +++ b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/helpers/w3c_actions/ActionsHelpers.java @@ -18,7 +18,6 @@ import android.graphics.Rect; import android.os.Build; -import androidx.annotation.Nullable; import android.util.LongSparseArray; import android.view.InputDevice; import android.view.KeyEvent; @@ -36,6 +35,7 @@ import java.util.List; import java.util.Set; +import androidx.annotation.Nullable; import io.appium.espressoserver.lib.model.Element; import io.appium.espressoserver.lib.model.ViewElement; diff --git a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/http/Router.java b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/http/Router.java index 1c930d43b..8e0a19c62 100644 --- a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/http/Router.java +++ b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/http/Router.java @@ -60,8 +60,8 @@ import io.appium.espressoserver.lib.handlers.Keys; import io.appium.espressoserver.lib.handlers.MobileBackdoor; import io.appium.espressoserver.lib.handlers.MobileClickAction; -import io.appium.espressoserver.lib.handlers.MobileViewFlash; import io.appium.espressoserver.lib.handlers.MobileSwipe; +import io.appium.espressoserver.lib.handlers.MobileViewFlash; import io.appium.espressoserver.lib.handlers.MultiTouchAction; import io.appium.espressoserver.lib.handlers.MultiTouchActionsParams; import io.appium.espressoserver.lib.handlers.NavigateTo; @@ -104,7 +104,6 @@ import io.appium.espressoserver.lib.http.response.BaseResponse; import io.appium.espressoserver.lib.model.AppiumParams; import io.appium.espressoserver.lib.model.AppiumStatus; -import io.appium.espressoserver.lib.model.MobileClickActionParams; import io.appium.espressoserver.lib.model.DrawerActionParams; import io.appium.espressoserver.lib.model.EditorActionParams; import io.appium.espressoserver.lib.model.ElementValueParams; @@ -112,6 +111,7 @@ import io.appium.espressoserver.lib.model.KeyEventParams; import io.appium.espressoserver.lib.model.Locator; import io.appium.espressoserver.lib.model.MobileBackdoorParams; +import io.appium.espressoserver.lib.model.MobileClickActionParams; import io.appium.espressoserver.lib.model.MobileSwipeParams; import io.appium.espressoserver.lib.model.MotionEventParams; import io.appium.espressoserver.lib.model.NavigateToParams; diff --git a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/http/response/AppiumResponse.java b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/http/response/AppiumResponse.java index f65e1d33e..e9edc5eeb 100644 --- a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/http/response/AppiumResponse.java +++ b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/http/response/AppiumResponse.java @@ -16,10 +16,9 @@ package io.appium.espressoserver.lib.http.response; -import androidx.annotation.Nullable; - import java.util.UUID; +import androidx.annotation.Nullable; import fi.iki.elonen.NanoHTTPD.Response.Status; import io.appium.espressoserver.lib.model.AppiumStatus; diff --git a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/model/ActionsParams.java b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/model/ActionsParams.java index 189973056..ddffb29b9 100644 --- a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/model/ActionsParams.java +++ b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/model/ActionsParams.java @@ -17,7 +17,6 @@ package io.appium.espressoserver.lib.model; import androidx.annotation.Nullable; - import io.appium.espressoserver.lib.helpers.w3c.models.Actions; @SuppressWarnings("unused") diff --git a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/model/DataMatcherJson.kt b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/model/DataMatcherJson.kt new file mode 100644 index 000000000..2146085f4 --- /dev/null +++ b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/model/DataMatcherJson.kt @@ -0,0 +1,46 @@ +package io.appium.espressoserver.lib.model + +import androidx.test.espresso.DataInteraction +import androidx.test.espresso.Espresso.onData +import com.google.gson.* +import com.google.gson.annotations.JsonAdapter +import io.appium.espressoserver.lib.handlers.exceptions.AppiumException +import io.appium.espressoserver.lib.handlers.exceptions.InvalidStrategyException +import org.hamcrest.Matcher +import java.lang.reflect.Type + +@JsonAdapter(DataMatcherJson.DataMatcherJsonDeserializer::class) +data class DataMatcherJson(val matcher:Matcher<*>) : AppiumParams() { + + fun invoke(): DataInteraction { + return onData(matcher); + } + + class DataMatcherJsonDeserializer : JsonDeserializer { + @Throws(JsonParseException::class) + override fun deserialize(json: JsonElement, paramType: Type?, + paramJsonDeserializationContext: JsonDeserializationContext?): DataMatcherJson { + if (!json.isJsonObject) { + throw JsonParseException("Data matcher must be an object. Found '${json}'") + } + + val matcher = HamcrestMatcher.HamcrestMatcherDeserializer() + .deserialize(json, null, null) + .invoke(); + + return DataMatcherJson(matcher) + } + } + + companion object { + fun fromJson(selector:String): DataMatcherJson { + try { + return Gson().fromJson(selector, DataMatcherJson::class.java) + } catch (e: AppiumException) { + throw InvalidStrategyException(String.format("Not a valid selector '%s'. Reason: '%s'", selector, e.cause)) + } catch (e: JsonParseException) { + throw InvalidStrategyException(String.format("Could not parse selector '%s'. Reason: '%s'", selector, e.cause)) + } + } + } +} \ No newline at end of file diff --git a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/model/DrawerActionParams.java b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/model/DrawerActionParams.java index eb8812ea1..3dd32c560 100644 --- a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/model/DrawerActionParams.java +++ b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/model/DrawerActionParams.java @@ -16,8 +16,6 @@ package io.appium.espressoserver.lib.model; -import com.google.gson.annotations.SerializedName; - import javax.annotation.Nullable; @SuppressWarnings("unused") diff --git a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/model/Element.java b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/model/Element.java index 04ce03be6..e53d7b2b1 100644 --- a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/model/Element.java +++ b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/model/Element.java @@ -16,9 +16,6 @@ package io.appium.espressoserver.lib.model; -import androidx.test.espresso.DataInteraction; -import androidx.test.espresso.EspressoException; -import androidx.test.espresso.ViewInteraction; import android.view.View; import android.view.ViewParent; import android.widget.AdapterView; @@ -31,6 +28,9 @@ import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; +import androidx.test.espresso.DataInteraction; +import androidx.test.espresso.EspressoException; +import androidx.test.espresso.ViewInteraction; import io.appium.espressoserver.lib.handlers.exceptions.AppiumException; import io.appium.espressoserver.lib.handlers.exceptions.StaleElementException; import io.appium.espressoserver.lib.viewaction.ViewGetter; @@ -41,8 +41,8 @@ import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; import static androidx.test.espresso.matcher.ViewMatchers.withContentDescription; import static io.appium.espressoserver.lib.viewmatcher.WithView.withView; -import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.Matchers.hasEntry; +import static org.hamcrest.Matchers.is; @SuppressWarnings("unused") diff --git a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/model/HamcrestMatcher.kt b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/model/HamcrestMatcher.kt new file mode 100644 index 000000000..00793e167 --- /dev/null +++ b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/model/HamcrestMatcher.kt @@ -0,0 +1,93 @@ +package io.appium.espressoserver.lib.model + +import com.google.gson.JsonDeserializationContext +import com.google.gson.JsonDeserializer +import com.google.gson.JsonElement +import com.google.gson.JsonParseException +import com.google.gson.annotations.JsonAdapter +import io.appium.espressoserver.lib.handlers.exceptions.InvalidArgumentException +import io.appium.espressoserver.lib.helpers.GsonParserHelpers +import io.appium.espressoserver.lib.helpers.KReflectionUtils +import org.hamcrest.Matcher +import org.hamcrest.Matchers +import java.lang.reflect.Type +import kotlin.reflect.KClass + +@JsonAdapter(HamcrestMatcher.HamcrestMatcherDeserializer::class) +data class HamcrestMatcher (var name:String, var args:Array, var matcherClass:KClass<*> = Matchers::class) { + + fun invoke():Matcher<*> { + val matcher = KReflectionUtils.invokeMethod(this.matcherClass, this.name, *this.args) + if (matcher !is Matcher<*>) { + throw InvalidArgumentException("'${this}' does not return a Matcher when invoked. Found '${matcher!!::class.qualifiedName}'"); + } + return matcher; + } + + class HamcrestMatcherDeserializer : JsonDeserializer { + @Throws(JsonParseException::class) + override fun deserialize(json: JsonElement, paramType: Type?, + paramJsonDeserializationContext: JsonDeserializationContext?): HamcrestMatcher { + + if (json.isJsonObject) { + + val jsonObj = json.asJsonObject + + // Validate and parse the name property + val nameProp = jsonObj.get("name") + + if (nameProp == null) { + throw JsonParseException("Matcher must contain 'name' property") + } else if (!nameProp.isJsonPrimitive) { + throw JsonParseException("'name' property on matcher must be a JSON primitive") + } + + val name = nameProp.asString + + // Parse args property + val listOfArgs = GsonParserHelpers.asArray(jsonObj, "args") + + val args = arrayListOf() + for (arg in listOfArgs) { + when { + arg.isJsonPrimitive -> args.add(GsonParserHelpers.parsePrimitive(arg.asJsonPrimitive)) + arg.isJsonNull -> args.add(null) + arg.isJsonObject -> args.add(HamcrestMatcherDeserializer().deserialize(arg, null, null).invoke()) + } + } + + // Parse the 'class' property + jsonObj.get("class")?.let { + if (it.isJsonPrimitive) { + val className = it.asString + + // Try fully casting class as fully qualified name + try { + val matcherClass = Class.forName(className).kotlin; + return HamcrestMatcher(name, args.toTypedArray(), matcherClass) + } catch (cnfe: ClassNotFoundException) { } + + // If above didn't work, try prepending 'androidx.test.espresso.matcher' package name + try { + val qualifiedClassName = "androidx.test.espresso.matcher.${className}"; + val matcherClass = Class.forName(qualifiedClassName).kotlin + return HamcrestMatcher(name, args.toTypedArray(), matcherClass) + } catch (cnfe: ClassCastException) { + throw JsonParseException("No such class found '${className}'") + } + } + + throw JsonParseException("'matcherClass' must be a string. Found '${it}'") + } + + return HamcrestMatcher(name, args.toTypedArray()) + } else if (json.isJsonPrimitive) { + // If it's just a primitive, return that as the name and no args + return HamcrestMatcher(json.asString, emptyArray()); + } + + throw JsonParseException("Matcher must be a JSON object with a 'name' property (required) " + + "and optional 'args' property and 'matcherClass' property"); + } + } +} \ No newline at end of file diff --git a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/model/MobileClickActionParams.kt b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/model/MobileClickActionParams.kt index a15b78aa5..5beab469b 100644 --- a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/model/MobileClickActionParams.kt +++ b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/model/MobileClickActionParams.kt @@ -50,10 +50,8 @@ class MobileClickActionParams : AppiumParams() { clickActionParams.buttonState = jsonObject.get("buttonState").asInt } - val gsonParserHelpers = GsonParserHelpers(); - // Deserialize TAPPER as a tap enum - clickActionParams.tapper = gsonParserHelpers.parseEnum( + clickActionParams.tapper = GsonParserHelpers.parseEnum( jsonObject, "tapper", "See https://developer.android.com/reference/android/support/test/espresso/action/Tap for list of valid tapper types", @@ -61,7 +59,7 @@ class MobileClickActionParams : AppiumParams() { ) // Deserialize COORDINATES_PROVIDER as a general location enum - clickActionParams.coordinatesProvider = gsonParserHelpers.parseEnum( + clickActionParams.coordinatesProvider = GsonParserHelpers.parseEnum( jsonObject, "coordinatesProvider", "See https://developer.android.com/reference/android/support/test/espresso/action/GeneralLocation for list of valid coordinatesProvider types", @@ -69,7 +67,7 @@ class MobileClickActionParams : AppiumParams() { ) // Deserialize PRECISION_DESCRIBER as a 'Press' enum - clickActionParams.precisionDescriber = gsonParserHelpers.parseEnum( + clickActionParams.precisionDescriber = GsonParserHelpers.parseEnum( jsonObject, "precisionDescriber", "See https://developer.android.com/reference/android/support/test/espresso/action/Press for list of valid precisionDescriber types", diff --git a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/model/MobileSwipeParams.kt b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/model/MobileSwipeParams.kt index 4b380a1ab..48f74767c 100644 --- a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/model/MobileSwipeParams.kt +++ b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/model/MobileSwipeParams.kt @@ -23,7 +23,6 @@ import com.google.gson.JsonElement import com.google.gson.JsonParseException import com.google.gson.annotations.JsonAdapter import com.google.gson.annotations.SerializedName -import io.appium.espressoserver.lib.handlers.exceptions.InvalidArgumentException import io.appium.espressoserver.lib.helpers.GsonParserHelpers import java.lang.reflect.Type @@ -55,17 +54,16 @@ class MobileSwipeParams : AppiumParams() { val swipeActionParams = MobileSwipeParams() val jsonObject = json.asJsonObject - val gsonParserHelpers = GsonParserHelpers(); // Deserialize 'direction' - swipeActionParams.direction = gsonParserHelpers.parseEnum( + swipeActionParams.direction = GsonParserHelpers.parseEnum( jsonObject, "direction", "See https://developer.android.com/reference/android/support/test/espresso/action/Swipe for list of valid tapper types" ); // Deserialize 'swiper' - swipeActionParams.swiper = gsonParserHelpers.parseEnum( + swipeActionParams.swiper = GsonParserHelpers.parseEnum( jsonObject, "swiper", "See https://developer.android.com/reference/android/support/test/espresso/action/Swipe for list of valid tapper types" @@ -79,7 +77,7 @@ class MobileSwipeParams : AppiumParams() { } // Deserialize 'startCoordinates' - swipeActionParams.startCoordinates = gsonParserHelpers.parseEnum( + swipeActionParams.startCoordinates = GsonParserHelpers.parseEnum( jsonObject, "startCoordinates", "See https://developer.android.com/reference/android/support/test/espresso/action/GeneralLocation for list of valid coordinate types", @@ -87,7 +85,7 @@ class MobileSwipeParams : AppiumParams() { ) // Deserialize 'endCoordinates' - swipeActionParams.endCoordinates = gsonParserHelpers.parseEnum( + swipeActionParams.endCoordinates = GsonParserHelpers.parseEnum( jsonObject, "endCoordinates", "See https://developer.android.com/reference/android/support/test/espresso/action/GeneralLocation for list of valid coordinate types", @@ -95,7 +93,7 @@ class MobileSwipeParams : AppiumParams() { ) // Deserialize 'precisionDescriber' - swipeActionParams.precisionDescriber = gsonParserHelpers.parseEnum( + swipeActionParams.precisionDescriber = GsonParserHelpers.parseEnum( jsonObject, "precisionDescriber", "See https://developer.android.com/reference/android/support/test/espresso/action/Press for list of valid precision types", diff --git a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/model/SetDateParams.java b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/model/SetDateParams.java index 177d0aff3..27a5c7543 100644 --- a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/model/SetDateParams.java +++ b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/model/SetDateParams.java @@ -16,8 +16,6 @@ package io.appium.espressoserver.lib.model; -import javax.annotation.Nullable; - @SuppressWarnings("unused") public class SetDateParams extends AppiumParams { private Integer year; diff --git a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/model/Strategy.java b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/model/Strategy.java index efb903488..930726ff4 100644 --- a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/model/Strategy.java +++ b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/model/Strategy.java @@ -44,7 +44,9 @@ public enum Strategy { @SerializedName("text") TEXT("text"), @SerializedName(value="-android viewtag", alternate={"tag name"}) - VIEW_TAG("-android viewtag"); + VIEW_TAG("-android viewtag"), + @SerializedName(value="-android datamatcher") + DATAMATCHER("-android datamatcher"); private final String strategyName; diff --git a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/model/web/WebAtom.kt b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/model/web/WebAtom.kt index 1ec32998e..6c9f7285c 100644 --- a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/model/web/WebAtom.kt +++ b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/model/web/WebAtom.kt @@ -16,13 +16,17 @@ package io.appium.espressoserver.lib.model.web -import com.google.gson.* +import com.google.gson.JsonDeserializationContext +import com.google.gson.JsonDeserializer +import com.google.gson.JsonElement +import com.google.gson.JsonParseException import com.google.gson.annotations.JsonAdapter +import io.appium.espressoserver.lib.helpers.GsonParserHelpers import io.appium.espressoserver.lib.model.AppiumParams import java.lang.reflect.Type @JsonAdapter(WebAtom.WebAtomDeserializer::class) -data class WebAtom(val name: String, val args: List = emptyList()) : AppiumParams() { +data class WebAtom(val name: String, val args: Array = emptyArray()) : AppiumParams() { class WebAtomDeserializer : JsonDeserializer { @Throws(JsonParseException::class) override fun deserialize(json: JsonElement, paramType: Type?, @@ -58,7 +62,7 @@ data class WebAtom(val name: String, val args: List = emptyList()) : Appium } // Set the args as locator - return WebAtom(webAtomName, arrayListOf( + return WebAtom(webAtomName, arrayOf( locator.get("using").asString, locator.get("value").asString )) @@ -67,20 +71,17 @@ data class WebAtom(val name: String, val args: List = emptyList()) : Appium // Parse the args jsonObj.get("args")?.let { if (it.isJsonPrimitive) { - return WebAtom(webAtomName, arrayListOf(it.asString)) + return WebAtom(webAtomName, arrayOf(it.asString)) } else if (it.isJsonArray){ val argsAsList = ArrayList() for (arg in it.asJsonArray) { if (arg.isJsonPrimitive) { - val argPrimitive = arg.asJsonPrimitive - if (argPrimitive.isBoolean) argsAsList.add(argPrimitive.asBoolean) - if (argPrimitive.isNumber) argsAsList.add(argPrimitive.asNumber) - if (argPrimitive.isString) argsAsList.add(argPrimitive.asString) + argsAsList.add(GsonParserHelpers.parsePrimitive(arg.asJsonPrimitive)) } else { throw JsonParseException("'${arg}' is not a valid 'arg' type"); } } - return WebAtom(webAtomName, argsAsList) + return WebAtom(webAtomName, argsAsList.toArray()) } else { throw JsonParseException("'args' must be an array or a singleton primitive JSON type. Found '${it}' ") } @@ -88,12 +89,12 @@ data class WebAtom(val name: String, val args: List = emptyList()) : Appium // If no args provided, treat it as a function call with no parameters if (!jsonObj.has("args")) { - return WebAtom(webAtomName, emptyList()); + return WebAtom(webAtomName, emptyArray()); } } else if (json.isJsonPrimitive) { // If JSON was provided as a String, treat it as a function call with no parameters - return WebAtom(json.asString, emptyList()) + return WebAtom(json.asString, emptyArray()) } // This block is unreachable diff --git a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/viewaction/ScrollTo.java b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/viewaction/ScrollTo.java index 416451c4a..448dd0432 100644 --- a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/viewaction/ScrollTo.java +++ b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/viewaction/ScrollTo.java @@ -16,8 +16,6 @@ package io.appium.espressoserver.lib.viewaction; -import androidx.test.espresso.UiController; -import androidx.test.espresso.ViewAction; import android.view.View; import android.widget.AbsListView; @@ -25,6 +23,9 @@ import javax.annotation.Nullable; +import androidx.test.espresso.UiController; +import androidx.test.espresso.ViewAction; + import static androidx.test.espresso.matcher.ViewMatchers.isDescendantOfA; import static androidx.test.espresso.matcher.ViewMatchers.isRoot; diff --git a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/viewaction/UiControllerPerformer.java b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/viewaction/UiControllerPerformer.java index 8a00d34c5..7973f83ce 100644 --- a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/viewaction/UiControllerPerformer.java +++ b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/viewaction/UiControllerPerformer.java @@ -1,13 +1,13 @@ package io.appium.espressoserver.lib.viewaction; -import androidx.test.espresso.NoMatchingViewException; -import androidx.test.espresso.UiController; -import androidx.test.espresso.ViewAction; -import androidx.test.espresso.ViewInteraction; import android.view.View; import org.hamcrest.Matcher; +import androidx.test.espresso.NoMatchingViewException; +import androidx.test.espresso.UiController; +import androidx.test.espresso.ViewAction; +import androidx.test.espresso.ViewInteraction; import io.appium.espressoserver.lib.handlers.exceptions.AppiumException; import io.appium.espressoserver.lib.helpers.AndroidLogger; diff --git a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/viewaction/UiControllerRunnable.java b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/viewaction/UiControllerRunnable.java index f46c5e4be..b41047622 100644 --- a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/viewaction/UiControllerRunnable.java +++ b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/viewaction/UiControllerRunnable.java @@ -1,7 +1,6 @@ package io.appium.espressoserver.lib.viewaction; import androidx.test.espresso.UiController; - import io.appium.espressoserver.lib.handlers.exceptions.AppiumException; public interface UiControllerRunnable { diff --git a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/viewaction/ViewGetter.java b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/viewaction/ViewGetter.java index 65749cc8e..d8e57c3be 100644 --- a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/viewaction/ViewGetter.java +++ b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/viewaction/ViewGetter.java @@ -22,6 +22,7 @@ import org.hamcrest.Matcher; import org.hamcrest.TypeSafeMatcher; +import androidx.test.espresso.DataInteraction; import androidx.test.espresso.UiController; import androidx.test.espresso.ViewAction; import androidx.test.espresso.ViewInteraction; @@ -83,4 +84,9 @@ public View getView(ViewInteraction viewInteraction) { viewInteraction.perform(new GetViewAction()); return views[0]; } + + public View getView(DataInteraction dataInteraction) { + dataInteraction.perform(new GetViewAction()); + return views[0]; + } } diff --git a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/viewaction/ViewTextGetter.java b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/viewaction/ViewTextGetter.java index 7eef6932f..d86680926 100644 --- a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/viewaction/ViewTextGetter.java +++ b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/viewaction/ViewTextGetter.java @@ -16,9 +16,9 @@ package io.appium.espressoserver.lib.viewaction; -import androidx.test.espresso.ViewInteraction; import android.view.View; +import androidx.test.espresso.ViewInteraction; import io.appium.espressoserver.lib.handlers.exceptions.AppiumException; import io.appium.espressoserver.lib.model.ViewElement; import io.appium.espressoserver.lib.model.ViewText; diff --git a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/viewmatcher/WithXPath.java b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/viewmatcher/WithXPath.java index 92fe785fc..b426b8e7f 100644 --- a/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/viewmatcher/WithXPath.java +++ b/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/viewmatcher/WithXPath.java @@ -16,8 +16,6 @@ package io.appium.espressoserver.lib.viewmatcher; -import androidx.annotation.Nullable; - import android.view.View; import org.hamcrest.Description; @@ -26,6 +24,7 @@ import java.util.List; +import androidx.annotation.Nullable; import io.appium.espressoserver.lib.handlers.exceptions.AppiumException; import io.appium.espressoserver.lib.model.SourceDocument; diff --git a/espresso-server/app/src/test/java/io/appium/espressoserver/test/helpers/GsonParserHelpersTest.kt b/espresso-server/app/src/test/java/io/appium/espressoserver/test/helpers/GsonParserHelpersTest.kt index 3739639d4..72558649e 100644 --- a/espresso-server/app/src/test/java/io/appium/espressoserver/test/helpers/GsonParserHelpersTest.kt +++ b/espresso-server/app/src/test/java/io/appium/espressoserver/test/helpers/GsonParserHelpersTest.kt @@ -16,14 +16,14 @@ class GsonParserHelpersTest { fun shouldParseEnumsFromJsonObj() { val jsonObj = JsonObject() jsonObj.add("b", JsonPrimitive("b")) - val enumValue = GsonParserHelpers().parseEnum(jsonObj, "b", "") + val enumValue = GsonParserHelpers.parseEnum(jsonObj, "b", "") assertEquals(enumValue, BasicEnum.B) } @Test fun shouldReturnNullIfNoObject() { val jsonObj = JsonObject() - val enumValue = GsonParserHelpers().parseEnum(jsonObj, "b", "") + val enumValue = GsonParserHelpers.parseEnum(jsonObj, "b", "") assertNull(enumValue) } @@ -32,7 +32,7 @@ class GsonParserHelpersTest { try { val jsonObj = JsonObject() jsonObj.add("b", JsonPrimitive("z")) - GsonParserHelpers().parseEnum(jsonObj, "b", "") + GsonParserHelpers.parseEnum(jsonObj, "b", "") } catch (jpe:JsonParseException) { return assertTrue(true); } diff --git a/espresso-server/app/src/test/java/io/appium/espressoserver/test/helpers/InvocationOperationTest.java b/espresso-server/app/src/test/java/io/appium/espressoserver/test/helpers/InvocationOperationTest.java index afff60673..30fdbebc3 100644 --- a/espresso-server/app/src/test/java/io/appium/espressoserver/test/helpers/InvocationOperationTest.java +++ b/espresso-server/app/src/test/java/io/appium/espressoserver/test/helpers/InvocationOperationTest.java @@ -9,7 +9,8 @@ import io.appium.espressoserver.lib.helpers.InvocationOperation; import static junit.framework.Assert.fail; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; public class InvocationOperationTest { diff --git a/espresso-server/app/src/test/java/io/appium/espressoserver/test/helpers/KReflectionUtilsTest.kt b/espresso-server/app/src/test/java/io/appium/espressoserver/test/helpers/KReflectionUtilsTest.kt index 26a12ebdd..944b9cbd9 100644 --- a/espresso-server/app/src/test/java/io/appium/espressoserver/test/helpers/KReflectionUtilsTest.kt +++ b/espresso-server/app/src/test/java/io/appium/espressoserver/test/helpers/KReflectionUtilsTest.kt @@ -4,11 +4,14 @@ import androidx.test.espresso.web.model.Atom import androidx.test.espresso.web.webdriver.DriverAtoms import io.appium.espressoserver.lib.handlers.exceptions.AppiumException import io.appium.espressoserver.lib.helpers.KReflectionUtils +import org.hamcrest.Matcher +import org.hamcrest.Matchers import org.junit.Test import org.junit.runner.RunWith import org.robolectric.RobolectricTestRunner import kotlin.reflect.full.memberFunctions import kotlin.test.assertEquals +import kotlin.test.assertFalse import kotlin.test.assertTrue @RunWith(RobolectricTestRunner::class) @@ -51,6 +54,17 @@ class `KReflectionUtils Test` { assertTrue(findElementAtom is Atom<*>); } + @Test + fun `should parse Hamcrest 'instanceOf' matcher with className`() { + arrayOf("java.lang.String", "java.lang.String.class", "String", "String.class") + .forEach {className -> + val hamcrestMatcher = KReflectionUtils.invokeMethod(Matchers::class, "instanceOf", className) + assertTrue(hamcrestMatcher is Matcher<*>) + assertTrue(hamcrestMatcher.matches("Hello World")) + assertFalse(hamcrestMatcher.matches(123)) + } + } + class TestClass { fun plus (numOne: Int, numTwo: Int):Number { return numOne + numTwo; diff --git a/espresso-server/app/src/test/java/io/appium/espressoserver/test/helpers/w3c/ActionsTest.java b/espresso-server/app/src/test/java/io/appium/espressoserver/test/helpers/w3c/ActionsTest.java index 3bd69341b..89e189b0b 100644 --- a/espresso-server/app/src/test/java/io/appium/espressoserver/test/helpers/w3c/ActionsTest.java +++ b/espresso-server/app/src/test/java/io/appium/espressoserver/test/helpers/w3c/ActionsTest.java @@ -17,7 +17,6 @@ import io.appium.espressoserver.test.assets.Helpers; import static io.appium.espressoserver.test.helpers.w3c.Helpers.assertFloatEquals; -import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertTrue; diff --git a/espresso-server/app/src/test/java/io/appium/espressoserver/test/model/DataMatcherJsonTest.kt b/espresso-server/app/src/test/java/io/appium/espressoserver/test/model/DataMatcherJsonTest.kt new file mode 100644 index 000000000..8abdb1df6 --- /dev/null +++ b/espresso-server/app/src/test/java/io/appium/espressoserver/test/model/DataMatcherJsonTest.kt @@ -0,0 +1,20 @@ +package io.appium.espressoserver.test.model + +import com.google.gson.Gson +import io.appium.espressoserver.lib.model.DataMatcherJson +import org.junit.Test +import kotlin.test.assertFalse +import kotlin.test.assertTrue + +class `DataMatcherJson Tests` { + val g = Gson(); + + @Test + fun `should parse data matchers`() { + val dataMatcher = g.fromJson("""{ + "name": "instanceOf", "args": "String.class" + }""".trimIndent(), DataMatcherJson::class.java) + assertTrue(dataMatcher.matcher.matches("A STRING")) + assertFalse(dataMatcher.matcher.matches(100)) + } +} \ No newline at end of file diff --git a/espresso-server/app/src/test/java/io/appium/espressoserver/test/model/HamcrestMatcherTest.kt b/espresso-server/app/src/test/java/io/appium/espressoserver/test/model/HamcrestMatcherTest.kt new file mode 100644 index 000000000..76d856449 --- /dev/null +++ b/espresso-server/app/src/test/java/io/appium/espressoserver/test/model/HamcrestMatcherTest.kt @@ -0,0 +1,112 @@ +package io.appium.espressoserver.test.model + +import androidx.test.espresso.matcher.CursorMatchers +import androidx.test.espresso.matcher.CursorMatchers.CursorMatcher +import com.google.gson.Gson +import com.google.gson.JsonParseException +import io.appium.espressoserver.lib.model.HamcrestMatcher +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertFalse +import kotlin.test.assertTrue + +class HamcrestMatcherTest { + val g = Gson(); + + @Test + fun `should parse Hamcrest matcher with single string arg`() { + val matcher = g.fromJson(""" + {"name": "containsString", "args": "Hello World!"} + """.trimIndent(), HamcrestMatcher::class.java) + assertEquals(matcher.name, "containsString") + assertTrue(matcher.args contentEquals arrayOf("Hello World!")) + } + + @Test + fun `should parse Hamcrest matcher with array of primitive args` () { + val matcher = g.fromJson(""" + {"name": "fakeMatcher", "args": [1, true, "Hello World!", null]} + """.trimIndent(), HamcrestMatcher::class.java) + assertEquals(matcher.name, "fakeMatcher") + val numberArg = matcher.args.get(0) + assertTrue(numberArg is Number) + assertEquals(numberArg.toInt(), 1) + assertEquals(matcher.args.get(1), true) + assertEquals(matcher.args.get(2), "Hello World!") + assertEquals(matcher.args.get(3), null) + } + + @Test + fun `should parse empty args` () { + val matcher = g.fromJson(""" + {"name": "isAThing"} + """.trimIndent(), HamcrestMatcher::class.java) + assertEquals(matcher.name, "isAThing") + assertTrue(matcher.args contentEquals emptyArray()) + } + + @Test + fun `should parse string as matcher with no args` () { + val matcher = g.fromJson("arglessMethod", HamcrestMatcher::class.java) + assertEquals(matcher.name, "arglessMethod") + assertTrue(matcher.args contentEquals emptyArray()) + } + + @Test + fun `should default the matcher class type to 'org_hamcrest_Matchers'` () { + val matcher = g.fromJson(""" + {"name": "containsString", "args": "Hello"} + """.trimIndent(), HamcrestMatcher::class.java) + assertEquals(matcher.matcherClass, org.hamcrest.Matchers::class) + val containsStringMatcher = matcher.invoke(); + assertTrue(containsStringMatcher.matches("Hello World")) + assertFalse(containsStringMatcher.matches("Goodbye World")) + } + + @Test + fun `should parse the matcher class type` () { + val matcher = g.fromJson(""" + {"name": "withRowBlob", "class": "androidx.test.espresso.matcher.CursorMatchers"} + """.trimIndent(), HamcrestMatcher::class.java) + assertEquals(matcher.matcherClass, CursorMatchers::class) + } + + @Test + fun `should use 'androidx_test_espresso_matcher' when class provided but package not provided` () { + val matcher = g.fromJson(""" + {"name": "withRowDouble", "args": ["Hello", 2.0], "class": "CursorMatchers"} + """.trimIndent(), HamcrestMatcher::class.java) + assertEquals(matcher.matcherClass, CursorMatchers::class) + assertTrue(matcher.invoke() is CursorMatcher) + } + + @Test + fun `should parse matchers that have Class as an arg` () { + val matcher = g.fromJson(""" + {"name": "instanceOf", "args": "String.class"} + """.trimIndent(), HamcrestMatcher::class.java) + assertTrue(matcher.invoke().matches("Hello World")) + assertFalse(matcher.invoke().matches(123)) + } + + @Test + fun `should parse nested Hamcrest matchers` () { + val matcher = g.fromJson(""" + {"name": "anyOf", "args": [ + {"name": "containsString", "args": "Hello"}, + {"name": "instanceOf", "args": "Integer"} + ]}""".trimIndent(), HamcrestMatcher::class.java) + val nestedMatcher = matcher.invoke(); + assertTrue(nestedMatcher.matches("Hello")) + assertTrue(nestedMatcher.matches(100)) + assertFalse(nestedMatcher.matches("World")) + assertFalse(nestedMatcher.matches(100.1)) + } + + @Test(expected = JsonParseException::class) + fun `should fail if name not provided` () { + g.fromJson(""" + {"args": "Hello World!"} + """.trimIndent(), HamcrestMatcher::class.java) + } +} \ No newline at end of file diff --git a/espresso-server/app/src/test/java/io/appium/espressoserver/test/model/MobileBackdoorMethodTest.java b/espresso-server/app/src/test/java/io/appium/espressoserver/test/model/MobileBackdoorMethodTest.java index f344da099..ffe3f47e1 100644 --- a/espresso-server/app/src/test/java/io/appium/espressoserver/test/model/MobileBackdoorMethodTest.java +++ b/espresso-server/app/src/test/java/io/appium/espressoserver/test/model/MobileBackdoorMethodTest.java @@ -15,7 +15,9 @@ import static io.appium.espressoserver.lib.model.MobileBackdoorParams.InvocationTarget.ACTIVITY; import static junit.framework.Assert.fail; -import static org.junit.Assert.*; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; public class MobileBackdoorMethodTest { diff --git a/espresso-server/app/src/test/java/io/appium/espressoserver/test/model/MobileClickTest.kt b/espresso-server/app/src/test/java/io/appium/espressoserver/test/model/MobileClickTest.kt index c3bfe2116..6e239dea9 100644 --- a/espresso-server/app/src/test/java/io/appium/espressoserver/test/model/MobileClickTest.kt +++ b/espresso-server/app/src/test/java/io/appium/espressoserver/test/model/MobileClickTest.kt @@ -2,7 +2,8 @@ package io.appium.espressoserver.test.model import androidx.test.espresso.action.GeneralLocation.TOP_RIGHT import androidx.test.espresso.action.GeneralLocation.VISIBLE_CENTER -import androidx.test.espresso.action.Press.* +import androidx.test.espresso.action.Press.FINGER +import androidx.test.espresso.action.Press.PINPOINT import androidx.test.espresso.action.Tap.DOUBLE import androidx.test.espresso.action.Tap.SINGLE import com.google.gson.JsonObject diff --git a/espresso-server/app/src/test/java/io/appium/espressoserver/test/model/web/WebAtomTest.kt b/espresso-server/app/src/test/java/io/appium/espressoserver/test/model/web/WebAtomTest.kt index d8c078472..64f0a8f69 100644 --- a/espresso-server/app/src/test/java/io/appium/espressoserver/test/model/web/WebAtomTest.kt +++ b/espresso-server/app/src/test/java/io/appium/espressoserver/test/model/web/WebAtomTest.kt @@ -6,6 +6,7 @@ import com.google.gson.JsonPrimitive import io.appium.espressoserver.lib.model.web.WebAtom import org.junit.Test import kotlin.test.assertEquals +import kotlin.test.assertTrue class WebAtomTest { @@ -47,7 +48,7 @@ class WebAtomTest { jsonObject.add("args", argsArr) val webAtom = WebAtom.WebAtomDeserializer().deserialize(jsonObject, null, null) assertEquals(webAtom.name, "someFakeAtom") - assertEquals(webAtom.args, arrayListOf("hello", true, 100, 1.1)) + assertTrue(webAtom.args contentEquals arrayOf("hello", true, 100L, 1.1)) assertEquals(webAtom.args.size, 4); } @@ -61,8 +62,6 @@ class WebAtomTest { jsonObject.add("locator", locatorObject); val webAtom = WebAtom.WebAtomDeserializer().deserialize(jsonObject, null, null) assertEquals(webAtom.name, "findElement") - assertEquals(webAtom.args.get(0), "id") - assertEquals(webAtom.args.get(1), "some_html_id") - assertEquals(webAtom.args.size, 2) + assertTrue(webAtom.args contentEquals arrayOf("id", "some_html_id")) } } diff --git a/espresso-server/app/src/test/java/io/appium/espressoserver/test/model/web/WebAtomsTest.kt b/espresso-server/app/src/test/java/io/appium/espressoserver/test/model/web/WebAtomsTest.kt index 25fa911d6..5516c1893 100644 --- a/espresso-server/app/src/test/java/io/appium/espressoserver/test/model/web/WebAtomsTest.kt +++ b/espresso-server/app/src/test/java/io/appium/espressoserver/test/model/web/WebAtomsTest.kt @@ -5,6 +5,7 @@ import io.appium.espressoserver.lib.model.web.WebAtomsParams import io.appium.espressoserver.lib.model.web.WebAtomsParams.WebAtomsMethod import org.junit.Test import kotlin.test.assertEquals +import kotlin.test.assertTrue class WebAtomsTest { val g = Gson() @@ -22,7 +23,7 @@ class WebAtomsTest { }""".trimIndent(), WebAtomsMethod::class.java) assertEquals(webAtomsMethod.name, "withElement"); assertEquals(webAtomsMethod.atom.name, "findElement"); - assertEquals(webAtomsMethod.atom.args, arrayListOf("id", "text_input")); + assertTrue(webAtomsMethod.atom.args contentEquals arrayOf("id", "text_input")); } @Test @@ -61,19 +62,19 @@ class WebAtomsTest { webAtoms.methodChain.get(0).let { assertEquals(it.name, "withElement") assertEquals(it.atom.name, "findElement") - assertEquals(it.atom.args, arrayListOf("id", "text_input")) + assertTrue(it.atom.args contentEquals arrayOf("id", "text_input")) } webAtoms.methodChain.get(1).let { assertEquals(it.name, "perform") assertEquals(it.atom.name, "clearElement") - assertEquals(it.atom.args, emptyList()) + assertTrue(it.atom.args contentEquals emptyArray()) } webAtoms.methodChain.get(2).let { assertEquals(it.name, "perform") assertEquals(it.atom.name, "webKeys") - assertEquals(it.atom.args, arrayListOf("Foo")) + assertTrue(it.atom.args contentEquals arrayOf("Foo")) } } diff --git a/package.json b/package.json index b8bf6c43a..e54836b8f 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ "coverage": "gulp coveralls", "prepare": "gulp prepublish && npm run build:server", "precommit-msg": "echo 'Pre-commit checks...' && exit 0", - "precommit-test": "REPORTER=dot gulp once", + "precommit-test": "REPORTER=dot gulp once && npm run test:server", "lint": "gulp eslint", "lint:fix": "gulp eslint --fix" }, diff --git a/test/functional/commands/find-e2e-specs.js b/test/functional/commands/find-e2e-specs.js index aa44195a7..72326f338 100644 --- a/test/functional/commands/find-e2e-specs.js +++ b/test/functional/commands/find-e2e-specs.js @@ -8,7 +8,7 @@ import { APIDEMO_CAPS } from '../desired'; chai.should(); chai.use(chaiAsPromised); -describe('elementByXPath', function () { +describe('find elements', function () { this.timeout(MOCHA_TIMEOUT); let driver; @@ -18,64 +18,127 @@ describe('elementByXPath', function () { after(async function () { await deleteSession(); }); - it(`should find an element by it's xpath`, async function () { - let el = await driver.elementByXPath("//*[@text='Animation']"); - el.should.exist; - await el.click(); - await driver.back(); - }); - it('should find multiple elements that match one xpath', async function () { - let els = await driver.elementsByXPath('//android.widget.TextView'); - els.length.should.be.above(1); - await els[0].click(); - await driver.back(); - }); - it('should get the first element of an xpath that matches more than one element', async function () { - let el = await driver.elementByXPath('//android.widget.TextView'); - el.should.exist; - await el.click(); - await driver.back(); - }); - it('should throw a stale element exception if clicking on element that does not exist', async function () { - let el = await driver.elementByXPath("//*[@content-desc='Animation']"); - await el.click(); - await retryInterval(5, 1000, async () => await el.click().should.eventually.be.rejectedWith(/no longer exists /)); - await driver.back(); - }); - it('should get the isDisplayed attribute on the same element twice', async function () { - let el = await driver.elementByXPath("//*[@content-desc='Animation']"); - await el.isDisplayed().should.eventually.be.true; - await el.isDisplayed().should.eventually.be.true; - await el.click(); - await driver.back(); - }); - it('should match an element if the element is off-screen but has an accessibility id', async function () { - let el = await driver.elementByAccessibilityId('Views'); - await el.click(); + describe('elementByXPath', function () { + it(`should find an element by it's xpath`, async function () { + let el = await driver.elementByXPath("//*[@text='Animation']"); + el.should.exist; + await el.click(); + await driver.back(); + }); + it('should find multiple elements that match one xpath', async function () { + let els = await driver.elementsByXPath('//android.widget.TextView'); + els.length.should.be.above(1); + await els[0].click(); + await driver.back(); + }); + it('should get the first element of an xpath that matches more than one element', async function () { + let el = await driver.elementByXPath('//android.widget.TextView'); + el.should.exist; + await el.click(); + await driver.back(); + }); + it('should throw a stale element exception if clicking on element that does not exist', async function () { + let el = await driver.elementByXPath("//*[@content-desc='Animation']"); + await el.click(); + await retryInterval(5, 1000, async () => await el.click().should.eventually.be.rejectedWith(/no longer exists /)); + await driver.back(); + }); + it('should get the isDisplayed attribute on the same element twice', async function () { + let el = await driver.elementByXPath("//*[@content-desc='Animation']"); + await el.isDisplayed().should.eventually.be.true; + await el.isDisplayed().should.eventually.be.true; + await el.click(); + await driver.back(); + }); + it('should match an element if the element is off-screen but has an accessibility id', async function () { + let el = await driver.elementByAccessibilityId('Views'); + await el.click(); - // Click on an element that is at the bottom of the list - let moveToEl = await driver.elementByAccessibilityId('WebView'); - await moveToEl.click(); - await driver.back(); - await driver.back(); + // Click on an element that is at the bottom of the list + let moveToEl = await driver.elementByAccessibilityId('WebView'); + await moveToEl.click(); + await driver.back(); + await driver.back(); + }); + it('should test element equality', async function () { + let el = await driver.elementByAccessibilityId('Views'); + let elAgain = await driver.elementByXPath("//*[@content-desc='Views']"); + let elNonMatch = await driver.elementByAccessibilityId('Preference'); + await el.equals(elAgain).should.eventually.be.true; + await el.equals(elNonMatch).should.eventually.be.false; + }); + // TODO: This test is very flakey. Need to inspect this. + it.skip('should scroll element back into view if was scrolled out of view (regression test for https://github.com/appium/appium-espresso-driver/issues/276)', async function () { + // If we find an element by 'contentDescription', scroll out of view of that element, we should be able to scroll it back into view, as long + // as that element has a content description associated with an adapter item + let el = await driver.elementByAccessibilityId('Views'); + await el.click(); + el = await driver.elementByAccessibilityId('Custom'); + await el.text().should.eventually.equal('Custom'); + let {value: element} = await driver.elementById('android:id/list'); + await driver.execute('mobile: swipe', {direction: 'up', element}); + await el.text().should.eventually.equal('Custom'); + await driver.back(); + }); }); - it('should test element equality', async function () { - let el = await driver.elementByAccessibilityId('Views'); - let elAgain = await driver.elementByXPath("//*[@content-desc='Views']"); - let elNonMatch = await driver.elementByAccessibilityId('Preference'); - await el.equals(elAgain).should.eventually.be.true; - await el.equals(elNonMatch).should.eventually.be.false; - }); - it('should scroll element back into view if was scrolled out of view (regression test for https://github.com/appium/appium-espresso-driver/issues/276)', async function () { - // If we find an element by 'contentDescription', scroll out of view of that element, we should be able to scroll it back into view, as long - // as that element has a content description associated with an adapter item - let el = await driver.elementByAccessibilityId('Views'); - await el.click(); - el = await driver.elementByAccessibilityId('Custom'); - await el.text().should.eventually.equal('Custom'); - let {value: element} = await driver.elementById('android:id/list'); - await driver.execute('mobile: swipe', {direction: 'up', element}); - await el.text().should.eventually.equal('Custom'); - await driver.back(); + + describe('by data matcher', function () { + it('should find an element using a data matcher', async function () { + let el = await driver.element('-android datamatcher', JSON.stringify({ + name: 'hasEntry', args: ['title', 'Animation'] + })); + await el.click(); + await driver.elementByAccessibilityId('Bouncing Balls').should.eventually.exist; + await driver.back(); + }); + it('should find an offscreen element using a data matcher', async function () { + let viewsEl = await driver.elementByAccessibilityId('Views'); + await viewsEl.click(); + let el = await driver.element('-android datamatcher', JSON.stringify({ + name: 'hasEntry', args: ['title', 'WebView3'] + })); + await el.click(); + await driver.back(); + await driver.elementByAccessibilityId('Controls').should.eventually.exist; + await driver.back(); + }); + it('should fail to find elements with helpful error messages', async function () { + await driver.element('-android datamatcher', JSON.stringify({ + name: 'hasEntry', args: ['title', 'A Fake Item'] + })).should.eventually.be.rejectedWith(/NoSuchElement/); + }); + it('should fail with invalid selector with helpful error messages', async function () { + await driver.element('-android datamatcher', JSON.stringify({ + name: 'notARealHamcrestMatcherStrategy', args: ['title', 'A Fake Item'] + })).should.eventually.be.rejectedWith(/InvalidSelector/); + }); + it('should allow "class" property with fully qualified className', async function () { + await driver.element('-android datamatcher', JSON.stringify({ + name: 'notARealHamcrestMatcherStrategy', args: ['title', 'A Fake Item'], class: 'org.hamcrest.Matchers', + })).should.eventually.be.rejectedWith(/InvalidSelector/); + }); + it('should be able to set a specific AdapterView as a root element when activity has multiple AdapterViews', async function () { + const viewsEl = await driver.elementByAccessibilityId('Views'); + await viewsEl.click(); + const splittingEl = await driver.elementByAccessibilityId('Splitting Touches across Views'); + await splittingEl.click(); + + // Finding by adapter equalTo 'Zamorano' should be ambiguous, because there are two + // adapter items with the same matcher + await driver.element('-android datamatcher', JSON.stringify({ + name: 'equalTo', args: 'Zamorano' + })).should.eventually.be.rejectedWith(/AmbiguousViewMatcherException/); + + // Narrow them down by making the root an adapter view + const listOneEl = await driver.elementById('list1'); + await listOneEl.element('-android datamatcher', JSON.stringify({ + name: 'equalTo', args: 'Zamorano' + })).should.eventually.exist; + + const listTwoEl = await driver.elementById('list2'); + await listTwoEl.element('-android datamatcher', JSON.stringify({ + name: 'equalTo', args: 'Zamorano' + })).should.eventually.exist; + }); }); -}); +}); \ No newline at end of file