mobile-dev-inc / maestro

Painless Mobile UI Automation
https://maestro.mobile.dev/
Apache License 2.0
5.88k stars 281 forks source link

eraseText deletes an extra character on Android #2122

Open Fishbowler opened 2 weeks ago

Fishbowler commented 2 weeks ago

Is there an existing issue for this?

Steps to reproduce

- inputText: 'testing'
- eraseText: 3

Actual results

'tes' 4 characters have been erased.

Expected results

'test' Only erases the 3 I asked for :)

About app

n/a, but found with com.example.example - Maestro's Flutter test app

About environment

Linux, OpenJDK Temurin 17

Logs

Logs ``` 17:19:20.341 [ INFO] maestro.cli.runner.MaestroCommandRunner.invoke: Erase 3 characters RUNNING 17:19:20.342 [ INFO] maestro.cli.runner.MaestroCommandRunner.invoke: Erase 3 characters metadata CommandMetadata(numberOfRuns=null, evaluatedCommand=MaestroCommand(eraseTextCommand=EraseTextCommand(charactersToErase=3, label=null, optional=false)), logMessages=[], insight=Insight(message=, level=NONE)) 17:19:20.342 [ INFO] maestro.Maestro.eraseText: Erasing 3 characters 17:19:20.343 [DEBUG] io.grpc.netty.NettyClientHandler.log: [id: 0x4c15d066, L:/127.0.0.1:57512 - R:localhost/127.0.0.1:7001] OUTBOUND HEADERS: streamId=279 headers=GrpcHttp2OutboundHeaders[:authority: localhost:7001, :path: /maestro_android.MaestroDriver/eraseAllText, :method: POST, :scheme: http, content-type: application/grpc, te: trailers, user-agent: grpc-java-netty/1.50.2, grpc-accept-encoding: gzip, grpc-timeout: 119999m] streamDependency=0 weight=16 exclusive=false padding=0 endStream=false 17:19:20.343 [DEBUG] io.grpc.netty.NettyClientHandler.log: [id: 0x4c15d066, L:/127.0.0.1:57512 - R:localhost/127.0.0.1:7001] OUTBOUND DATA: streamId=279 padding=0 endStream=true length=7 bytes=00000000020803 17:19:20.346 [DEBUG] io.grpc.netty.NettyClientHandler.log: [id: 0x4c15d066, L:/127.0.0.1:57512 - R:localhost/127.0.0.1:7001] INBOUND PING: ack=false bytes=1234 17:19:20.346 [DEBUG] io.grpc.netty.NettyClientHandler.log: [id: 0x4c15d066, L:/127.0.0.1:57512 - R:localhost/127.0.0.1:7001] OUTBOUND PING: ack=true bytes=1234 17:19:20.542 [DEBUG] io.grpc.netty.NettyClientHandler.log: [id: 0x4c15d066, L:/127.0.0.1:57512 - R:localhost/127.0.0.1:7001] INBOUND HEADERS: streamId=279 headers=GrpcHttp2ResponseHeaders[:status: 200, content-type: application/grpc, grpc-encoding: identity, grpc-accept-encoding: gzip] padding=0 endStream=false 17:19:20.542 [DEBUG] io.grpc.netty.NettyClientHandler.log: [id: 0x4c15d066, L:/127.0.0.1:57512 - R:localhost/127.0.0.1:7001] INBOUND DATA: streamId=279 padding=0 endStream=false length=5 bytes=0000000000 17:19:20.542 [DEBUG] io.grpc.netty.NettyClientHandler.log: [id: 0x4c15d066, L:/127.0.0.1:57512 - R:localhost/127.0.0.1:7001] OUTBOUND PING: ack=false bytes=1234 17:19:20.542 [DEBUG] io.grpc.netty.NettyClientHandler.log: [id: 0x4c15d066, L:/127.0.0.1:57512 - R:localhost/127.0.0.1:7001] INBOUND HEADERS: streamId=279 headers=GrpcHttp2ResponseHeaders[grpc-status: 0] padding=0 endStream=true 17:19:20.543 [DEBUG] io.grpc.netty.NettyClientHandler.log: [id: 0x4c15d066, L:/127.0.0.1:57512 - R:localhost/127.0.0.1:7001] OUTBOUND HEADERS: streamId=281 headers=GrpcHttp2OutboundHeaders[:authority: localhost:7001, :path: /maestro_android.MaestroDriver/deviceInfo, :method: POST, :scheme: http, content-type: application/grpc, te: trailers, user-agent: grpc-java-netty/1.50.2, grpc-accept-encoding: gzip, grpc-timeout: 119999m] streamDependency=0 weight=16 exclusive=false padding=0 endStream=false 17:19:20.543 [DEBUG] io.grpc.netty.NettyClientHandler.log: [id: 0x4c15d066, L:/127.0.0.1:57512 - R:localhost/127.0.0.1:7001] OUTBOUND DATA: streamId=281 padding=0 endStream=true length=5 bytes=0000000000 17:19:20.544 [DEBUG] io.grpc.netty.NettyClientHandler.log: [id: 0x4c15d066, L:/127.0.0.1:57512 - R:localhost/127.0.0.1:7001] INBOUND PING: ack=true bytes=1234 17:19:20.587 [DEBUG] io.grpc.netty.NettyClientHandler.log: [id: 0x4c15d066, L:/127.0.0.1:57512 - R:localhost/127.0.0.1:7001] INBOUND PING: ack=false bytes=1234 17:19:20.588 [DEBUG] io.grpc.netty.NettyClientHandler.log: [id: 0x4c15d066, L:/127.0.0.1:57512 - R:localhost/127.0.0.1:7001] OUTBOUND PING: ack=true bytes=1234 17:19:20.588 [DEBUG] io.grpc.netty.NettyClientHandler.log: [id: 0x4c15d066, L:/127.0.0.1:57512 - R:localhost/127.0.0.1:7001] INBOUND HEADERS: streamId=281 headers=GrpcHttp2ResponseHeaders[:status: 200, content-type: application/grpc, grpc-encoding: identity, grpc-accept-encoding: gzip] padding=0 endStream=false 17:19:20.588 [DEBUG] io.grpc.netty.NettyClientHandler.log: [id: 0x4c15d066, L:/127.0.0.1:57512 - R:localhost/127.0.0.1:7001] INBOUND DATA: streamId=281 padding=0 endStream=false length=11 bytes=000000000608b80810e012 17:19:20.588 [DEBUG] io.grpc.netty.NettyClientHandler.log: [id: 0x4c15d066, L:/127.0.0.1:57512 - R:localhost/127.0.0.1:7001] OUTBOUND PING: ack=false bytes=1234 17:19:20.588 [DEBUG] io.grpc.netty.NettyClientHandler.log: [id: 0x4c15d066, L:/127.0.0.1:57512 - R:localhost/127.0.0.1:7001] INBOUND HEADERS: streamId=281 headers=GrpcHttp2ResponseHeaders[grpc-status: 0] padding=0 endStream=true 17:19:20.588 [DEBUG] io.grpc.netty.NettyClientHandler.log: [id: 0x4c15d066, L:/127.0.0.1:57512 - R:localhost/127.0.0.1:7001] OUTBOUND HEADERS: streamId=283 headers=GrpcHttp2OutboundHeaders[:authority: localhost:7001, :path: /maestro_android.MaestroDriver/viewHierarchy, :method: POST, :scheme: http, content-type: application/grpc, te: trailers, user-agent: grpc-java-netty/1.50.2, grpc-accept-encoding: gzip, grpc-timeout: 119999m] streamDependency=0 weight=16 exclusive=false padding=0 endStream=false 17:19:20.589 [DEBUG] io.grpc.netty.NettyClientHandler.log: [id: 0x4c15d066, L:/127.0.0.1:57512 - R:localhost/127.0.0.1:7001] OUTBOUND DATA: streamId=283 padding=0 endStream=true length=5 bytes=0000000000 17:19:20.590 [DEBUG] io.grpc.netty.NettyClientHandler.log: [id: 0x4c15d066, L:/127.0.0.1:57512 - R:localhost/127.0.0.1:7001] INBOUND PING: ack=true bytes=1234 17:19:20.631 [DEBUG] io.grpc.netty.NettyClientHandler.log: [id: 0x4c15d066, L:/127.0.0.1:57512 - R:localhost/127.0.0.1:7001] INBOUND PING: ack=false bytes=1234 17:19:20.631 [DEBUG] io.grpc.netty.NettyClientHandler.log: [id: 0x4c15d066, L:/127.0.0.1:57512 - R:localhost/127.0.0.1:7001] OUTBOUND PING: ack=true bytes=1234 17:19:21.167 [DEBUG] io.grpc.netty.NettyClientHandler.log: [id: 0x4c15d066, L:/127.0.0.1:57512 - R:localhost/127.0.0.1:7001] INBOUND HEADERS: streamId=283 headers=GrpcHttp2ResponseHeaders[:status: 200, content-type: application/grpc, grpc-encoding: identity, grpc-accept-encoding: gzip] padding=0 endStream=false 17:19:21.169 [DEBUG] io.grpc.netty.NettyClientHandler.log: [id: 0x4c15d066, L:/127.0.0.1:57512 - R:localhost/127.0.0.1:7001] INBOUND DATA: streamId=283 padding=0 endStream=false length=16384 bytes=0000014cbf0abb99053c3f786d6c2076657273696f6e3d27312e302720656e636f64696e673d275554462d3827207374616e64616c6f6e653d2779657327203f... 17:19:21.169 [DEBUG] io.grpc.netty.NettyClientHandler.log: [id: 0x4c15d066, L:/127.0.0.1:57512 - R:localhost/127.0.0.1:7001] OUTBOUND PING: ack=false bytes=1234 17:19:21.169 [DEBUG] io.grpc.netty.NettyClientHandler.log: [id: 0x4c15d066, L:/127.0.0.1:57512 - R:localhost/127.0.0.1:7001] INBOUND DATA: streamId=283 padding=0 endStream=false length=16384 bytes=2d636c69636b61626c653d2266616c7365222070617373776f72643d2266616c7365222073656c65637465643d2266616c7365222076697369626c652d746f2d... 17:19:21.169 [DEBUG] io.grpc.netty.NettyClientHandler.log: [id: 0x4c15d066, L:/127.0.0.1:57512 - R:localhost/127.0.0.1:7001] INBOUND DATA: streamId=283 padding=0 endStream=false length=16384 bytes=75746d6574686f642e6c6174696e3a69642f305f7265736f757263655f6e616d655f6f6266757363617465642220636c6173733d22616e64726f69642e776964... 17:19:21.169 [DEBUG] io.grpc.netty.NettyClientHandler.log: [id: 0x4c15d066, L:/127.0.0.1:57512 - R:localhost/127.0.0.1:7001] INBOUND DATA: streamId=283 padding=0 endStream=false length=16384 bytes=696e7075746d6574686f642e6c6174696e2220636f6e74656e742d646573633d222220636865636b61626c653d2266616c73652220636865636b65643d226661... 17:19:21.211 [DEBUG] io.grpc.netty.NettyClientHandler.log: [id: 0x4c15d066, L:/127.0.0.1:57512 - R:localhost/127.0.0.1:7001] INBOUND DATA: streamId=283 padding=0 endStream=false length=16384 bytes=313936335d5b3539332c323131385d223e0d0a202020202020202020202020202020202020202020202020202020202020202020203c6e6f646520696e646578... 17:19:21.211 [DEBUG] io.grpc.netty.NettyClientHandler.log: [id: 0x4c15d066, L:/127.0.0.1:57512 - R:localhost/127.0.0.1:7001] INBOUND DATA: streamId=283 padding=0 endStream=false length=3268 bytes=6c653d2266616c7365222070617373776f72643d2266616c7365222073656c65637465643d2266616c7365222076697369626c652d746f2d757365723d227472... 17:19:21.211 [DEBUG] io.grpc.netty.NettyClientHandler.log: [id: 0x4c15d066, L:/127.0.0.1:57512 - R:localhost/127.0.0.1:7001] INBOUND HEADERS: streamId=283 headers=GrpcHttp2ResponseHeaders[grpc-status: 0] padding=0 endStream=true 17:19:21.212 [DEBUG] io.grpc.netty.NettyClientHandler.log: [id: 0x4c15d066, L:/127.0.0.1:57512 - R:localhost/127.0.0.1:7001] INBOUND PING: ack=true bytes=1234 17:19:21.215 [DEBUG] io.grpc.netty.NettyClientHandler.log: [id: 0x4c15d066, L:/127.0.0.1:57512 - R:localhost/127.0.0.1:7001] OUTBOUND HEADERS: streamId=285 headers=GrpcHttp2OutboundHeaders[:authority: localhost:7001, :path: /maestro_android.MaestroDriver/deviceInfo, :method: POST, :scheme: http, content-type: application/grpc, te: trailers, user-agent: grpc-java-netty/1.50.2, grpc-accept-encoding: gzip, grpc-timeout: 119999m] streamDependency=0 weight=16 exclusive=false padding=0 endStream=false 17:19:21.215 [DEBUG] io.grpc.netty.NettyClientHandler.log: [id: 0x4c15d066, L:/127.0.0.1:57512 - R:localhost/127.0.0.1:7001] OUTBOUND DATA: streamId=285 padding=0 endStream=true length=5 bytes=0000000000 17:19:21.217 [DEBUG] io.grpc.netty.NettyClientHandler.log: [id: 0x4c15d066, L:/127.0.0.1:57512 - R:localhost/127.0.0.1:7001] INBOUND PING: ack=false bytes=1234 17:19:21.217 [DEBUG] io.grpc.netty.NettyClientHandler.log: [id: 0x4c15d066, L:/127.0.0.1:57512 - R:localhost/127.0.0.1:7001] OUTBOUND PING: ack=true bytes=1234 17:19:21.218 [DEBUG] io.grpc.netty.NettyClientHandler.log: [id: 0x4c15d066, L:/127.0.0.1:57512 - R:localhost/127.0.0.1:7001] INBOUND HEADERS: streamId=285 headers=GrpcHttp2ResponseHeaders[:status: 200, content-type: application/grpc, grpc-encoding: identity, grpc-accept-encoding: gzip] padding=0 endStream=false 17:19:21.219 [DEBUG] io.grpc.netty.NettyClientHandler.log: [id: 0x4c15d066, L:/127.0.0.1:57512 - R:localhost/127.0.0.1:7001] INBOUND DATA: streamId=285 padding=0 endStream=false length=11 bytes=000000000608b80810e012 17:19:21.219 [DEBUG] io.grpc.netty.NettyClientHandler.log: [id: 0x4c15d066, L:/127.0.0.1:57512 - R:localhost/127.0.0.1:7001] OUTBOUND PING: ack=false bytes=1234 17:19:21.219 [DEBUG] io.grpc.netty.NettyClientHandler.log: [id: 0x4c15d066, L:/127.0.0.1:57512 - R:localhost/127.0.0.1:7001] INBOUND HEADERS: streamId=285 headers=GrpcHttp2ResponseHeaders[grpc-status: 0] padding=0 endStream=true 17:19:21.219 [DEBUG] io.grpc.netty.NettyClientHandler.log: [id: 0x4c15d066, L:/127.0.0.1:57512 - R:localhost/127.0.0.1:7001] OUTBOUND HEADERS: streamId=287 headers=GrpcHttp2OutboundHeaders[:authority: localhost:7001, :path: /maestro_android.MaestroDriver/viewHierarchy, :method: POST, :scheme: http, content-type: application/grpc, te: trailers, user-agent: grpc-java-netty/1.50.2, grpc-accept-encoding: gzip, grpc-timeout: 119999m] streamDependency=0 weight=16 exclusive=false padding=0 endStream=false 17:19:21.220 [DEBUG] io.grpc.netty.NettyClientHandler.log: [id: 0x4c15d066, L:/127.0.0.1:57512 - R:localhost/127.0.0.1:7001] OUTBOUND DATA: streamId=287 padding=0 endStream=true length=5 bytes=0000000000 17:19:21.220 [DEBUG] io.grpc.netty.NettyClientHandler.log: [id: 0x4c15d066, L:/127.0.0.1:57512 - R:localhost/127.0.0.1:7001] INBOUND PING: ack=true bytes=1234 17:19:21.261 [DEBUG] io.grpc.netty.NettyClientHandler.log: [id: 0x4c15d066, L:/127.0.0.1:57512 - R:localhost/127.0.0.1:7001] INBOUND PING: ack=false bytes=1234 17:19:21.261 [DEBUG] io.grpc.netty.NettyClientHandler.log: [id: 0x4c15d066, L:/127.0.0.1:57512 - R:localhost/127.0.0.1:7001] OUTBOUND PING: ack=true bytes=1234 17:19:21.818 [DEBUG] io.grpc.netty.NettyClientHandler.log: [id: 0x4c15d066, L:/127.0.0.1:57512 - R:localhost/127.0.0.1:7001] INBOUND HEADERS: streamId=287 headers=GrpcHttp2ResponseHeaders[:status: 200, content-type: application/grpc, grpc-encoding: identity, grpc-accept-encoding: gzip] padding=0 endStream=false 17:19:21.819 [DEBUG] io.grpc.netty.NettyClientHandler.log: [id: 0x4c15d066, L:/127.0.0.1:57512 - R:localhost/127.0.0.1:7001] INBOUND DATA: streamId=287 padding=0 endStream=false length=16384 bytes=0000014cbf0abb99053c3f786d6c2076657273696f6e3d27312e302720656e636f64696e673d275554462d3827207374616e64616c6f6e653d2779657327203f... 17:19:21.819 [DEBUG] io.grpc.netty.NettyClientHandler.log: [id: 0x4c15d066, L:/127.0.0.1:57512 - R:localhost/127.0.0.1:7001] OUTBOUND PING: ack=false bytes=1234 17:19:21.819 [DEBUG] io.grpc.netty.NettyClientHandler.log: [id: 0x4c15d066, L:/127.0.0.1:57512 - R:localhost/127.0.0.1:7001] INBOUND DATA: streamId=287 padding=0 endStream=false length=16384 bytes=2d636c69636b61626c653d2266616c7365222070617373776f72643d2266616c7365222073656c65637465643d2266616c7365222076697369626c652d746f2d... 17:19:21.819 [DEBUG] io.grpc.netty.NettyClientHandler.log: [id: 0x4c15d066, L:/127.0.0.1:57512 - R:localhost/127.0.0.1:7001] INBOUND DATA: streamId=287 padding=0 endStream=false length=16384 bytes=75746d6574686f642e6c6174696e3a69642f305f7265736f757263655f6e616d655f6f6266757363617465642220636c6173733d22616e64726f69642e776964... 17:19:21.819 [DEBUG] io.grpc.netty.NettyClientHandler.log: [id: 0x4c15d066, L:/127.0.0.1:57512 - R:localhost/127.0.0.1:7001] INBOUND DATA: streamId=287 padding=0 endStream=false length=16384 bytes=696e7075746d6574686f642e6c6174696e2220636f6e74656e742d646573633d222220636865636b61626c653d2266616c73652220636865636b65643d226661... 17:19:21.861 [DEBUG] io.grpc.netty.NettyClientHandler.log: [id: 0x4c15d066, L:/127.0.0.1:57512 - R:localhost/127.0.0.1:7001] INBOUND DATA: streamId=287 padding=0 endStream=false length=16384 bytes=313936335d5b3539332c323131385d223e0d0a202020202020202020202020202020202020202020202020202020202020202020203c6e6f646520696e646578... 17:19:21.861 [DEBUG] io.grpc.netty.NettyClientHandler.log: [id: 0x4c15d066, L:/127.0.0.1:57512 - R:localhost/127.0.0.1:7001] OUTBOUND WINDOW_UPDATE: streamId=0 windowSizeIncrement=527616 17:19:21.861 [DEBUG] io.grpc.netty.NettyClientHandler.log: [id: 0x4c15d066, L:/127.0.0.1:57512 - R:localhost/127.0.0.1:7001] INBOUND DATA: streamId=287 padding=0 endStream=false length=3268 bytes=6c653d2266616c7365222070617373776f72643d2266616c7365222073656c65637465643d2266616c7365222076697369626c652d746f2d757365723d227472... 17:19:21.861 [DEBUG] io.grpc.netty.NettyClientHandler.log: [id: 0x4c15d066, L:/127.0.0.1:57512 - R:localhost/127.0.0.1:7001] INBOUND HEADERS: streamId=287 headers=GrpcHttp2ResponseHeaders[grpc-status: 0] padding=0 endStream=true 17:19:21.862 [DEBUG] io.grpc.netty.NettyClientHandler.log: [id: 0x4c15d066, L:/127.0.0.1:57512 - R:localhost/127.0.0.1:7001] INBOUND PING: ack=true bytes=1234 17:19:21.865 [ INFO] maestro.cli.runner.MaestroCommandRunner.invoke: Erase 3 characters COMPLETED ```

