Skip to content

fix(maestro): type inputText with a 75 ms per-character delay on Android - #3725

Merged
thymikee merged 3 commits into
callstack:mainfrom
airowe:fix/maestro-android-input-text-delay
Oct 16, 2026
Merged

thymikee merged 3 commits into
callstack:mainfrom
airowe:fix/maestro-android-input-text-delay

Conversation

@airowe

@airowe airowe commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Maestro inputText on Android now types with Maestro 2.5.1's 75 ms per-character delay (MaestroDriverService.kt), so debounced inputs see a change per keystroke instead of one batched commit. iOS is unchanged. The default lives in the Maestro compatibility policy next to the other 2.5.1 defaults and reaches the port through MAESTRO_RUNTIME_ADAPTER_POLICY. No new CLI flag or flow grammar. 7 files touched, no scope expansion.

Fixes #2159

Validation

  • Tested SHA: 327c9e2 (pnpm check:affected --run on an identical working tree, not --head, so the receipt is not commit-exact): format, lint, typecheck, layering, fallow, build and vitest-related all pass.
  • New tests: a projection case, and port-level tests that Android inputText sends delayMs: 75, iOS inputText sends none, and eraseText sends none on either platform. The Android assertions failed before each change.
  • Updated two Android provider-scenario assertions that encoded delayMs: 0; they show 75 reaching the provider seam.
  • Live (device evidence from 4331a7f, before the eraseText fix in 327c9e2, which doesn't touch the inputText path): replay --maestro inputText of 100 chars into Settings search took 12,023 ms on API 36 and 15,602 ms on API 32; released 0.20.3 took 375 ms and 299 ms. Recordings are in the comments.
  • Not run: the debounced Catalog search field in the Expo test app, API 34, and the Appium/Limrun backends.

View guided diff

Maestro 2.5.1 types inputText one character at a time with a 75 ms
sleep. The daemon port sent `type` with no delay, so Android's IME path
committed the whole string at once and debounced handlers fired once.

Own the delay in the Maestro compatibility policy and pass it from the
runtime port on Android only. iOS is unchanged.

Fixes callstack#2159
@airowe

airowe commented Oct 16, 2026

Copy link
Copy Markdown
Contributor Author

Live check on a Pixel_7_API_36 emulator (branch build, 4331a7f): replay --maestro inputText of 100 characters into Settings search took 12,241 ms. Released 0.20.3 took 376 ms for the same input, so the 75 ms pacing reaches the device on the Maestro path.

I haven't run the debounced Catalog search field from the test app. Its debounce is 320 ms (examples/test-app/src/lab-state.tsx), longer than the ~120 ms per-character gap, so it fires once at the end with or without this change. The final results would look the same either way.

If you want a check that tells the two apart, the test app could expose a draft-change counter next to the search field, and a flow could assert it. That would be a separate change to the test app. Happy to do it here or as a follow-up, whichever you prefer.

Appium/Limrun backends aren't covered; I only checked the ADB path.

@airowe
airowe marked this pull request as ready for review October 16, 2026 15:38

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 7 files

Reply to a comment to ask cubic a question or push back. It learns from your replies.

View guided diff | Re-trigger cubic

Comment thread packages/maestro/src/daemon-port/daemon-runtime-port.ts Outdated
@airowe

airowe commented Oct 16, 2026

Copy link
Copy Markdown
Contributor Author

Screen recordings: Maestro inputText of 100 characters into Android Settings search, same flow on each emulator.

Emulator Build type duration
Pixel_7_API_36 (API 36) released 0.20.3 375 ms
Pixel_7_API_36 (API 36) this PR (4331a7f) 12,023 ms
Pixel 6 (API 32) released 0.20.3 299 ms
Pixel 6 (API 32) this PR (4331a7f) 15,602 ms

With the PR the text arrives one character at a time, and Settings updates its results while typing. On the released build the whole string lands at once. API 34 wasn't run because its system image isn't installed on this machine. The first API 32 run hit a 10 s adb timeout on a fresh emulator and passed on the retry.

Videos, in table order:

Pixel_7_API_36-released-0.20.3.mp4
Pixel_7_API_36.mp4
ad2159_API_32-released-0.20.3.mp4
ad2159_API_32.mp4

eraseText sends its backspaces through the same type helper as
inputText, so it inherited the 75 ms per-character delay and a default
50-character erase gained about 3.75 s. Pass the delay only from the
inputText path.
@thymikee

Copy link
Copy Markdown
Member

This PR is ready at 327c9e2. The 75 ms Android inputText pacing is limited to inputText, and eraseText keeps its old path with no delay on both platforms. CI is green, and I did not run the tests locally.

Not blocking: the pacing test declares its own 75 value instead of reading the shipped preset (https://github.com/callstack/agent-device/blob/327c9e2/packages/maestro/src/daemon-port/__tests__/daemon-runtime-port-input-text-pacing.test.ts#L46), so the number is spelled in three places, and Android inputText now takes about 0.12 s per character, which the Maestro docs page does not mention (https://github.com/callstack/agent-device/blob/327c9e2/website/docs/docs/run-maestro-flows.md#L29). You can take or leave both.

The cubic-dev-ai thread about eraseText inheriting the delay no longer applies, because eraseText calls the shared helper without a delay at this head and the test.each asserts that on both platforms. Please resolve it: #3725 (comment)

Two things I could not check: the 75 ms value against the pinned 2.5.1 bytecode, and whether the Appium and Limrun providers honor the delay they now receive. A live run on a field that debounces under 75 ms, or with a draft-change counter, would show the per-keystroke onChange from #2159. That run is not required to merge.

@thymikee thymikee added the ready-for-human Valid work that needs human implementation, judgment, or maintainer merge label Oct 16, 2026
@thymikee
thymikee merged commit 0c672c0 into callstack:main Oct 16, 2026
1 check passed
@airowe

airowe commented Oct 16, 2026

Copy link
Copy Markdown
Contributor Author

Thanks! In 6474ef9 I added a Typing boundary to the versioned Maestro help (support-matrix.ts) and the matching line in run-maestro-flows.md: Android inputText is paced at 75 ms per character (about 0.12 s per character on an emulator), and iOS inputText and eraseText are unpaced. The docs-sync test keeps the two in step.

I kept the test's own 75 on purpose: docs/agents/test-authoring.md rejects expectations computed by the subject, and the separate literal is what catches the preset drifting from the pinned upstream value. Happy to switch it to read the preset if you'd prefer.

pnpm check:affected --run --head 6474ef9 passes every stage, including docs-links and docs-prose. The eraseText thread is already resolved.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-for-human Valid work that needs human implementation, judgment, or maintainer merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Maestro inputText types whole string at once; debounced inputs only fire once (real Maestro types per-keystroke)

2 participants