This commit is contained in:
@@ -289,10 +289,12 @@ async def interactions_service(
|
||||
if isinstance(interaction, dict):
|
||||
action = interaction.get("action")
|
||||
selector = interaction.get("selector")
|
||||
xpath_selector = interaction.get("xpath_selector")
|
||||
text = interaction.get("text")
|
||||
else:
|
||||
action = getattr(interaction, "action", None)
|
||||
selector = getattr(interaction, "selector", None)
|
||||
xpath_selector = getattr(interaction, "xpath_selector", None)
|
||||
text = getattr(interaction, "text", None)
|
||||
# Coordinates may be present on interaction models.
|
||||
x = getattr(interaction, "x", None)
|
||||
@@ -305,38 +307,77 @@ async def interactions_service(
|
||||
if not action:
|
||||
raise ValueError("Interaction must contain an action")
|
||||
|
||||
# Prefer selector-based interactions when selector is provided.
|
||||
if selector:
|
||||
# Prefer selector-based interactions when selectors are provided (CSS first, then XPath).
|
||||
if selector or xpath_selector:
|
||||
if action == "click":
|
||||
await page.wait_for_selector(selector, timeout=30000)
|
||||
# Avoid Playwright auto-scrolling: click via DOM.
|
||||
await page.evaluate(
|
||||
"""(sel) => {
|
||||
const el = document.querySelector(sel);
|
||||
if (!el) throw new Error(`No element for selector: ${sel}`);
|
||||
el.click();
|
||||
}""",
|
||||
selector,
|
||||
)
|
||||
if selector:
|
||||
await page.wait_for_selector(selector, timeout=30000)
|
||||
# Avoid Playwright auto-scrolling: click via DOM.
|
||||
await page.evaluate(
|
||||
"""(sel) => {
|
||||
const el = document.querySelector(sel);
|
||||
if (!el) throw new Error(`No element for selector: ${sel}`);
|
||||
el.click();
|
||||
}""",
|
||||
selector,
|
||||
)
|
||||
else:
|
||||
await page.wait_for_selector(f"xpath={xpath_selector}", timeout=30000)
|
||||
await page.evaluate(
|
||||
"""(xpath) => {
|
||||
const el = document.evaluate(
|
||||
xpath,
|
||||
document,
|
||||
null,
|
||||
XPathResult.FIRST_ORDERED_NODE_TYPE,
|
||||
null
|
||||
).singleNodeValue;
|
||||
if (!el) throw new Error(`No element for xpath: ${xpath}`);
|
||||
el.click();
|
||||
}""",
|
||||
xpath_selector,
|
||||
)
|
||||
|
||||
elif action == "type":
|
||||
if text is None:
|
||||
raise ValueError("Type interaction must contain text")
|
||||
await page.wait_for_selector(selector, timeout=30000)
|
||||
# Avoid Playwright auto-scrolling: focus/fill via DOM.
|
||||
await page.evaluate(
|
||||
"""({ sel, value }) => {
|
||||
const el = document.querySelector(sel);
|
||||
if (!el) throw new Error(`No element for selector: ${sel}`);
|
||||
el.focus?.();
|
||||
if ('value' in el) {
|
||||
el.value = value;
|
||||
el.dispatchEvent(new Event('input', { bubbles: true }));
|
||||
el.dispatchEvent(new Event('change', { bubbles: true }));
|
||||
}
|
||||
}""",
|
||||
{"sel": selector, "value": text},
|
||||
)
|
||||
if selector:
|
||||
await page.wait_for_selector(selector, timeout=30000)
|
||||
# Avoid Playwright auto-scrolling: focus/fill via DOM.
|
||||
await page.evaluate(
|
||||
"""({ sel, value }) => {
|
||||
const el = document.querySelector(sel);
|
||||
if (!el) throw new Error(`No element for selector: ${sel}`);
|
||||
el.focus?.();
|
||||
if ('value' in el) {
|
||||
el.value = value;
|
||||
el.dispatchEvent(new Event('input', { bubbles: true }));
|
||||
el.dispatchEvent(new Event('change', { bubbles: true }));
|
||||
}
|
||||
}""",
|
||||
{"sel": selector, "value": text},
|
||||
)
|
||||
else:
|
||||
await page.wait_for_selector(f"xpath={xpath_selector}", timeout=30000)
|
||||
await page.evaluate(
|
||||
"""({ xpath, value }) => {
|
||||
const el = document.evaluate(
|
||||
xpath,
|
||||
document,
|
||||
null,
|
||||
XPathResult.FIRST_ORDERED_NODE_TYPE,
|
||||
null
|
||||
).singleNodeValue;
|
||||
if (!el) throw new Error(`No element for xpath: ${xpath}`);
|
||||
el.focus?.();
|
||||
if ('value' in el) {
|
||||
el.value = value;
|
||||
el.dispatchEvent(new Event('input', { bubbles: true }));
|
||||
el.dispatchEvent(new Event('change', { bubbles: true }));
|
||||
}
|
||||
}""",
|
||||
{"xpath": xpath_selector, "value": text},
|
||||
)
|
||||
|
||||
else:
|
||||
raise ValueError(f"Unknown interaction action: {action}")
|
||||
@@ -383,7 +424,7 @@ async def interactions_service(
|
||||
raise ValueError(f"Unknown interaction action: {action}")
|
||||
|
||||
else:
|
||||
raise ValueError("Interaction must contain either selector or x/y coordinates")
|
||||
raise ValueError("Interaction must contain selector, xpath_selector, or x/y coordinates")
|
||||
|
||||
# Let the UI settle after each action.
|
||||
await page.wait_for_timeout(1000)
|
||||
|
||||
Reference in New Issue
Block a user