Maestro version

1.39.0

How did you install Maestro?

install script (https://get.maestro.mobile.dev)

Anything else?

I think this is caused by this loop:

https://github.com/mobile-dev-inc/maestro/blob/475acc1ce6884ed273a12fbc8ae5aaf5970c06f8/maestro-android/src/androidTest/java/dev/mobile/maestro/MaestroDriverService.kt#L276-L278

When using - inputText: 3 this will press delete for 0 to 3 -> 4 times.

This can be reproduced by performing the same logic in FakeDriver:

diff --git a/maestro-test/src/main/kotlin/maestro/test/drivers/FakeDriver.kt b/maestro-test/src/main/kotlin/maestro/test/drivers/FakeDriver.kt
index b6bb66a..99bb988 100644
--- a/maestro-test/src/main/kotlin/maestro/test/drivers/FakeDriver.kt
+++ b/maestro-test/src/main/kotlin/maestro/test/drivers/FakeDriver.kt
@@ -256,10 +256,12 @@ class FakeDriver : Driver {
     override fun eraseText(charactersToErase: Int) {
         ensureOpen()

-        currentText = if (charactersToErase == MAX_ERASE_CHARACTERS) {
-            ""
+        if (charactersToErase == MAX_ERASE_CHARACTERS) {
+            currentText = ""
         } else {
-            currentText.dropLast(charactersToErase)
+            for (i in 0..charactersToErase) {
+                currentText = currentText.dropLast(1)
+            }
         }
         events += Event.EraseAllText
     }
linear[bot] commented 2 weeks ago

MA-2458 eraseText deletes an extra character on Android