Compare commits

...

2 Commits

Author SHA1 Message Date
dgtlmoon
0d4a410cd7 Convert to async
Some checks failed
Publish Python 🐍distribution 📦 to PyPI and TestPyPI / Build distribution 📦 (push) Has been cancelled
ChangeDetection.io App Test / lint-code (push) Has been cancelled
Publish Python 🐍distribution 📦 to PyPI and TestPyPI / Test the built 📦 package works basically. (push) Has been cancelled
Publish Python 🐍distribution 📦 to PyPI and TestPyPI / Publish Python 🐍 distribution 📦 to PyPI (push) Has been cancelled
ChangeDetection.io App Test / test-application-3-10 (push) Has been cancelled
ChangeDetection.io App Test / test-application-3-11 (push) Has been cancelled
ChangeDetection.io App Test / test-application-3-12 (push) Has been cancelled
ChangeDetection.io App Test / test-application-3-13 (push) Has been cancelled
2025-06-04 08:38:25 +02:00
dgtlmoon
81a8cabbd4 Re #3194 handle execution context changes better in browsersteps 2025-06-04 07:46:43 +02:00

View File

@@ -1,8 +1,6 @@
import os
import time
import re
import sys
import traceback
from random import randint
from loguru import logger
@@ -92,8 +90,32 @@ class steppable_browser_interface():
if optional_value and ('{%' in optional_value or '{{' in optional_value):
optional_value = jinja_render(template_str=optional_value)
# Trigger click and cautiously handle potential navigation
# This means the page redirects/reloads/changes JS etc etc
if call_action_name.startswith('click_'):
try:
# Set up navigation expectation before the click (like sync version)
async with self.page.expect_event("framenavigated", timeout=3000) as navigation_info:
await action_handler(selector, optional_value)
# Check if navigation actually occurred
try:
await navigation_info.value # This waits for the navigation promise
logger.debug(f"Navigation occurred on {call_action_name}.")
except Exception:
logger.debug(f"No navigation occurred within timeout when calling {call_action_name}, that's OK, continuing.")
except Exception as e:
# If expect_event itself times out, that means no navigation occurred - that's OK
if "framenavigated" in str(e) and "exceeded" in str(e):
logger.debug(f"No navigation occurred within timeout when calling {call_action_name}, that's OK, continuing.")
else:
raise e
else:
# Some other action that probably a navigation is not expected
await action_handler(selector, optional_value)
await action_handler(selector, optional_value)
# Safely wait for timeout
await self.page.wait_for_timeout(1.5 * 1000)
logger.debug(f"Call action done in {time.time()-now:.2f}s")
@@ -428,6 +450,9 @@ class browsersteps_live_ui(steppable_browser_interface):
try:
# Get screenshot first
screenshot = await capture_full_page_async(page=self.page)
if not screenshot:
logger.error("No screenshot was retrieved :((")
logger.debug(f"Time to get screenshot from browser {time.time() - now:.2f}s")
# Then get interactive elements
@@ -450,6 +475,12 @@ class browsersteps_live_ui(steppable_browser_interface):
except Exception as e:
logger.error(f"Error getting current state: {str(e)}")
# If the page has navigated (common with logins) then the context is destroyed on navigation, continue
# I'm not sure that this is required anymore because we have the "expect navigation wrapper" at the top
if "Execution context was destroyed" in str(e):
logger.debug("Execution context was destroyed, most likely because of navigation, continuing...")
pass
# Attempt recovery - force garbage collection
try:
await self.page.request_gc()