Skip to content

Commit

Permalink
Merge pull request #2053 from leancodepl/feature/native_tap_at
Browse files Browse the repository at this point in the history
Feature/native tap at coordinates
  • Loading branch information
MatejLNCD authored Jan 17, 2024
2 parents 4ae9b3d + 2c12384 commit 9e1c1e2
Show file tree
Hide file tree
Showing 19 changed files with 223 additions and 29 deletions.
25 changes: 25 additions & 0 deletions dev/e2e_app/integration_test/tap_at_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import 'dart:io' show Platform;

import 'common.dart';

void main() {
final String appId;
if (Platform.isIOS) {
appId = 'com.apple.Preferences';
} else if (Platform.isAndroid) {
appId = 'com.android.settings';
} else {
throw UnsupportedError('Unsupported platform');
}

patrol('taps at the lower middle of the screen in the Settings app',
($) async {
await createApp($);

await $.native.openApp(appId: appId);
await $.native.tapAt(
Offset(0.5, 0.8),
appId: appId,
);
});
}
50 changes: 26 additions & 24 deletions docs/native/feature-parity.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -10,37 +10,38 @@ implemented. We hope that it will help you evaluate Patrol.
We strive for high feature parity across iOS and Android, but in some cases it's
impossible to reach 100%. macOs support is still in alpha, so it has no native features yet.


### Table

