diff --git a/bin/test.sh b/bin/test.sh index 8edcea9db..741252d9a 100755 --- a/bin/test.sh +++ b/bin/test.sh @@ -6,4 +6,4 @@ SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" cd "$SCRIPT_DIR/.." || exit 1 -exec uv run pytest -xsv --numprocesses auto --timeout=60 --dist=loadscope tests/ci +exec uv run pytest --numprocesses auto tests/ci $1 $2 $3 diff --git a/browser_use/browser/session.py b/browser_use/browser/session.py index 637c545ab..37403cdb8 100644 --- a/browser_use/browser/session.py +++ b/browser_use/browser/session.py @@ -359,22 +359,23 @@ class BrowserSession(BaseModel): # trying to launch/kill browsers at the same time is an easy way to trash an entire user_data_dir # it's worth the 1s or 2s of delay in the worst case to avoid race conditions, user_data_dir can be a few GBs # Use timeout to prevent indefinite waiting on lock acquisition - async with asyncio.timeout(30): # 30 second timeout for stop operations + + # save cookies to disk if cookies_file or storage_state is configured + # but only if the browser context is still connected + if self.browser_context: + try: + await asyncio.wait_for(self.save_storage_state(), timeout=5) + except Exception as e: + self.logger.warning(f'⚠️ Failed to save auth storage state before stopping: {type(e).__name__}: {e}') + + if self.browser_profile.keep_alive: + self.logger.info( + '🕊️ BrowserSession.stop() called but keep_alive=True, leaving the browser running. Use .kill() to force close.' + ) + return # nothing to do if keep_alive=True, leave the browser running + + async with asyncio.timeout(60): # 60 second timeout for all stop operations async with self._start_lock: - # save cookies to disk if cookies_file or storage_state is configured - # but only if the browser context is still connected - if self.browser_context: - try: - await asyncio.wait_for(self.save_storage_state(), timeout=5) - except Exception as e: - self.logger.warning(f'⚠️ Failed to save auth storage state before stopping: {type(e).__name__}: {e}') - - if self.browser_profile.keep_alive: - self.logger.info( - '🕊️ BrowserSession.stop() called but keep_alive=True, leaving the browser running. Use .kill() to force close.' - ) - return # nothing to do if keep_alive=True, leave the browser running - if self.browser_context or self.browser: self.logger.info(f'🛑 Closing {self._connection_str} browser context {self.browser or self.browser_context}') @@ -413,7 +414,7 @@ class BrowserSession(BaseModel): try: # Add timeout to prevent hanging on close if context is already closed try: - async with asyncio.timeout(30): # 30 second timeout for close operation + async with asyncio.timeout(45): # long-ish to give browser time to save video and trace files # IMPORTANT: Close context first to ensure HAR/video files are saved if self.browser_context: await self.browser_context.close() @@ -2601,10 +2602,10 @@ class BrowserSession(BaseModel): desired_height = dimensions['height'] + viewport_expansion capped_height = min(desired_height, MAX_SCREENSHOT_HEIGHT) - if desired_height > capped_height: - self.logger.debug( - f'📐 Expanded viewport {desired_height}px exceeds max {capped_height}px limit for screenshots, taking top {capped_height}px only' - ) + # if desired_height > capped_height: + # self.logger.debug( + # f'📐 Page viewport {desired_height}px exceeds max {capped_height}px limit for screenshots, taking top {capped_height}px only' + # ) # 3. Expand the viewport if we are using one original_viewport = page.viewport_size @@ -2613,13 +2614,13 @@ class BrowserSession(BaseModel): # if we're already using a viewport, temporarily expand it to the desired size for the screenshot await asyncio.wait_for( page.set_viewport_size({'width': capped_width, 'height': desired_height}), - timeout=self.browser_profile.default_timeout or 20000, + timeout=(self.browser_profile.default_timeout or 20000) / 1000, # Convert ms to seconds ) # intentionally set short because we want this to be noisy if it's slowing us down else: # In headless mode without viewport, we always need to set one temporarily before taking a screenshot to limit rendering resource usage await asyncio.wait_for( page.set_viewport_size({'width': capped_width, 'height': desired_height}), - timeout=self.browser_profile.default_timeout or 20000, + timeout=(self.browser_profile.default_timeout or 20000) / 1000, # Convert ms to seconds ) except Exception as e: self.logger.warning( @@ -2695,7 +2696,7 @@ class BrowserSession(BaseModel): try: await asyncio.wait_for( page.set_viewport_size(original_viewport), - timeout=self.browser_profile.default_timeout or 20000, + timeout=(self.browser_profile.default_timeout or 20000) / 1000, # Convert ms to seconds ) except Exception as e: self.logger.warning( diff --git a/pyproject.toml b/pyproject.toml index e380d7c0b..03ce808d7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -143,7 +143,7 @@ testpaths = [ "tests" ] python_files = ["test_*.py", "*_test.py"] -addopts = "-v --strict-markers --tb=short --dist=loadscope" +addopts = "-svx --strict-markers --tb=short --dist=loadscope --full-trace" log_cli = true log_cli_format = "%(levelname)-8s [%(name)s] %(message)s" filterwarnings = [