mirror of
https://github.com/priyanshujain/sanderling.git
synced 2026-10-03 03:27:10 +00:00
feat(driver): native DoubleTap RPC for a tight inter-tap gap
Composing two Tap round trips from the Go client spread the taps by hundreds of milliseconds on iOS, wide enough for the app to navigate between them, so double-submission races could never reproduce. The sidecar now lands both taps back-to-back next to the device transport.
This commit is contained in:
1 parent
d6188df667
commit
4f579d2a0b
8 files changed
+151
-38
No files matched your search
@@ -4,6 +4,15 @@ interface DriverBackend {
|
||||
fun launch(bundleId: String, clearState: Boolean, env: Map<String, String> = emptyMap())
|
||||
fun terminate(bundleId: String)
|
||||
fun tap(x: Int, y: Int)
|
||||
|
||||
// doubleTap lands two taps as close together as the platform allows.
|
||||
// The default composes two taps back-to-back; backends with higher
|
||||
// per-tap latency override to tighten the gap.
|
||||
fun doubleTap(x: Int, y: Int) {
|
||||
tap(x, y)
|
||||
tap(x, y)
|
||||
}
|
||||
|
||||
fun tapSelector(selector: String)
|
||||
fun inputText(text: String)
|
||||
fun eraseText(characterCount: Int)
|
||||
@@ -735,6 +744,15 @@ class IosDriverBackend(private val udid: String) : DriverBackend {
|
||||
|
||||
override fun tap(x: Int, y: Int) = withReconnect { driver.tap(maestro.Point(x, y)) }
|
||||
|
||||
// Both taps inside one reconnect scope, with nothing between them: the
|
||||
// XCTest transport adds hundreds of milliseconds per round trip, so any
|
||||
// client-side composition spreads the taps wide enough for the app to
|
||||
// navigate between them.
|
||||
override fun doubleTap(x: Int, y: Int) = withReconnect {
|
||||
driver.tap(maestro.Point(x, y))
|
||||
driver.tap(maestro.Point(x, y))
|
||||
}
|
||||
|
||||
override fun longPress(x: Int, y: Int) = withReconnect { driver.longPress(maestro.Point(x, y)) }
|
||||
|
||||
override fun tapSelector(selector: String) = withReconnect {
|
||||
|
||||
@@ -54,6 +54,13 @@ class DriverService(
|
||||
}
|
||||
}
|
||||
|
||||
override fun doubleTap(request: Point, responseObserver: StreamObserver<Empty>) {
|
||||
runRpc(responseObserver) {
|
||||
backend.doubleTap(request.x, request.y)
|
||||
Empty.getDefaultInstance()
|
||||
}
|
||||
}
|
||||
|
||||
override fun longPress(request: Point, responseObserver: StreamObserver<Empty>) {
|
||||
runRpc(responseObserver) {
|
||||
backend.longPress(request.x, request.y)
|
||||
|
||||
@@ -83,6 +83,34 @@ class DriverServiceTest {
|
||||
assertEquals("hello world", backend.lastInputText)
|
||||
}
|
||||
|
||||
@Test fun doubleTapDefaultComposesTwoTaps() {
|
||||
// Interface delegation would bind the default doubleTap to the
|
||||
// delegate, bypassing the tap override, so implement the interface
|
||||
// directly.
|
||||
val taps = mutableListOf<Pair<Int, Int>>()
|
||||
val backend = object : DriverBackend {
|
||||
override fun launch(bundleId: String, clearState: Boolean, env: Map<String, String>) {}
|
||||
override fun terminate(bundleId: String) {}
|
||||
override fun tap(x: Int, y: Int) { taps.add(x to y) }
|
||||
override fun tapSelector(selector: String) {}
|
||||
override fun inputText(text: String) {}
|
||||
override fun eraseText(characterCount: Int) {}
|
||||
override fun swipe(fromX: Int, fromY: Int, toX: Int, toY: Int, durationMillis: Long) {}
|
||||
override fun pressKey(key: String) {}
|
||||
override fun longPress(x: Int, y: Int) {}
|
||||
override fun screenshot(): Triple<ByteArray, Int, Int> = Triple(byteArrayOf(), 0, 0)
|
||||
override fun hierarchy(): String = "{}"
|
||||
override fun recentLogs(sinceUnixMillis: Long, minLevel: String): List<LogLine> = emptyList()
|
||||
override fun waitForIdle(durationMillis: Long) {}
|
||||
override fun healthy(): Boolean = true
|
||||
override fun metrics(bundleId: String): MetricsSample = MetricsSample(0.0, 0L, 0L)
|
||||
}
|
||||
val client = newClient(backend)
|
||||
|
||||
client.doubleTap(Point.newBuilder().setX(120).setY(340).build())
|
||||
assertEquals(listOf(120 to 340, 120 to 340), taps)
|
||||
}
|
||||
|
||||
@Test fun eraseTextForwardsCharacterCount() {
|
||||
val backend = StubDriverBackend("android")
|
||||
val client = newClient(backend)
|
||||
|
||||
Reference in new issue
Block a user