diff --git a/cli/src/commands.rs b/cli/src/commands.rs index a802c064..215b0594 100644 --- a/cli/src/commands.rs +++ b/cli/src/commands.rs @@ -138,18 +138,22 @@ pub fn parse_command(args: &[String], flags: &Flags) -> Result { let new_tab = rest.contains(&"--new-tab"); + let js_click = rest.contains(&"--js-click"); let sel = rest .iter() - .find(|arg| **arg != "--new-tab") + .find(|arg| **arg != "--new-tab" && **arg != "--js-click") .ok_or_else(|| ParseError::MissingArguments { context: "click".to_string(), - usage: "click [--new-tab]", + usage: "click [--new-tab] [--js-click]", })?; + let mut cmd = json!({ "id": id, "action": "click", "selector": sel }); if new_tab { - Ok(json!({ "id": id, "action": "click", "selector": sel, "newTab": true })) - } else { - Ok(json!({ "id": id, "action": "click", "selector": sel })) + cmd["newTab"] = json!(true); + } + if js_click { + cmd["jsClick"] = json!(true); } + Ok(cmd) } "dblclick" => { let sel = rest.first().ok_or_else(|| ParseError::MissingArguments { diff --git a/cli/src/native/actions.rs b/cli/src/native/actions.rs index 4c140043..3a1bd9a7 100644 --- a/cli/src/native/actions.rs +++ b/cli/src/native/actions.rs @@ -2186,6 +2186,19 @@ async fn handle_click(cmd: &Value, state: &mut DaemonState) -> Result, +) -> Result<(), String> { + let (object_id, effective_session_id) = resolve_element_object_id( + client, + session_id, + ref_map, + selector_or_ref, + iframe_sessions, + ) + .await?; + + let js = r#"function() { + this.scrollIntoView({ block: 'center', behavior: 'instant' }); + this.click(); + }"#; + + client + .send_command_typed::<_, Value>( + "Runtime.callFunctionOn", + &CallFunctionOnParams { + function_declaration: js.to_string(), + object_id: Some(object_id), + arguments: None, + return_by_value: Some(true), + await_promise: Some(false), + }, + Some(&effective_session_id), + ) + .await?; + + Ok(()) +} + /// Fallback for when the coordinate-based CDP click did not toggle the /// checkbox/radio state. This mirrors how Playwright dispatches clicks /// through the DOM rather than via raw Input.dispatchMouseEvent coordinates.