fix: include buttons bitmask in drag mouseMoved events (#1087)

* fix: include buttons bitmask in drag mouseMoved events

The drag handler was omitting the `buttons` field from every
`mouseMoved` event dispatched during the move phase.  Without it the
browser sees `event.buttons === 0`, meaning no button is held, so
`dragstart`/`dragover`/`drop` never fire and the drop target never
receives the element.

Fix:
- Add `"buttons": 1` (left-button mask) to each `mouseMoved` sent
  while the button is held.
- Add `"buttons": 1` to `mousePressed` and `"buttons": 0` to
  `mouseReleased`, consistent with how `dispatch_click` handles the
  same fields in interaction.rs.
- Correct the parity-test fixture for `drag`, which was supplying a
  `selector` key instead of the `source` key that `handle_drag` reads.
- Add an e2e test (`e2e_drag_action_sends_buttons_during_move`) that
  drives the high-level `drag` action against the existing
  `html5_drag_probe` fixture and asserts that `mousemove` events carry
  `buttons == 1` and that `dragstart` fires on the source element.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* style: fix rustfmt formatting in e2e drag test

---------

Co-authored-by: wangjingjing <wangjingjing.99@bytedance.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: ctate <366502+ctate@users.noreply.github.com>
This commit is contained in:
juniper929
2026-03-30 20:21:04 -05:00
committed by GitHub
co-authored by Claude Sonnet 4.6 wangjingjing ctate
parent 6c93480d0d
commit 1f4b6b9d7a
3 changed files with 73 additions and 5 deletions
+67
View File
@@ -1615,6 +1615,73 @@ async fn e2e_mouse_drag_reaches_pointer_capture_target() {
assert_success(&resp);
}
#[tokio::test]
#[ignore]
async fn e2e_drag_action_sends_buttons_during_move() {
let mut state = DaemonState::new();
let resp = execute_command(
&json!({ "id": "1", "action": "launch", "headless": true }),
&mut state,
)
.await;
assert_success(&resp);
let resp = execute_command(
&json!({
"id": "2",
"action": "navigate",
"url": native_test_fixture_url("html5_drag_probe")
}),
&mut state,
)
.await;
assert_success(&resp);
let resp = execute_command(
&json!({
"id": "3",
"action": "drag",
"source": "#source",
"target": "#dest"
}),
&mut state,
)
.await;
assert_success(&resp);
assert_eq!(get_data(&resp)["dragged"].as_bool(), Some(true));
let resp = execute_command(
&json!({ "id": "4", "action": "evaluate", "script": "window.__html5DragProbe" }),
&mut state,
)
.await;
assert_success(&resp);
let probe = &get_data(&resp)["result"];
let events = probe["events"]
.as_array()
.expect("html5 drag probe should expose events");
// The mousemove events emitted while the button is held should carry
// buttons == 1 so the browser recognises the gesture as a drag.
assert!(
events
.iter()
.any(|event| { event["type"] == "mousemove" && event["buttons"].as_i64() == Some(1) }),
"Expected at least one mousemove with buttons == 1 during drag"
);
// dragstart must fire on the source element.
assert!(
events.iter().any(|event| event["type"] == "dragstart"),
"Expected dragstart to fire on the source element"
);
let resp = execute_command(&json!({ "id": "99", "action": "close" }), &mut state).await;
assert_success(&resp);
}
// ---------------------------------------------------------------------------
// State save/load, state management
// ---------------------------------------------------------------------------