[feat]: add timeout support for locator actions & reads - #3024
Open
seanmcguire12 wants to merge 3 commits into
Open
seanmcguire12 wants to merge 3 commits into
seanmcguire12 wants to merge 3 commits into
Conversation
|
seanmcguire12
changed the base branch from
add-locator-operation-context
to
share-operation-context-in-locator-helpers
September 23, 2026 20:57
Contributor
There was a problem hiding this comment.
All reported issues were addressed across 14 files
Architecture diagram
sequenceDiagram
participant Client
participant Delegate as Locator Delegate (Direct/Deep/Frame)
participant Locator as Locator
participant Progress as Progress Context
participant Registry as ExecutionContextRegistry
participant Resolver as SelectorResolver
participant CDP as CDP Session
Note over Client,CDP: Locator Action/Read with Timeout Boundary
Client->>Delegate: click()/hover()/count()/etc.(..., progress)
Delegate->>Delegate: real(progress)
Delegate->>Progress: throwIfStopped()
alt Deep or Frame Locator
Delegate->>Locator: resolveLocatorWithHops(page, root, selector, progress)
Locator->>Registry: waitForLocatorWorld(session, frameId, 1000, progress)
Registry->>CDP: Runtime.enable bounded
Registry->>CDP: Runtime.evaluate inspector probe
CDP-->>Registry: Locator world ready or fallback
Registry-->>Locator: Context ID
Locator-->>Delegate: Real Locator
end
Delegate->>Locator: action/read(..., progress)
Locator->>Progress: throwIfStopped()
Locator->>Resolver: resolveNode/resolveAll/count(query, progress)
Resolver->>Registry: waitForLocatorWorld(..., progress)
Registry-->>Resolver: Context ID
loop Per element index resolve
Resolver->>CDP: Runtime.evaluate bounded via runLocatorStep
CDP-->>Resolver: objectId
end
alt Element found
Resolver-->>Locator: ResolvedNode
else Timeout during resolve
Resolver->>Progress: throwIfStopped()
Progress-->>Resolver: TimeoutError
Resolver->>CDP: Runtime.releaseObject bounded cleanup
Resolver-->>Locator: Reject with timeout
end
Locator->>CDP: DOM.scrollIntoViewIfNeeded / DOM.getBoxModel / Input.dispatchMouseEvent each bounded
alt Command succeeds within budget
CDP-->>Locator: Result
Locator->>CDP: Runtime.releaseObject bounded cleanup
Locator-->>Delegate: Result
Delegate-->>Client: Action/read result
else Command stalls past deadline
Progress->>CDP: Abort signal fires
CDP-->>Locator: Late response ignored
Locator->>Progress: throwIfStopped throws TimeoutError
Locator->>CDP: Runtime.releaseObject cleanup bounded
Locator-->>Delegate: Reject
Delegate-->>Client: TimeoutError
end
Note over Progress,CDP: Closing CDP errors propagate and ordinary lookup failures keep prior behavior
Note over Progress,CDP: Cleanup failures never replace action errors and timeout during cleanup reports timeout
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
seanmcguire12
force-pushed
the
share-operation-context-in-locator-actions-reads
branch
from
September 23, 2026 21:11
b6a1ee8 to
77b5510
Compare
seanmcguire12
added this pull request to stack #3025
September 23, 2026 21:12
Contributor
There was a problem hiding this comment.
No issues found across 7 files
Confidence score: 5/5
- Automated review surfaced no issues in the provided summaries.
- No files require special attention.
Architecture diagram
sequenceDiagram
participant Caller as Caller Code
participant Delegate as Locator Delegate (Deep/Frame)
participant Locator as Locator
participant Progress as Progress Context
participant Resolver as Selector Resolver
participant Session as CDP Session
participant Browser as Browser Target
Note over Caller,Browser: Locator Action with Timeout (Happy Path)
Caller->>Delegate: click(options, progress)
Delegate->>Delegate: real(progress)
Delegate->>Locator: resolveNode(progress)
Locator->>Progress: throwIfStopped()
Progress-->>Locator: OK
Locator->>Session: Runtime.callFunctionOn (resolve selector)
Session-->>Locator: objectId
Locator->>Progress: remainingMs (check budget)
alt Budget remaining
Locator->>Session: DOM.scrollIntoViewIfNeeded
Session-->>Locator: OK
Locator->>Session: DOM.getBoxModel
Session-->>Locator: box model
Locator->>Progress: remainingMs (check budget)
loop For each click event
Locator->>Progress: throwIfStopped (before dispatch)
alt Still within deadline
Locator->>Session: Input.dispatchMouseEvent (fire-and-forget)
else Expired
Locator-->>Delegate: throw TimeoutError
Delegate-->>Caller: throw TimeoutError
end
end
Locator->>Progress: cleanup(releaseObject)
Progress->>Session: Runtime.releaseObject (bounded)
Session-->>Locator: OK
Locator-->>Delegate: Success
Delegate-->>Caller: Success
else Expired
Locator-->>Delegate: throw TimeoutError
Delegate-->>Caller: throw TimeoutError
end
Note over Caller,Browser: Stalled Command Path (Unhappy Path)
Caller->>Locator: count(progress)
Locator->>Progress: throwIfStopped()
Locator->>Session: Runtime.enable
Locator->>Session: DOM.enable
Locator->>Resolver: count(query, progress)
Resolver->>Resolver: waitForLocatorWorld(session, frameId, 1000, progress)
alt Stalled command (never responds)
Resolver->>Session: Runtime.evaluate (held)
Note over Resolver,Progress: Deadline reached while waiting
Progress-->>Resolver: TimeoutError
Resolver-->>Locator: throw TimeoutError
Locator-->>Caller: throw TimeoutError (late response ignored)
else CDP connection closed
Session-->>Resolver: CDP closed error
Resolver->>Resolver: throwIfStopped(), isCdpClosedError()
Resolver-->>Locator: throw original error
end
Note over Caller,Browser: Cleanup Path with Expired Deadline
Caller->>Locator: hover(progress)
Locator->>Session: resolveNode (completes)
Locator->>Session: DOM.getBoxModel (completes)
Locator->>Progress: cleanup(releaseObject)
alt Cleanup stale (deadline reached)
Progress->>Progress: Mark as expiring
Progress-->>Locator: throw TimeoutError (not awaiting release)
Locator-->>Caller: throw TimeoutError
else Cleanup fails
Session-->>Progress: release failure
Locator->>Progress: throwIfStopped()
Locator-->>Caller: throw original action error (cleanup error swallowed)
end
Note over Caller,Browser: Deep Locator with Shared Budget
Caller->>Delegate: selectOption(values, progress)
Delegate->>Delegate: real(progress) (takes time)
Delegate->>Locator: selectOption(values, progress)
Note over Locator,Progress: Remaining budget = original timeout - resolution time
Locator->>Progress: remainingMs (reduced budget)
alt Enough budget
Locator->>Session: execute action commands
Locator-->>Delegate: Success
else Budget exhausted
Locator-->>Delegate: throw TimeoutError
Delegate-->>Caller: throw TimeoutError
end
seanmcguire12
force-pushed
the
share-operation-context-in-locator-actions-reads
branch
from
September 25, 2026 22:08
9c695a4 to
a938b81
Compare
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
why
pr #3023 made locator resolution respect the caller's deadline. the action or read that follows also needs to use the remaining time. otherwise, a stalled browser command can keep the call waiting after its timeout.
what changed
click(),hover(),selectOption(),scrollTo(),sendClickEvent(),centroid(),backendNodeId(), counts, & element reads.note:
progress remains optional during migration. fill, typing, highlighting, & uploads come in a subsequent PR
test plan
added tests in
locatorActions.test.tsusing shared setup, controlled time, & held browser responses to verify:Summary by cubic
Makes locator actions and reads respect the caller's timeout so a stalled browser command can no longer hold a call past its deadline.
Written for commit a938b81. Summary will update on new commits.