From 231a74b87691c6f230c7e8c43447bb12e3657e40 Mon Sep 17 00:00:00 2001 From: PJ Date: Sat, 15 Aug 2026 13:59:03 +0530 Subject: [PATCH] fix(runner): a selector the tree cannot resolve is not a focus failure otherElementHoldsFocus answered true when FindNode returned nothing, so an unresolvable target read as "another element holds focus". confirmFocus then re-dumped, resolved nothing again, and errored unconditionally. Three of those in a row abort the run. Not knowing where the target is says nothing about where the text would land. The guard's real case, a resolved target with focus outside its subtree, still errors exactly as before. Claude-Session: https://claude.ai/code/session_01A5KmftdEJ49A9z5mF5ESrX --- internal/runner/runner.go | 7 +++++-- internal/runner/runner_test.go | 24 ++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/internal/runner/runner.go b/internal/runner/runner.go index 950c12c..d429115 100644 --- a/internal/runner/runner.go +++ b/internal/runner/runner.go @@ -827,13 +827,16 @@ func confirmFocus( // otherElementHoldsFocus reports whether the hierarchy shows focus on // something outside the selector's subtree, which is the state that sends -// typed text to the wrong field. +// typed text to the wrong field. A selector the hierarchy cannot resolve +// answers false: not knowing where the target is says nothing about where the +// text would land, and failing on it turns every step the dump has no node for +// into an apply error, which is an aborted run three steps later. func otherElementHoldsFocus(tree *hierarchy.Tree, selector string) bool { if tree == nil || focusedElement(tree) == nil { return false } target := tree.FindNode(selector) - return target == nil || !holdsFocus(target) + return target != nil && !holdsFocus(target) } func focusedElement(tree *hierarchy.Tree) *hierarchy.Element { diff --git a/internal/runner/runner_test.go b/internal/runner/runner_test.go index 1e1cd90..4911ae5 100644 --- a/internal/runner/runner_test.go +++ b/internal/runner/runner_test.go @@ -974,6 +974,30 @@ func TestApplyAction_InputTextSkipsFocusCheckWhenNoOtherFieldHoldsFocus(t *testi } } +// A selector the hierarchy cannot resolve is the guard saying "I cannot tell", +// not "another element holds focus". Answering the second manufactures an apply +// error on every InputText the tree has no node for, and three in a row abort +// the run. +func TestApplyAction_InputTextTypesWhenTheTargetIsNotInTheHierarchy(t *testing.T) { + fastFocusSettle(t) + tree, err := hierarchy.Parse(loginFocusOnEmail) + if err != nil { + t.Fatalf("Parse: %v", err) + } + driverMock := mockdriver.New() + driverMock.HierarchyJSON = loginFocusOnEmail + action := verifier.Action{ + Kind: verifier.ActionKindInputText, + On: "data-testid:LoginPassword", + Text: "ledger123", + } + + mustDispatch(t, driverMock, action, tree) + if !typedText(driverMock.Actions(), "ledger123") { + t.Errorf("an unresolvable target must not block typing, got %v", driverMock.Actions()) + } +} + func typedText(actions []mockdriver.Action, text string) bool { for _, action := range actions { if action.Kind == mockdriver.ActionInputText && action.Text == text {