From 41511a2a329702e081b93a6869b0f24c8bb53ad7 Mon Sep 17 00:00:00 2001 From: PJ Date: Fri, 5 Jun 2026 17:40:09 +0530 Subject: [PATCH] feat(driver): add EraseText to the device driver surface --- internal/driver/chrome/driver.go | 17 +++++++++++++++ internal/driver/driver.go | 4 ++++ internal/driver/mock/mock.go | 36 ++++++++++++++++++++----------- internal/driver/sidecar/client.go | 5 +++++ 4 files changed, 49 insertions(+), 13 deletions(-) diff --git a/internal/driver/chrome/driver.go b/internal/driver/chrome/driver.go index 4dc98eb..df8aad1 100644 --- a/internal/driver/chrome/driver.go +++ b/internal/driver/chrome/driver.go @@ -193,6 +193,23 @@ func (d *Driver) InputText(_ context.Context, text string) error { ) } +// EraseText clears the focused field. InputText above already replaces via +// select-all, so the character count is not needed to bound the deletion. +func (d *Driver) EraseText(_ context.Context, _ int) error { + return chromedp.Run(d.tabCtx, + chromedp.ActionFunc(func(ctx context.Context) error { + if err := chromedp.Evaluate(` + (function() { + const el = document.activeElement; + if (el && typeof el.select === 'function') el.select(); + })()`, nil).Do(ctx); err != nil { + return err + } + return input.InsertText("").Do(ctx) + }), + ) +} + func (d *Driver) Swipe(_ context.Context, fromX, fromY, toX, toY int, duration time.Duration) error { millis := max(duration.Milliseconds(), 50) script := fmt.Sprintf(` diff --git a/internal/driver/driver.go b/internal/driver/driver.go index 6eb62f9..e4757d2 100644 --- a/internal/driver/driver.go +++ b/internal/driver/driver.go @@ -20,6 +20,10 @@ type DeviceDriver interface { DoubleTap(ctx context.Context, x, y int) error DoubleTapSelector(ctx context.Context, selector string) error InputText(ctx context.Context, text string) error + // EraseText deletes characterCount characters from the focused field. + // The runner calls it before InputText so the verb replaces existing + // content instead of appending to it. + EraseText(ctx context.Context, characterCount int) error Swipe(ctx context.Context, fromX, fromY, toX, toY int, duration time.Duration) error PressKey(ctx context.Context, key string) error LongPress(ctx context.Context, x, y int) error diff --git a/internal/driver/mock/mock.go b/internal/driver/mock/mock.go index a6f0f13..f60c323 100644 --- a/internal/driver/mock/mock.go +++ b/internal/driver/mock/mock.go @@ -19,6 +19,7 @@ const ( ActionDoubleTap ActionKind = "double_tap" ActionDoubleTapSelector ActionKind = "double_tap_selector" ActionInputText ActionKind = "input_text" + ActionEraseText ActionKind = "erase_text" ActionSwipe ActionKind = "swipe" ActionPressKey ActionKind = "press_key" ActionLongPress ActionKind = "long_press" @@ -32,19 +33,20 @@ const ( ) type Action struct { - Kind ActionKind - BundleID string - ClearState bool - X, Y int - FromX, FromY int - ToX, ToY int - Duration time.Duration - Selector string - Text string - Key string - LogLevel string - LogSince time.Time - Idle time.Duration + Kind ActionKind + BundleID string + ClearState bool + X, Y int + FromX, FromY int + ToX, ToY int + Duration time.Duration + Selector string + Text string + CharacterCount int + Key string + LogLevel string + LogSince time.Time + Idle time.Duration } // Driver is an in-memory Driver implementation for unit tests. @@ -210,6 +212,14 @@ func (d *Driver) InputText(ctx context.Context, text string) error { return nil } +func (d *Driver) EraseText(ctx context.Context, characterCount int) error { + if err := d.failure(ActionEraseText); err != nil { + return err + } + d.record(Action{Kind: ActionEraseText, CharacterCount: characterCount}) + return nil +} + func (d *Driver) Swipe(ctx context.Context, fromX, fromY, toX, toY int, duration time.Duration) error { if err := d.failure(ActionSwipe); err != nil { return err diff --git a/internal/driver/sidecar/client.go b/internal/driver/sidecar/client.go index 7374a47..1963409 100644 --- a/internal/driver/sidecar/client.go +++ b/internal/driver/sidecar/client.go @@ -137,6 +137,11 @@ func (c *Client) InputText(ctx context.Context, text string) error { return err } +func (c *Client) EraseText(ctx context.Context, characterCount int) error { + _, err := c.stub.EraseText(ctx, &driverpb.EraseTextRequest{CharacterCount: int32(characterCount)}) + return err +} + func (c *Client) Swipe(ctx context.Context, fromX, fromY, toX, toY int, duration time.Duration) error { _, err := c.stub.Swipe(ctx, &driverpb.SwipeRequest{ From: &driverpb.Point{X: int32(fromX), Y: int32(fromY)},