fix(driver): skip pre-erase for replace-on-input drivers

The web driver's InputText already replaces content via select-all, so
the runner's unconditional EraseText was a redundant round-trip on
every InputText. A new optional TextReplacer capability lets a driver
assert replace semantics; the runner skips the erase when asserted.
This commit is contained in:
pj committed 2026-06-06 00:35:13 +05:30
1 parent 6009adac48
commit 29ec13adcd
5 files changed
+64 -3

No files matched your search

+6
View File
@@ -193,6 +193,12 @@ func (d *Driver) InputText(_ context.Context, text string) error {
)
}
// ReplacesTextOnInput reports that InputText replaces existing content via
// select-all, so the runner skips its pre-erase.
func (d *Driver) ReplacesTextOnInput() bool {
return true
}
// 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 {
+10
View File
@@ -60,6 +60,16 @@ type ForegroundChecker interface {
ForegroundApp(ctx context.Context) (string, error)
}
// TextReplacer is the optional capability for drivers whose InputText already
// replaces the field's content instead of appending to it. The runner must
// skip its pre-erase for such drivers: the erase would be a redundant
// round-trip on every InputText.
type TextReplacer interface {
// ReplacesTextOnInput reports whether InputText replaces existing
// content, making the runner's pre-erase unnecessary.
ReplacesTextOnInput() bool
}
// FocusedWindowChecker is the optional capability for reporting which app owns
// the focused (on-screen) window. The startup gate prefers it over
// ForegroundChecker: the resumed-activity signal flips to a freshly launched
+10
View File
@@ -63,6 +63,10 @@ type Driver struct {
MetricsData driver.Metrics
Failures map[ActionKind]error
// ReplacesText makes the mock assert the TextReplacer capability, so
// tests cover both the erase-before-type and replace-on-input paths.
ReplacesText bool
// ForegroundResults is consumed one entry per ForegroundApp call (the
// last entry repeats). Empty yields "", which disables the runner's
// app-scope guard so tests that don't care are unaffected.
@@ -212,6 +216,12 @@ func (d *Driver) InputText(ctx context.Context, text string) error {
return nil
}
func (d *Driver) ReplacesTextOnInput() bool {
d.mutex.Lock()
defer d.mutex.Unlock()
return d.ReplacesText
}
func (d *Driver) EraseText(ctx context.Context, characterCount int) error {
if err := d.failure(ActionEraseText); err != nil {
return err