-
Notifications
You must be signed in to change notification settings - Fork 1.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: add device.tap()
and device.longPress()
.
#4542
base: master
Are you sure you want to change the base?
Conversation
…eat/device-tap
…eat/device-tap-ios
…eat/device-tap
…eat/device-tap-ios
device.tap()
and device.longPress()
.
Unit test failed due to code coverage issues.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Relatively small comments compared to this massive, impressive, awesome work. This is REALLY great work, @gayablau. 100 / 100! 🫡 We are close!
|
||
@Override | ||
public void perform(UiController uiController, View view) { | ||
int adjustedY = shouldIgnoreStatusBar ? y + UiAutomatorHelper.getStatusBarHeight(view) : y; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let's extract that to private method that will be shared with the longPress
's perform (reuse & separation of concerns) → e.g. calculateAdjustedY(y, shouldIgnoreStatusBar)
or something similar.
@SuppressLint({"DiscouragedApi", "InternalInsetResource"}) | ||
public static int getStatusBarHeight(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)); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just to avoid confusion, could you please exctrat the method with the same name from isDisplayingAtLeastDetoxMatcher
to this file? They perform a similar task but return coordinates in different units (px vs dp), so I would suggest creating two distinct method names to differentiate them:
getStatusBarHeightPixels
getStatusBarHeightDps
Lines 140 to 144 in 8fc7c6e
@SuppressLint("InternalInsetResource", "DiscouragedApi") | |
private fun getStatusBarHeight(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 | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just a scout rule that'll make the code cleaner 🙏
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I changed the names, do you mean to move one of the functions?
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; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please reindent
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) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let's avoid repeated calls to XCUIApplication.appUnderTest()
by storing it in a variable
} catch { | ||
throw Error.failedToTapDeviceByCoordinates | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you're going to throw this error anyway if you catch anything (Error.failedToTapDeviceByCoordinates
) since you already wrapped this method with try-catch on the switch-case (on handle
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You may avoid the try-catch here and just let it be caught by the caller, or remove the duplicated try-catch from the caller(s).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not even sure if we need any of these catches since they might hide other errors that are more specific. Please revisit the error throwing logic.
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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you're throwing this error but catching it and hiding it (with failedToTapDeviceByCoordinates
, see below).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also this is not the right error to throw, you might want to make this error more generic by introducing params to it, e.g. missingParam(paramName, paramType)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I removed the error because we want to allow this case, I just need the fallback
docs/api/device.md
Outdated
### `device.tap(point, shouldIgnoreStatusBar)` | ||
|
||
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` | ||
|
||
#### tap examples |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is going to be nitpicky and that's an nice structure, but we usually describe the parameters within bullet points and then just put examples without the headlines. For example: https://wix.github.io/Detox/docs/api/actions#swipedirection-speed-normalizedoffset-normalizedstartingpointx-normalizedstartingpointy
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
Description
In this pull request, I have added api for device tap and long press for android and IOS
fixed review comments in #4534