22//!
33//! Simple and clean - just uses the extension bridge, no DevTools fallback.
44
5- use crate :: { AutomationError , Browser , Desktop , Selector , UIElement } ;
5+ use crate :: { AutomationError , Desktop } ;
66use std:: time:: Duration ;
77use tracing:: { debug, error, info, warn} ;
88
9- async fn wake_extension_service_worker_and_restore_focus ( previously_focused : Option < UIElement > ) {
10- // Best-effort: try to open Chrome's extensions page and click the Service Worker link
11- // Then restore the previously focused UI element to avoid disrupting the user.
12- let wake_attempt = ( || -> Result < ( ) , AutomationError > {
13- let desktop = Desktop :: new_default ( ) ?;
14-
15- // Open in Chrome explicitly to ensure we're targeting the correct browser settings UI
16- let _chrome_window = desktop. open_url ( "chrome://extensions" , Some ( Browser :: Chrome ) ) ?;
17-
18- Ok ( ( ) )
19- } ) ( ) ;
20-
21- if wake_attempt. is_err ( ) {
22- warn ! (
23- error = %wake_attempt. err( ) . unwrap( ) ,
24- "Failed to open chrome://extensions for service worker wakeup"
25- ) ;
26- return ;
27- }
28-
29- // Give the page a brief moment to render
30- tokio:: time:: sleep ( Duration :: from_millis ( 800 ) ) . await ;
31-
32- // Try a few selector variants that commonly match the service worker inspect link text
33- // This is intentionally permissive and case-insensitive via contains behavior in matchers.
34- let candidate_selectors = [ "role:link|name:service worker" ] ;
35-
36- // Best-effort clicking; ignore errors if not found.
37- if let Ok ( desktop) = Desktop :: new_default ( ) {
38- for selector_str in candidate_selectors. iter ( ) {
39- let try_click = async {
40- let locator = desktop. locator ( Selector :: from ( * selector_str) ) ;
41- match locator. first ( Some ( Duration :: from_millis ( 1500 ) ) ) . await {
42- Ok ( link) => link. invoke ( ) . map ( |_| true ) . unwrap_or ( false ) ,
43- Err ( _) => false ,
44- }
45- } ;
46-
47- if try_click. await {
48- info ! (
49- selector = * selector_str,
50- "Clicked service worker link to wake extension"
51- ) ;
52- // Allow devtools window to spawn and the worker to initialize
53- tokio:: time:: sleep ( Duration :: from_millis ( 800 ) ) . await ;
54- break ;
55- }
56- }
57- }
58-
59- // Restore original focus to minimize disruption
60- if let Some ( prev) = previously_focused {
61- let _ = prev. activate_window ( ) ;
62- }
63- }
64-
659/// Execute JavaScript in browser using extension bridge ONLY
6610pub async fn execute_script (
6711 browser_element : & crate :: UIElement ,
@@ -87,10 +31,9 @@ pub async fn execute_script(
8731 let ext = crate :: extension_bridge:: ExtensionBridge :: global ( ) . await ;
8832 if !ext. is_client_connected ( ) . await {
8933 info ! ( "Waiting for extension client to connect..." ) ;
90- // Try a short wait first, then attempt to wake the service worker via extensions UI,
91- // then continue to wait up to the original overall budget (~60s total)
34+ // Wait up to ~60s total for the client to connect. The MV3 service worker
35+ // will be auto-woken by the content-script handshake on page load/navigation.
9236 let mut connected = false ;
93- let mut attempted_wakeup = false ;
9437 for i in 0 ..120 {
9538 tokio:: time:: sleep ( Duration :: from_millis ( 500 ) ) . await ;
9639
@@ -100,17 +43,6 @@ pub async fn execute_script(
10043 break ;
10144 }
10245
103- // After ~4 seconds without a connection, try to wake the service worker once
104- if !attempted_wakeup && i >= 8 {
105- attempted_wakeup = true ;
106- info ! ( "Attempting to wake extension service worker via chrome://extensions" ) ;
107- wake_extension_service_worker_and_restore_focus ( previously_focused. clone ( ) ) . await ;
108-
109- // Re-focus the browser window to ensure the active tab is correct for evaluation
110- let _ = browser_element. focus ( ) ;
111- tokio:: time:: sleep ( Duration :: from_millis ( 300 ) ) . await ;
112- }
113-
11446 if i % 6 == 5 {
11547 info ! (
11648 "Still waiting for extension client... {}s" ,
0 commit comments