| **Feature** | **Android** | **iOS** | **macOS (alpha)** |
| --------------------------- | -------------- | ------------- | ----------------- |
| [Press home] ||||
| [Press back] || ❌ (no API) ||
| [Open any app] ||||
| [Open notifications] ||||
| [Tap on notification] ||||
| [Open quick settings] ||||
| [Toggle dark mode] ||||
| [Toggle airplane mode] | ✅ see [#1359] |||
| [Toggle cellular] ||||
| [Toggle Wi-Fi] ||||
| [Toggle Bluetooth] | ✅ see [#282] |||
| Toggle location | ✅ see [#283] | ✅ see [#326] ||
| [Tap] ||||
| [Double tap] ||||
| [Enter text] ||||
| [Swipe] ||||
| [Handle permission dialogs] ||||
| Interact with WebView | ⚠️ see [#244] |||
| [Press home] ||||
| [Press back] || ❌ (no API) ||
| [Open any app] ||||
| [Open notifications] ||||
| [Tap on notification] ||||
| [Open quick settings] ||||
| [Toggle dark mode] ||||
| [Toggle airplane mode] | ✅ see [#1359] |||
| [Toggle cellular] ||||
| [Toggle Wi-Fi] ||||
| [Toggle Bluetooth] | ✅ see [#282] |||
| Toggle location | ✅ see [#283] | ✅ see [#326] ||
| [Tap] ||||
| [Double tap] ||||
| [Tap at coordinate] ||||
| [Enter text] ||||
| [Swipe] ||||
| [Handle permission dialogs] ||||
| Interact with WebView | ⚠️ see [#244] |||

### Platfom support

Patrol works on:
- Android 5.0 (API 21) and newer,
- iOS 11 and newer,
- macOS 10.14 and newer.


- Android 5.0 (API 21) and newer,
- iOS 11 and newer,
- macOS 10.14 and newer.

On mobile platforms it works on both physical and virtual devices.

[#244]: https://github.com/leancodepl/patrol/issues/244
Expand All @@ -61,6 +62,7 @@ On mobile platforms it works on both physical and virtual devices.
[toggle bluetooth]: https://pub.dev/documentation/patrol/latest/patrol/NativeAutomator/enableBluetooth.html
[tap]: https://pub.dev/documentation/patrol/latest/patrol/NativeAutomator/tap.html
[double tap]: https://pub.dev/documentation/patrol/latest/patrol/NativeAutomator/doubleTap.html
[tap at coordinate]: https://pub.dev/documentation/patrol/latest/patrol/NativeAutomator/tapAt.html
[enter text]: https://pub.dev/documentation/patrol/latest/patrol/NativeAutomator/enterText.html
[enter text]: https://pub.dev/documentation/patrol/latest/patrol/NativeAutomator/swipe.html
[swipe]: https://pub.dev/documentation/patrol/latest/patrol/NativeAutomator/swipe.html
[handle permission dialogs]: https://pub.dev/documentation/patrol/latest/patrol/NativeAutomator/grantPermissionWhenInUse.html
1 change: 1 addition & 0 deletions packages/patrol/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
## Unreleased

- Add optional timeout parameter to native methods (#2042).
- Add `$.native.tapAt()` (#2053)

## 3.4.0

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,31 @@ class Automator private constructor() {
delay()
}

fun tapAt(x: Float, y: Float) {
Logger.d("tapAt(x: $x, y: $y)")

if (x !in 0f..1f) {
throw IllegalArgumentException("x represents a percentage and must be between 0 and 1")
}

if (y !in 0f..1f) {
throw IllegalArgumentException("y represents a percentage and must be between 0 and 1")
}

val displayX = (uiDevice.displayWidth * x).roundToInt()
val displayY = (uiDevice.displayHeight * y).roundToInt()

Logger.d("Clicking at display location (pixels) [$displayX, $displayY]")

val successful = uiDevice.click(displayX, displayY)

if (!successful) {
throw IllegalArgumentException("Clicking at location [$displayX, $displayY] failed")
}

delay()
}

fun enterText(text: String, index: Int, keyboardBehavior: KeyboardBehavior, timeout: Long? = null) {
Logger.d("enterText(text: $text, index: $index)")

Expand Down Expand Up @@ -263,6 +288,7 @@ class Automator private constructor() {
val eY = (uiDevice.displayHeight * endY).roundToInt()

val successful = uiDevice.swipe(sX, sY, eX, eY, steps)

if (!successful) {
throw IllegalArgumentException("Swipe failed")
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package pl.leancode.patrol

import pl.leancode.patrol.contracts.Contracts
import pl.leancode.patrol.contracts.Contracts.ConfigureRequest
import pl.leancode.patrol.contracts.Contracts.DarkModeRequest
import pl.leancode.patrol.contracts.Contracts.EnterTextRequest
Expand Down Expand Up @@ -144,6 +145,13 @@ class AutomatorServer(private val automation: Automator) : NativeAutomatorServer
)
}

override fun tapAt(request: Contracts.TapAtRequest) {
automation.tapAt(
x = request.x.toFloat(),
y = request.y.toFloat()
)
}

override fun enterText(request: EnterTextRequest) {
if (request.index != null) {
automation.enterText(
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
inApp bundleId: String,
withTimeout timeout: TimeInterval?
) throws
func tapAt(coordinate vector: CGVector, inApp bundleId: String) throws
func enterText(
_ data: String,
byText text: String,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,16 @@
}
}

func tapAt(coordinate vector: CGVector, inApp bundleId: String) throws {
try runAction("tapping at coordinate \(vector) in app \(bundleId)") {
let app = try self.getApp(withBundleId: bundleId)

let coordinate = app.coordinate(withNormalizedOffset: vector)

coordinate.tap()
}
}

func enterText(
_ data: String,
byText text: String,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,12 @@
}
}

func tapAt(coordinate vector: CGVector, inApp bundleId: String) throws {
try runAction("tapAt") {
throw PatrolError.methodNotImplemented("tapAt")
}
}

func enterText(
_ data: String,
byText text: String,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,15 @@
}
}

func tapAt(request: TapAtRequest) throws {
return try runCatching {
try automator.tapAt(
coordinate: CGVector(dx: request.x, dy: request.y),
inApp: request.appId
)
}
}

func enterText(request: EnterTextRequest) throws {
return try runCatching {
if let index = request.index {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,12 @@ struct TapRequest: Codable {
var timeoutMillis: Int?
}

struct TapAtRequest: Codable {
var x: Double
var y: Double
var appId: String
}

struct EnterTextRequest: Codable {
var data: String
var appId: String
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ protocol NativeAutomatorServer {
func getNativeViews(request: GetNativeViewsRequest) throws -> GetNativeViewsResponse
func tap(request: TapRequest) throws
func doubleTap(request: TapRequest) throws
func tapAt(request: TapAtRequest) throws
func enterText(request: EnterTextRequest) throws
func swipe(request: SwipeRequest) throws
func waitUntilVisible(request: WaitUntilVisibleRequest) throws
Expand Down Expand Up @@ -113,6 +114,12 @@ extension NativeAutomatorServer {
return HTTPResponse(.ok)
}

private func tapAtHandler(request: HTTPRequest) throws -> HTTPResponse {
let requestArg = try JSONDecoder().decode(TapAtRequest.self, from: request.body)
try tapAt(request: requestArg)
return HTTPResponse(.ok)
}

private func enterTextHandler(request: HTTPRequest) throws -> HTTPResponse {
let requestArg = try JSONDecoder().decode(EnterTextRequest.self, from: request.body)
try enterText(request: requestArg)
Expand Down Expand Up @@ -303,6 +310,11 @@ extension NativeAutomatorServer {
request: request,
handler: doubleTapHandler)
}
server.route(.POST, "tapAt") {
request in handleRequest(
request: request,
handler: tapAtHandler)
}
server.route(.POST, "enterText") {
request in handleRequest(
request: request,
Expand Down
10 changes: 5 additions & 5 deletions packages/patrol/example/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@ PODS:
- Firebase/Messaging (10.18.0):
- Firebase/CoreOnly
- FirebaseMessaging (~> 10.18.0)
- firebase_auth (4.15.3):
- firebase_auth (4.16.0):
- Firebase/Auth (= 10.18.0)
- firebase_core
- Flutter
- firebase_core (2.24.2):
- Firebase/CoreOnly (= 10.18.0)
- Flutter
- firebase_messaging (14.7.9):
- firebase_messaging (14.7.10):
- Firebase/Messaging (= 10.18.0)
- firebase_core
- Flutter
Expand Down Expand Up @@ -170,9 +170,9 @@ SPEC CHECKSUMS:
AppAuth: 3bb1d1cd9340bd09f5ed189fb00b1cc28e1e8570
CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99
Firebase: 414ad272f8d02dfbf12662a9d43f4bba9bec2a06
firebase_auth: df44e14f8a93e8a9869d91695bd3f8e53d2c9f5a
firebase_auth: 8e9ec02991ca4659111cc671c84d0c010b6bfb26
firebase_core: 0af4a2b24f62071f9bf283691c0ee41556dcb3f5
firebase_messaging: 875385354f623750aa03204a028d640108bc3412
firebase_messaging: 90e8a6db84b6e1e876cebce4f30f01dc495e7014
FirebaseAppCheckInterop: 3cd914842ba46f4304050874cd284de82f154ffd
FirebaseAuth: 12314b438fa76048540c8fb86d6cfc9e08595176
FirebaseCore: 2322423314d92f946219c8791674d2f3345b598f
Expand All @@ -198,4 +198,4 @@ SPEC CHECKSUMS:

PODFILE CHECKSUM: a2f999e8fe2642046eaa22133617aca7cd25a681

COCOAPODS: 1.14.3
COCOAPODS: 1.10.1
25 changes: 25 additions & 0 deletions packages/patrol/lib/src/native/contracts/contracts.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 13 additions & 0 deletions packages/patrol/lib/src/native/contracts/contracts.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 9e1c1e2

Please sign in to comment.