Skip to content

Commit

Permalink
Merge pull request #2042 from leancodepl/feature/native-methods-timeout
Browse files Browse the repository at this point in the history
Feature/native methods timeout
  • Loading branch information
piotruela authored Jan 11, 2024
2 parents 454d2a1 + b42f0fa commit 93c52e8
Show file tree
Hide file tree
Showing 16 changed files with 269 additions and 102 deletions.
4 changes: 2 additions & 2 deletions dev/e2e_app/macos/Flutter/GeneratedPluginRegistrant.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@

import FlutterMacOS
import Foundation

import flutter_local_notifications
import flutter_timezone
import geolocator_apple
import patrol

func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin"))
FlutterLocalNotificationsPlugin.register(
with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin"))
FlutterTimezonePlugin.register(with: registry.registrar(forPlugin: "FlutterTimezonePlugin"))
GeolocatorPlugin.register(with: registry.registrar(forPlugin: "GeolocatorPlugin"))
PatrolPlugin.register(with: registry.registrar(forPlugin: "PatrolPlugin"))
Expand Down
2 changes: 1 addition & 1 deletion dev/e2e_app/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -406,7 +406,7 @@ packages:
path: "../../packages/patrol"
relative: true
source: path
version: "3.3.0"
version: "3.4.0"
patrol_finders:
dependency: transitive
description:
Expand Down
4 changes: 4 additions & 0 deletions packages/patrol/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## Unreleased

- Add optional timeout parameter to native methods (#2042).

## 3.4.0

- Allow for changing the port when running on iOS (#2027).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,10 +156,10 @@ class Automator private constructor() {
return getWindowTrees(uiDevice, uiAutomation)
}

fun tap(uiSelector: UiSelector, bySelector: BySelector, index: Int) {
fun tap(uiSelector: UiSelector, bySelector: BySelector, index: Int, timeout: Long? = null) {
Logger.d("tap(): $uiSelector, $bySelector")

if (waitForView(bySelector, index) == null) {
if (waitForView(bySelector, index, timeout) == null) {
throw UiObjectNotFoundException("$uiSelector")
}

Expand All @@ -169,12 +169,12 @@ class Automator private constructor() {
delay()
}

fun doubleTap(uiSelector: UiSelector, bySelector: BySelector, index: Int) {
fun doubleTap(uiSelector: UiSelector, bySelector: BySelector, index: Int, timeout: Long? = null) {
Logger.d("doubleTap(): $uiSelector, $bySelector")

val uiObject = uiDevice.findObject(uiSelector)

if (waitForView(bySelector, index) == null) {
if (waitForView(bySelector, index, timeout) == null) {
throw UiObjectNotFoundException("$uiSelector")
}

Expand All @@ -187,11 +187,11 @@ class Automator private constructor() {
delay()
}

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

val selector = By.clazz(EditText::class.java)
if (waitForView(selector, index) == null) {
if (waitForView(selector, index, timeout) == null) {
throw UiObjectNotFoundException("$selector")
}

Expand All @@ -216,11 +216,12 @@ class Automator private constructor() {
uiSelector: UiSelector,
bySelector: BySelector,
index: Int,
keyboardBehavior: KeyboardBehavior
keyboardBehavior: KeyboardBehavior,
timeout: Long? = null
) {
Logger.d("enterText($text): $uiSelector, $bySelector")

if (waitForView(bySelector, index) == null) {
if (waitForView(bySelector, index, timeout) == null) {
throw UiObjectNotFoundException("$uiSelector")
}

Expand Down Expand Up @@ -269,10 +270,10 @@ class Automator private constructor() {
delay()
}

fun waitUntilVisible(uiSelector: UiSelector, bySelector: BySelector, index: Int) {
fun waitUntilVisible(uiSelector: UiSelector, bySelector: BySelector, index: Int, timeout: Long? = null) {
Logger.d("waitUntilVisible(): $uiSelector, $bySelector")

if (waitForView(bySelector, index) == null) {
if (waitForView(bySelector, index, timeout) == null) {
throw UiObjectNotFoundException("$uiSelector")
}
}
Expand Down Expand Up @@ -355,14 +356,18 @@ class Automator private constructor() {
return notifications
}

fun tapOnNotification(index: Int) {
fun tapOnNotification(index: Int, timeout: Long? = null) {
Logger.d("tapOnNotification($index)")

try {
val query = Selector(
resourceId = "android:id/status_bar_latest_event_content",
instance = index.toLong()
)
val selector = query.toBySelector()
if (waitForView(selector, index, timeout) == null) {
throw UiObjectNotFoundException("$selector")
}
val obj = uiDevice.findObject(query.toUiSelector())
obj.click()
} catch (err: UiObjectNotFoundException) {
Expand All @@ -372,9 +377,12 @@ class Automator private constructor() {
delay()
}

fun tapOnNotification(selector: UiSelector) {
fun tapOnNotification(selector: UiSelector, bySelector: BySelector, timeout: Long? = null) {
Logger.d("tapOnNotification()")

if (waitForView(bySelector, 0, timeout) == null) {
throw UiObjectNotFoundException("$bySelector")
}
val obj = uiDevice.findObject(selector)
obj.click()

Expand Down Expand Up @@ -474,9 +482,9 @@ class Automator private constructor() {
/**
* Returns true if [bySelector] found a view at [index] within [timeoutMillis], false otherwise.
*/
private fun waitForView(bySelector: BySelector, index: Int): UiObject2? {
private fun waitForView(bySelector: BySelector, index: Int, timeout: Long? = null): UiObject2? {
val startTime = System.currentTimeMillis()
while (System.currentTimeMillis() - startTime < timeoutMillis) {
while (System.currentTimeMillis() - startTime < (timeout ?: timeoutMillis)) {
val objects = uiDevice.findObjects(bySelector)
if (objects.size > index && objects[index] != null) {
return objects[index]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,15 +130,17 @@ class AutomatorServer(private val automation: Automator) : NativeAutomatorServer
automation.tap(
uiSelector = request.selector.toUiSelector(),
bySelector = request.selector.toBySelector(),
index = request.selector.instance?.toInt() ?: 0
index = request.selector.instance?.toInt() ?: 0,
timeout = request.timeoutMillis
)
}

override fun doubleTap(request: TapRequest) {
automation.doubleTap(
uiSelector = request.selector.toUiSelector(),
bySelector = request.selector.toBySelector(),
index = request.selector.instance?.toInt() ?: 0
index = request.selector.instance?.toInt() ?: 0,
timeout = request.timeoutMillis
)
}

Expand All @@ -147,15 +149,17 @@ class AutomatorServer(private val automation: Automator) : NativeAutomatorServer
automation.enterText(
text = request.data,
index = request.index.toInt(),
keyboardBehavior = request.keyboardBehavior
keyboardBehavior = request.keyboardBehavior,
timeout = request.timeoutMillis
)
} else if (request.selector != null) {
automation.enterText(
text = request.data,
uiSelector = request.selector.toUiSelector(),
bySelector = request.selector.toBySelector(),
index = request.selector.instance?.toInt() ?: 0,
keyboardBehavior = request.keyboardBehavior
keyboardBehavior = request.keyboardBehavior,
timeout = request.timeoutMillis
)
} else {
throw PatrolException("enterText(): neither index nor selector are set")
Expand All @@ -176,7 +180,8 @@ class AutomatorServer(private val automation: Automator) : NativeAutomatorServer
automation.waitUntilVisible(
uiSelector = request.selector.toUiSelector(),
bySelector = request.selector.toBySelector(),
index = request.selector.instance?.toInt() ?: 0
index = request.selector.instance?.toInt() ?: 0,
timeout = request.timeoutMillis
)
}

Expand Down Expand Up @@ -206,9 +211,10 @@ class AutomatorServer(private val automation: Automator) : NativeAutomatorServer

override fun tapOnNotification(request: TapOnNotificationRequest) {
if (request.index != null) {
automation.tapOnNotification(request.index.toInt())
automation.tapOnNotification(request.index.toInt(), timeout = request.timeoutMillis)
} else if (request.selector != null) {
automation.tapOnNotification(request.selector.toUiSelector())
val selector = request.selector
automation.tapOnNotification(selector.toUiSelector(), selector.toBySelector(), timeout = request.timeoutMillis)
} else {
throw PatrolException("tapOnNotification(): neither index nor selector are set")
}
Expand Down

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 @@ -12,23 +12,38 @@
func openControlCenter() throws

// MARK: General UI interaction
func tap(onText text: String, inApp bundleId: String, atIndex index: Int) throws
func doubleTap(onText text: String, inApp bundleId: String) throws
func tap(
onText text: String,
inApp bundleId: String,
atIndex index: Int,
withTimeout timeout: TimeInterval?
) throws
func doubleTap(
onText text: String,
inApp bundleId: String,
withTimeout timeout: TimeInterval?
) throws
func enterText(
_ data: String,
byText text: String,
atIndex index: Int,
inApp bundleId: String,
dismissKeyboard: Bool
dismissKeyboard: Bool,
withTimeout timeout: TimeInterval?
) throws
func enterText(
_ data: String,
byIndex index: Int,
inApp bundleId: String,
dismissKeyboard: Bool
dismissKeyboard: Bool,
withTimeout timeout: TimeInterval?
) throws
func swipe(from start: CGVector, to end: CGVector, inApp bundleId: String) throws
func waitUntilVisible(onText text: String, inApp bundleId: String) throws
func waitUntilVisible(
onText text: String,
inApp bundleId: String,
withTimeout timeout: TimeInterval?
) throws

// MARK: Services
func enableDarkMode(_ bundleId: String) throws
Expand All @@ -52,8 +67,8 @@
func closeNotifications() throws
func closeHeadsUpNotification() throws
func getNotifications() throws -> [Notification]
func tapOnNotification(byIndex index: Int) throws
func tapOnNotification(bySubstring substring: String) throws
func tapOnNotification(byIndex index: Int, withTimeout timeout: TimeInterval?) throws
func tapOnNotification(bySubstring substring: String, withTimeout timeout: TimeInterval?) throws

// MARK: Permissions
func isPermissionDialogVisible(timeout: TimeInterval) throws -> Bool
Expand Down
Loading

0 comments on commit 93c52e8

Please sign in to comment.