Skip to content

fix: fill_field no longer types into a field it did not capture (#56) - #61

Open
bluzername wants to merge 1 commit into
awlevin:mainfrom
bluzername:fix-fill-field-focus-steal
Open

bluzername wants to merge 1 commit into
awlevin:mainfrom
bluzername:fix-fill-field-focus-steal

Conversation

@bluzername

Copy link
Copy Markdown

Fixes #56.

fill_field's keystroke fallback (clear_field then type_text) act on whatever field has focus the moment it runs. Between the step's capture and this call there is the decision round trip and the settle delay - long enough for a page to move the focus somewhere else. In that window the fallback can empty a field it never meant to touch, same risk restore_field already refuses for the undo path ("Select All/Delete could destroy an unrelated field's contents"), but it was not guarded here.

What changed:

  • Field.same_element() (models.py): tells whether a live field is the same one as a captured Field, by role, label, placeholder and position - not by value, since typing is exactly what would change the value.
  • fill_field (actions.py): reads desktop.focused_field() right before clear_field/type_text and refuse, untouched, when it is not the same field. Returns "refused: focus moved to a different field since the step was captured".
  • _type_text and _type_email both forward this as "type_text refused: ..." / "type_email refused: ..." in the history line instead of acting like the text landed somewhere.

Test evidence: 5 new tests in tests/test_actions.py (focus moved to another field, nothing focused any more, same field still focused after a partial AX write, and propagation through _type_text/_type_email), RED confirmed against the old code then GREEN. Full suite: 735 passed (730 + 5 new), 2 skipped, 1 xfailed, unchanged otherwise. ruff check and ruff format --check both clean.

I not a maintainer here, just opening this for review. Happy to adjust the identity check if you want a different definition of "same field".

fill_field's keystroke fallback (clear_field + type_text) run on whatever
field has focus at the moment it fires. Between the step's capture and this
call there is the decision round trip and the settle delay, long enough for
a page to move the focus. In that window the fallback can empty a field it
never meant to touch.

Now fill_field reads desktop.focused_field() right before clear_field and
type_text, and it refuse, untouched, when that is not the same field the
step captured (checked by role, label, placeholder and position, not by
value, since typing is the very thing that would change the value). _type_text
and _type_email both forward this refusal in the history line instead of
going on as if the text landed somewhere.

5 new tests in tests/test_actions.py, RED->GREEN. Full suite 735 passed
(730 + 5 new), ruff clean.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

The keystroke fallback in fill_field can wipe whichever field has focus by the time it fires

1 participant