diff --git a/detox/android/detox/src/full/java/com/wix/detox/espresso/EspressoDetox.java b/detox/android/detox/src/full/java/com/wix/detox/espresso/EspressoDetox.java index 6e41bf98e8..fd21977c08 100644 --- a/detox/android/detox/src/full/java/com/wix/detox/espresso/EspressoDetox.java +++ b/detox/android/detox/src/full/java/com/wix/detox/espresso/EspressoDetox.java @@ -21,12 +21,11 @@ import androidx.test.espresso.UiController; import androidx.test.espresso.ViewAction; -import androidx.test.espresso.ViewInteraction; -import androidx.test.espresso.NoMatchingViewException; import androidx.test.platform.app.InstrumentationRegistry; import static androidx.test.espresso.Espresso.onView; import static androidx.test.espresso.matcher.ViewMatchers.isRoot; +import static com.wix.detox.espresso.UiAutomatorHelper.getStatusBarHeightDps; /** * Created by rotemm on 26/12/2016. @@ -34,6 +33,10 @@ public class EspressoDetox { private static final String LOG_TAG = "detox"; + private static int calculateAdjustedY(View view, Integer y, boolean shouldIgnoreStatusBar) { + return shouldIgnoreStatusBar ? y + getStatusBarHeightDps(view) : y; + } + public static Object perform(Matcher matcher, ViewAction action) { ViewActionPerformer performer = ViewActionPerformer.forAction(action); return performer.performOn(matcher); @@ -136,7 +139,7 @@ public String getDescription() { @Override public void perform(UiController uiController, View view) { - int adjustedY = shouldIgnoreStatusBar ? y + UiAutomatorHelper.getStatusBarHeight(view) : y; + int adjustedY = calculateAdjustedY(view, y, shouldIgnoreStatusBar); ViewAction action = DetoxAction.tapAtLocation(x, adjustedY); action.perform(uiController, view); uiController.loopMainThreadUntilIdle(); @@ -162,7 +165,7 @@ public String getDescription() { @Override public void perform(UiController uiController, View view) { - int adjustedY = shouldIgnoreStatusBar ? y + UiAutomatorHelper.getStatusBarHeight(view) : y; + int adjustedY = calculateAdjustedY(view, y, shouldIgnoreStatusBar); ViewAction action = DetoxAction.longPress(x, adjustedY, duration); action.perform(uiController, view); uiController.loopMainThreadUntilIdle(); diff --git a/detox/android/detox/src/full/java/com/wix/detox/espresso/UiAutomatorHelper.java b/detox/android/detox/src/full/java/com/wix/detox/espresso/UiAutomatorHelper.java index 9b3e55a63f..e82be14e4e 100644 --- a/detox/android/detox/src/full/java/com/wix/detox/espresso/UiAutomatorHelper.java +++ b/detox/android/detox/src/full/java/com/wix/detox/espresso/UiAutomatorHelper.java @@ -117,7 +117,7 @@ public void doFrame(long frameTimeNanos) { } @SuppressLint({"DiscouragedApi", "InternalInsetResource"}) - public static int getStatusBarHeight(View view) { + public static int getStatusBarHeightDps(View view) { Context context = view.getContext(); int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android"); return (int) (context.getResources().getDimensionPixelSize(resourceId) / ((float) context.getResources().getDisplayMetrics().densityDpi / DisplayMetrics.DENSITY_DEFAULT)); diff --git a/detox/android/detox/src/full/java/com/wix/detox/espresso/matcher/IsDisplayingAtLeastDetoxMatcher.kt b/detox/android/detox/src/full/java/com/wix/detox/espresso/matcher/IsDisplayingAtLeastDetoxMatcher.kt index 44da10cac6..b34410b9b8 100644 --- a/detox/android/detox/src/full/java/com/wix/detox/espresso/matcher/IsDisplayingAtLeastDetoxMatcher.kt +++ b/detox/android/detox/src/full/java/com/wix/detox/espresso/matcher/IsDisplayingAtLeastDetoxMatcher.kt @@ -120,7 +120,7 @@ class IsDisplayingAtLeastDetoxMatcher(private val areaPercentage: Int) : TypeSaf .defaultDisplay .getMetrics(m) - val statusBarHeight = getStatusBarHeight(view) + val statusBarHeight = getStatusBarHeightPixels(view) val actionBarHeight = getActionBarHeight(view) return Rect(0, 0, m.widthPixels, m.heightPixels - (statusBarHeight + actionBarHeight)) } @@ -138,7 +138,7 @@ class IsDisplayingAtLeastDetoxMatcher(private val areaPercentage: Int) : TypeSaf } @SuppressLint("InternalInsetResource", "DiscouragedApi") - private fun getStatusBarHeight(view: View): Int { + private fun getStatusBarHeightPixels(view: View): Int { val resourceId = view.context.resources.getIdentifier("status_bar_height", "dimen", "android") return if (resourceId > 0) view.context.resources.getDimensionPixelSize(resourceId) else 0 } diff --git a/detox/ios/DetoxXCUITestRunner/DetoxXCUITestRunner/Handlers/ActionHandler.swift b/detox/ios/DetoxXCUITestRunner/DetoxXCUITestRunner/Handlers/ActionHandler.swift index 97a9d6b80a..86f07a587a 100644 --- a/detox/ios/DetoxXCUITestRunner/DetoxXCUITestRunner/Handlers/ActionHandler.swift +++ b/detox/ios/DetoxXCUITestRunner/DetoxXCUITestRunner/Handlers/ActionHandler.swift @@ -7,36 +7,31 @@ import Foundation import XCTest class ActionHandler { - - func findElement(from params: InvocationParams, predicateHandler: PredicateHandler) -> XCUIElement { - - let element = predicateHandler.findElement(using: params) - let exists = element.waitForExistence(timeout: .defaultTimeout) - DTXAssert( - exists, - "Action failed, element with matcher `\(params.matcherDescription)` does not exist" - ) - return element; - } + func findElement(from params: InvocationParams, predicateHandler: PredicateHandler) -> XCUIElement { + let element = predicateHandler.findElement(using: params) + let exists = element.waitForExistence(timeout: .defaultTimeout) + DTXAssert( + exists, + "Action failed, element with matcher `\(params.matcherDescription)` does not exist" + ) + return element + } + + func getNormalizedCoordinate(from params: InvocationParams) throws -> XCUICoordinate { + let x = Int(params.params?.first ?? "100") ?? 100 + let y = Int(params.params?[1] ?? "100") ?? 100 - func getNormalizedCoordinate(from params: InvocationParams) throws -> XCUICoordinate { - do { - guard let x = Int(params.params?.first ?? "100"), let y = Int(params.params?[1] ?? "100") else { - throw Error.missingTypeTextParam - } - - let screenFrame = try XCUIApplication.appUnderTest().frame - let normalizedX = CGFloat(x) / screenFrame.width - let normalizedY = CGFloat(y) / screenFrame.height - let normalizedPoint = CGVector(dx: normalizedX, dy: normalizedY) - let coordinate = try XCUIApplication.appUnderTest().coordinate(withNormalizedOffset: normalizedPoint) - - return coordinate; - } catch { - throw Error.failedToTapDeviceByCoordinates - } - } + let appUnderTest = try XCUIApplication.appUnderTest() + let screenFrame = appUnderTest.frame + let normalizedX = CGFloat(x) / screenFrame.width + let normalizedY = CGFloat(y) / screenFrame.height + let normalizedPoint = CGVector(dx: normalizedX, dy: normalizedY) + let coordinate = appUnderTest.coordinate( + withNormalizedOffset: normalizedPoint) + + return coordinate + } func handle(from params: InvocationParams, predicateHandler: PredicateHandler) throws { diff --git a/docs/api/device.md b/docs/api/device.md index 4e515fb29e..a5bf643d0d 100644 --- a/docs/api/device.md +++ b/docs/api/device.md @@ -422,10 +422,8 @@ Perform a tap at arbitrary coordinates on the device's screen. #### tap parameters -| parameter | platform | description | default value -| -------- | ------- | ------- | ------- | -| point | Android & IOS | Coordinates in the element's coordinate space | `{x: 100, y: 100}` -| shouldIgnoreStatusBar | Android | Coordinates will be measured starting from under the status bar. | `true` +- `point` — Coordinates in the element's coordinate space (default value: `{x: 100, y: 100}`, platforms: Android & IOS)
+- `shouldIgnoreStatusBar` — Coordinates will be measured starting from under the status bar (default value: `true`, platform: Android)
#### tap examples @@ -444,11 +442,9 @@ Perform a long press at arbitrary coordinates on the device's screen. Custom pre #### longPress parameters -| parameter | platform | description | default value -| -------- | ------- | ------- | ------- | -| point | Android & IOS | Coordinates in the element's coordinate space | `{x: 100, y: 100}` -| duration | Android & IOS | Custom press duration time, in milliseconds. | Android: Standard long-press duration. IOS: 1000 milliseconds. -| shouldIgnoreStatusBar | Android | Coordinates will be measured starting from under the status bar. | `true` +- `point` — Coordinates in the element's coordinate space (default value: `{x: 100, y: 100}`, platforms: Android & IOS)
+- `duration` — Custom press duration time, in milliseconds. (default values: Android: Standard long-press duration. IOS: 1000 milliseconds, platforms: Android & IOS)
+- `shouldIgnoreStatusBar` — Coordinates will be measured starting from under the status bar (default value: `true`, platform: Android)
#### longPress examples