implement wait_for_xpath function to enhance XPath handling in interactions_service, ensuring proper validation and timeout management
Build and Push Docker Images / build-and-push (push) Successful in 22s
Build and Push Docker Images / build-and-push (push) Successful in 22s
This commit is contained in:
@@ -307,6 +307,27 @@ async def interactions_service(
|
|||||||
if not action:
|
if not action:
|
||||||
raise ValueError("Interaction must contain an action")
|
raise ValueError("Interaction must contain an action")
|
||||||
|
|
||||||
|
async def wait_for_xpath(xp: str, timeout_ms: int = 30000) -> None:
|
||||||
|
# Accept both raw XPath ("//div") and Playwright-style ("xpath=//div").
|
||||||
|
normalized = xp[len("xpath=") :] if xp.startswith("xpath=") else xp
|
||||||
|
await page.wait_for_function(
|
||||||
|
"""(xpath) => {
|
||||||
|
try {
|
||||||
|
return !!document.evaluate(
|
||||||
|
xpath,
|
||||||
|
document,
|
||||||
|
null,
|
||||||
|
XPathResult.FIRST_ORDERED_NODE_TYPE,
|
||||||
|
null
|
||||||
|
).singleNodeValue;
|
||||||
|
} catch (e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}""",
|
||||||
|
normalized,
|
||||||
|
timeout=timeout_ms,
|
||||||
|
)
|
||||||
|
|
||||||
# Prefer selector-based interactions when selectors are provided (CSS first, then XPath).
|
# Prefer selector-based interactions when selectors are provided (CSS first, then XPath).
|
||||||
if selector or xpath_selector:
|
if selector or xpath_selector:
|
||||||
if action == "click":
|
if action == "click":
|
||||||
@@ -322,7 +343,9 @@ async def interactions_service(
|
|||||||
selector,
|
selector,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
await page.wait_for_selector(f"xpath={xpath_selector}", timeout=30000)
|
if not xpath_selector:
|
||||||
|
raise ValueError("xpath_selector must be a non-empty string")
|
||||||
|
await wait_for_xpath(xpath_selector, timeout_ms=30000)
|
||||||
await page.evaluate(
|
await page.evaluate(
|
||||||
"""(xpath) => {
|
"""(xpath) => {
|
||||||
const el = document.evaluate(
|
const el = document.evaluate(
|
||||||
@@ -335,7 +358,7 @@ async def interactions_service(
|
|||||||
if (!el) throw new Error(`No element for xpath: ${xpath}`);
|
if (!el) throw new Error(`No element for xpath: ${xpath}`);
|
||||||
el.click();
|
el.click();
|
||||||
}""",
|
}""",
|
||||||
xpath_selector,
|
xpath_selector[len("xpath=") :] if xpath_selector.startswith("xpath=") else xpath_selector,
|
||||||
)
|
)
|
||||||
|
|
||||||
elif action == "type":
|
elif action == "type":
|
||||||
@@ -358,7 +381,10 @@ async def interactions_service(
|
|||||||
{"sel": selector, "value": text},
|
{"sel": selector, "value": text},
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
await page.wait_for_selector(f"xpath={xpath_selector}", timeout=30000)
|
if not xpath_selector:
|
||||||
|
raise ValueError("xpath_selector must be a non-empty string")
|
||||||
|
await wait_for_xpath(xpath_selector, timeout_ms=30000)
|
||||||
|
normalized_xpath = xpath_selector[len("xpath=") :] if xpath_selector.startswith("xpath=") else xpath_selector
|
||||||
await page.evaluate(
|
await page.evaluate(
|
||||||
"""({ xpath, value }) => {
|
"""({ xpath, value }) => {
|
||||||
const el = document.evaluate(
|
const el = document.evaluate(
|
||||||
@@ -376,7 +402,7 @@ async def interactions_service(
|
|||||||
el.dispatchEvent(new Event('change', { bubbles: true }));
|
el.dispatchEvent(new Event('change', { bubbles: true }));
|
||||||
}
|
}
|
||||||
}""",
|
}""",
|
||||||
{"xpath": xpath_selector, "value": text},
|
{"xpath": normalized_xpath, "value": text},
|
||||||
)
|
)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
|||||||
Reference in New Issue
Block a user