Skip to content

fix(locator): serialize click input events - #2527

Open
alectimison-maker wants to merge 1 commit into
browserbase:mainfrom
alectimison-maker:fix/locator-click-order
Open

fix(locator): serialize click input events#2527
alectimison-maker wants to merge 1 commit into
browserbase:mainfrom
alectimison-maker:fix/locator-click-order

Conversation

@alectimison-maker

@alectimison-maker alectimison-maker commented Jul 30, 2026

Copy link
Copy Markdown

why

Locator.click() currently starts mouseMoved, mousePressed, and
mouseReleased CDP commands together and awaits them with Promise.all. A
reactive UI can therefore receive the press before its hover/pointer state has
settled, while Stagehand still reports a successful click. This matches the
failure described in #2486.

Stagehand prioritizes reliability over speed, so this change makes the
locator-only input sequence explicit and ordered. The separate coordinate
Page.click path is intentionally unchanged.

what changed

  • await each locator mouse move, press, and release before dispatching the next
    event
  • add a deterministic CDP-session regression that fails if two mouse events
    overlap and verifies the full double-click sequence
  • add a patch changeset for @browserbasehq/stagehand

test plan

  • Red/green regression: the new test failed on the old pipelined implementation
    with mouse events overlapped, then passed after serialization
  • Core unit suite: 83 files, 886 tests passed
  • Local click integration suite: 6 tests passed
  • pnpm --filter @browserbasehq/stagehand run lint
  • pnpm --filter @browserbasehq/stagehand run build (ESM and CJS)
  • prettier --check on all changed files

The repository's post-test CTRF converter prints a pre-existing
glob/minimatch export warning after successful standard test runs. Running
Vitest directly avoids that converter; the complete core unit suite passes.


Summary by cubic

Serialize Locator.click() mouse events to enforce ordered hover → press → release. This improves click reliability in reactive UIs; Page.click remains unchanged.

  • Bug Fixes
    • Await mouseMoved, then mousePressed, then mouseReleased (no overlapping CDP commands).
    • Add regression test to catch overlap and verify the full double-click sequence.
    • Add patch changeset for @browserbasehq/stagehand.

Written for commit d46e3e3. Summary will update on new commits.

Review in cubic

@changeset-bot

changeset-bot Bot commented Jul 30, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: d46e3e3

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 3 packages
Name Type
@browserbasehq/stagehand Patch
@browserbasehq/stagehand-evals Patch
@browserbasehq/stagehand-server-v3 Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions

Copy link
Copy Markdown
Contributor

This PR is from an external contributor and must be approved by a stagehand team member with write access before CI can run.
Approving the latest commit mirrors it into an internal PR owned by the approver.
If new commits are pushed later, the internal PR stays open but is marked stale until someone approves the latest external commit and refreshes it.

@github-actions github-actions Bot added external-contributor Tracks PRs mirrored from external contributor forks. external-contributor:awaiting-approval Waiting for a stagehand team member to approve the latest external commit. labels Jul 30, 2026

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 3 files

Confidence score: 5/5

  • Automated review surfaced no issues in the provided summaries.
  • No files require special attention.
Architecture diagram
sequenceDiagram
    participant Test as Test Suite
    participant Locator as Locator.click()
    participant CDP as CDP Session
    participant Page as Page (Browser Event Loop)
    
    Note over Test,Page: NEW: Serialized mouse event dispatch flow
    
    Test->>Locator: locator.click({ clickCount: 2 })
    
    Locator->>CDP: Input.dispatchMouseEvent (type: "mouseMoved")
    Note over Locator,CDP: CHANGED: await before next event
    CDP-->>Page: CDP command → browser processes mouse move
    CDP-->>Locator: response (success)

    alt Click 1
        Locator->>CDP: Input.dispatchMouseEvent (type: "mousePressed", clickCount: 1)
        CDP-->>Page: browser processes press
        Locator->>CDP: Input.dispatchMouseEvent (type: "mouseReleased", clickCount: 1)
        CDP-->>Page: browser processes release
    end

    alt Click 2
        Locator->>CDP: Input.dispatchMouseEvent (type: "mousePressed", clickCount: 2)
        CDP-->>Page: browser processes press
        Locator->>CDP: Input.dispatchMouseEvent (type: "mouseReleased", clickCount: 2)
        CDP-->>Page: browser processes release
    end

    CDP-->>Locator: all responses
    Locator-->>Test: undefined

    Note over Test,CDP: Regression test: detects overlapping events
    
    Test->>Locator: locator.click() with mock that fails on overlap
    Locator->>CDP: Input.dispatchMouseEvent (parallel in old code)
    alt If events overlap (old behavior)
        CDP-->>Locator: Error("mouse events overlapped")
        Locator-->>Test: rejected promise
        Test-->>Test: test fails
    else If serialized (new behavior)
        Locator->>CDP: await each sequentially
        CDP-->>Locator: success
        Locator-->>Test: undefined
    end

    Note over Locator,CDP: Page.click() path remains unchanged (not shown)
Loading

Re-trigger cubic

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

external-contributor:awaiting-approval Waiting for a stagehand team member to approve the latest external commit. external-contributor Tracks PRs mirrored from external contributor forks.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant