@@ -112,41 +112,116 @@ impl WebDriver {
112112 /// The spawned process will be automatically managed and can be stopped
113113 /// using the `stop()` method.
114114 pub ( crate ) fn spawn_webdriver ( & mut self ) {
115- info ! ( "Spawning {WEBDRIVER_BIN}" ) ;
115+ let port = self . inner . lock ( ) . unwrap ( ) . webdriver_port ;
116+ let driver_path = self . inner . lock ( ) . unwrap ( ) . driver_path . clone ( ) ;
117+
118+ info ! ( "Spawning {WEBDRIVER_BIN} on port {} with path: {:?}" , port, driver_path) ;
119+
120+ // Check if port is already in use
121+ if Self :: is_webdriver_running ( port) {
122+ warn ! ( "WebDriver already running on port {}, attempting to connect instead" , port) ;
123+ return ;
124+ }
125+
126+ // Check if the driver binary exists and is executable
127+ if !driver_path. exists ( ) {
128+ error ! ( "WebDriver binary does not exist: {:?}" , driver_path) ;
129+ return ;
130+ }
116131
117132 // Spawn the process in the main thread to get the Child handle
118- let mut command = Command :: new ( self . inner . lock ( ) . unwrap ( ) . driver_path . clone ( ) ) ;
133+ let mut command = Command :: new ( & driver_path) ;
134+ command
135+ . arg ( format ! ( "--port={}" , port) ) ;
136+
137+ // Add verbose flag only for chromedriver (geckodriver doesn't support it)
138+ #[ cfg( feature = "chromedriver" ) ]
139+ {
140+ command. arg ( "--verbose" ) ; // Enable verbose logging for debugging
141+ }
142+
119143 command
120- . arg ( format ! ( "--port={}" , self . inner. lock( ) . unwrap( ) . webdriver_port) )
121144 . stdin ( Stdio :: piped ( ) )
122145 . stdout ( Stdio :: piped ( ) )
123146 . stderr ( Stdio :: piped ( ) ) ;
124147
148+ info ! ( "Executing command: {:?} {:?}" , command. get_program( ) , command. get_args( ) ) ;
149+
125150 let mut child = match command. spawn ( ) {
126- Ok ( c) => c,
151+ Ok ( c) => {
152+ info ! ( "Successfully spawned {WEBDRIVER_BIN} with PID: {}" , c. id( ) ) ;
153+ c
154+ }
127155 Err ( e) => {
128156 error ! ( "Failed to spawn '{WEBDRIVER_BIN}': {e}" ) ;
157+ error ! ( "Command was: {:?} {:?}" , command. get_program( ) , command. get_args( ) ) ;
129158 return ;
130159 }
131160 } ;
132161
133162 // Spawn a thread to handle the process stderr output (logging only)
134163 if let Some ( stderr) = child. stderr . take ( ) {
164+ let port_for_logging = port;
135165 thread:: spawn ( move || {
166+ info ! ( "Starting stderr monitoring for WebDriver on port {}" , port_for_logging) ;
136167 let stderr_lines = BufReader :: new ( stderr) . lines ( ) ;
137168 for line in stderr_lines {
138169 if let Ok ( line) = line {
139- debug ! ( "{line}" ) ;
170+ debug ! ( "WebDriver[{}] stderr: {}" , port_for_logging, line) ;
171+ }
172+ }
173+ info ! ( "Stderr monitoring ended for WebDriver on port {}" , port_for_logging) ;
174+ } ) ;
175+ }
176+
177+ // Spawn a thread to handle the process stdout output (logging only)
178+ if let Some ( stdout) = child. stdout . take ( ) {
179+ let port_for_logging = port;
180+ thread:: spawn ( move || {
181+ info ! ( "Starting stdout monitoring for WebDriver on port {}" , port_for_logging) ;
182+ let stdout_lines = BufReader :: new ( stdout) . lines ( ) ;
183+ for line in stdout_lines {
184+ if let Ok ( line) = line {
185+ debug ! ( "WebDriver[{}] stdout: {}" , port_for_logging, line) ;
140186 }
141187 }
188+ info ! ( "Stdout monitoring ended for WebDriver on port {}" , port_for_logging) ;
142189 } ) ;
143190 }
144191
145- // Store the Child handle (without stderr)
192+ // Store the Child handle (without stderr/stdout )
146193 {
147194 let mut inner = self . inner . lock ( ) . unwrap ( ) ;
148195 inner. webdriver_child = Some ( child) ;
149196 }
197+
198+ info ! ( "WebDriver process stored, waiting for it to become ready..." ) ;
199+
200+ // Wait for WebDriver to become ready with timeout
201+ let start_time = std:: time:: Instant :: now ( ) ;
202+ let timeout_duration = std:: time:: Duration :: from_secs ( 30 ) ;
203+
204+ while start_time. elapsed ( ) < timeout_duration {
205+ if Self :: is_webdriver_running ( port) {
206+ info ! ( "WebDriver is ready on port {} after {:?}" , port, start_time. elapsed( ) ) ;
207+ return ;
208+ }
209+
210+ // Check if process is still alive
211+ {
212+ let mut inner = self . inner . lock ( ) . unwrap ( ) ;
213+ if let Some ( child) = inner. webdriver_child . as_mut ( ) {
214+ if let Ok ( Some ( _) ) = child. try_wait ( ) {
215+ error ! ( "WebDriver process exited before becoming ready on port {}" , port) ;
216+ return ;
217+ }
218+ }
219+ }
220+
221+ std:: thread:: sleep ( std:: time:: Duration :: from_millis ( 100 ) ) ;
222+ }
223+
224+ error ! ( "WebDriver failed to become ready on port {} within {:?}" , port, timeout_duration) ;
150225 }
151226
152227 /// Stops the WebDriver process
@@ -193,6 +268,47 @@ impl WebDriver {
193268 Ok ( ( ) )
194269 }
195270
271+ /// Get diagnostic information about the WebDriver process
272+ ///
273+ /// This method provides detailed information about the WebDriver process
274+ /// for debugging purposes.
275+ ///
276+ /// # Returns
277+ ///
278+ /// Returns a string with diagnostic information
279+ pub fn get_diagnostics ( & self ) -> String {
280+ let mut inner = self . inner . lock ( ) . unwrap ( ) ;
281+ let mut diagnostics = String :: new ( ) ;
282+
283+ diagnostics. push_str ( & format ! ( "WebDriver Diagnostics:\n " ) ) ;
284+ diagnostics. push_str ( & format ! ( " Port: {}\n " , inner. webdriver_port) ) ;
285+ diagnostics. push_str ( & format ! ( " Driver Path: {:?}\n " , inner. driver_path) ) ;
286+ diagnostics. push_str ( & format ! ( " Is External: {}\n " , inner. is_external) ) ;
287+
288+ if let Some ( child) = inner. webdriver_child . as_mut ( ) {
289+ diagnostics. push_str ( & format ! ( " Process ID: {}\n " , child. id( ) ) ) ;
290+
291+ // Check if process is still running
292+ match child. try_wait ( ) {
293+ Ok ( None ) => diagnostics. push_str ( " Process Status: Running\n " ) ,
294+ Ok ( Some ( status) ) => diagnostics. push_str ( & format ! ( " Process Status: Exited with {:?}\n " , status) ) ,
295+ Err ( e) => diagnostics. push_str ( & format ! ( " Process Status: Error checking status: {}\n " , e) ) ,
296+ }
297+ } else {
298+ diagnostics. push_str ( " Process ID: None (no child process)\n " ) ;
299+ }
300+
301+ // Check if WebDriver is responding
302+ let is_running = Self :: is_webdriver_running ( inner. webdriver_port ) ;
303+ diagnostics. push_str ( & format ! ( " WebDriver Responding: {}\n " , is_running) ) ;
304+
305+ // Check port availability
306+ let url = format ! ( "{WEBDRIVER_URL}:{}/status" , inner. webdriver_port) ;
307+ diagnostics. push_str ( & format ! ( " Status URL: {}\n " , url) ) ;
308+
309+ diagnostics
310+ }
311+
196312 /// Create a new WebDriver instance, connecting to existing if available
197313 ///
198314 /// This method provides WebDriver management:
@@ -213,14 +329,44 @@ impl WebDriver {
213329 /// - `Ok(webdriver)` - Successfully created or connected to WebDriver
214330 /// - `Err(e)` - Failed to create or connect to WebDriver
215331 pub ( crate ) fn new_or_connect ( port : u32 ) -> Result < Self > {
332+ info ! ( "Attempting to create or connect to WebDriver on port {}" , port) ;
333+
334+ // Check if port is already in use by another process
335+ debug ! ( "Checking if port {} is available..." , port) ;
336+
216337 if Self :: is_webdriver_running ( port) {
217- debug ! ( "WebDriver already running on port {port}, connecting to existing session" ) ;
218- Self :: connect_to_existing ( port)
338+ info ! ( "WebDriver already running on port {port}, connecting to existing session" ) ;
339+ match Self :: connect_to_existing ( port) {
340+ Ok ( wd) => {
341+ info ! ( "Successfully connected to existing WebDriver on port {}" , port) ;
342+ Ok ( wd)
343+ }
344+ Err ( e) => {
345+ error ! ( "Failed to connect to existing WebDriver on port {}: {}" , port, e) ;
346+ Err ( e)
347+ }
348+ }
219349 } else {
220- debug ! ( "No WebDriver running on port {port}, creating new instance and spawning" ) ;
221- let mut wd = Self :: new ( port) ?;
222- wd. spawn_webdriver ( ) ;
223- Ok ( wd)
350+ info ! ( "No WebDriver running on port {port}, creating new instance and spawning" ) ;
351+ match Self :: new ( port) {
352+ Ok ( mut wd) => {
353+ wd. spawn_webdriver ( ) ;
354+
355+ // Verify that the WebDriver is now running
356+ if Self :: is_webdriver_running ( port) {
357+ info ! ( "Successfully created and started WebDriver on port {}" , port) ;
358+ Ok ( wd)
359+ } else {
360+ let diagnostics = wd. get_diagnostics ( ) ;
361+ error ! ( "WebDriver failed to start properly on port {}. Diagnostics:\n {}" , port, diagnostics) ;
362+ Err ( anyhow ! ( "WebDriver failed to start properly on port {}" , port) )
363+ }
364+ }
365+ Err ( e) => {
366+ error ! ( "Failed to create WebDriver instance on port {}: {}" , port, e) ;
367+ Err ( e)
368+ }
369+ }
224370 }
225371 }
226372
@@ -241,12 +387,35 @@ impl WebDriver {
241387 /// Returns `true` if WebDriver is running and ready, `false` otherwise.
242388 pub ( crate ) fn is_webdriver_running ( port : u32 ) -> bool {
243389 let url = format ! ( "{WEBDRIVER_URL}:{port}/status" ) ;
244- reqwest:: blocking:: get ( & url)
245- . ok ( )
246- . filter ( |response| response. status ( ) . as_u16 ( ) == 200 )
247- . and_then ( |response| response. text ( ) . ok ( ) )
248- . map ( |text| text. contains ( "ready" ) )
249- . unwrap_or ( false )
390+
391+ debug ! ( "Checking WebDriver status at: {}" , url) ;
392+
393+ match reqwest:: blocking:: get ( & url) {
394+ Ok ( response) => {
395+ debug ! ( "WebDriver status response: {} {}" , response. status( ) , response. status( ) . as_u16( ) ) ;
396+ if response. status ( ) . as_u16 ( ) == 200 {
397+ match response. text ( ) {
398+ Ok ( text) => {
399+ debug ! ( "WebDriver status response body: {}" , text) ;
400+ let is_ready = text. contains ( "ready" ) ;
401+ debug ! ( "WebDriver ready: {}" , is_ready) ;
402+ is_ready
403+ }
404+ Err ( e) => {
405+ debug ! ( "Failed to read WebDriver status response: {}" , e) ;
406+ false
407+ }
408+ }
409+ } else {
410+ debug ! ( "WebDriver status returned non-200 status: {}" , response. status( ) ) ;
411+ false
412+ }
413+ }
414+ Err ( e) => {
415+ debug ! ( "Failed to connect to WebDriver at {}: {}" , url, e) ;
416+ false
417+ }
418+ }
250419 }
251420
252421 /// Connect to an existing WebDriver session
0 commit comments