Merge pull request #439 from Br1an67/feat/issue-108-web-form-handling
feat: add support for select, textarea, and file upload in web forms
This commit is contained in:
+34
-3
@@ -2,7 +2,7 @@ from selenium import webdriver
|
|||||||
from selenium.webdriver.chrome.service import Service
|
from selenium.webdriver.chrome.service import Service
|
||||||
from selenium.webdriver.chrome.options import Options
|
from selenium.webdriver.chrome.options import Options
|
||||||
from selenium.webdriver.common.by import By
|
from selenium.webdriver.common.by import By
|
||||||
from selenium.webdriver.support.ui import WebDriverWait
|
from selenium.webdriver.support.ui import WebDriverWait, Select
|
||||||
from selenium.webdriver.support import expected_conditions as EC
|
from selenium.webdriver.support import expected_conditions as EC
|
||||||
from selenium.common.exceptions import TimeoutException, WebDriverException
|
from selenium.common.exceptions import TimeoutException, WebDriverException
|
||||||
from selenium.webdriver.common.action_chains import ActionChains
|
from selenium.webdriver.common.action_chains import ActionChains
|
||||||
@@ -530,7 +530,16 @@ class Browser:
|
|||||||
if input_type in ["hidden", "submit", "button", "image"] or not element["displayed"]:
|
if input_type in ["hidden", "submit", "button", "image"] or not element["displayed"]:
|
||||||
continue
|
continue
|
||||||
input_name = element.get("text") or element.get("id") or input_type
|
input_name = element.get("text") or element.get("id") or input_type
|
||||||
if input_type == "checkbox" or input_type == "radio":
|
if input_type == "select":
|
||||||
|
options = element.get("options", [])
|
||||||
|
options_str = ", ".join(opt["text"] for opt in options if opt["text"])
|
||||||
|
selected = next((opt["text"] for opt in options if opt.get("selected")), "")
|
||||||
|
form_strings.append(f"[{input_name}](select: {selected}) options: [{options_str}]")
|
||||||
|
elif input_type == "textarea":
|
||||||
|
form_strings.append(f"[{input_name}]("")")
|
||||||
|
elif input_type == "file":
|
||||||
|
form_strings.append(f"[{input_name}](file: )")
|
||||||
|
elif input_type == "checkbox" or input_type == "radio":
|
||||||
try:
|
try:
|
||||||
checked_status = "checked" if element.is_selected() else "unchecked"
|
checked_status = "checked" if element.is_selected() else "unchecked"
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -694,7 +703,29 @@ class Browser:
|
|||||||
self.logger.warning(f"Element '{name}' is not interactable (not displayed or disabled)")
|
self.logger.warning(f"Element '{name}' is not interactable (not displayed or disabled)")
|
||||||
continue
|
continue
|
||||||
input_type = (element.get_attribute("type") or "text").lower()
|
input_type = (element.get_attribute("type") or "text").lower()
|
||||||
if input_type in ["checkbox", "radio"]:
|
tag_name = (element.tag_name or "").lower()
|
||||||
|
if tag_name == "select":
|
||||||
|
try:
|
||||||
|
select = Select(element)
|
||||||
|
select.select_by_visible_text(value)
|
||||||
|
self.logger.info(f"Selected '{value}' for {name}")
|
||||||
|
except Exception:
|
||||||
|
try:
|
||||||
|
select.select_by_value(value)
|
||||||
|
self.logger.info(f"Selected value '{value}' for {name}")
|
||||||
|
except Exception as sel_e:
|
||||||
|
self.logger.warning(f"Could not select '{value}' for {name}: {sel_e}")
|
||||||
|
elif tag_name == "textarea":
|
||||||
|
element.clear()
|
||||||
|
element.send_keys(value)
|
||||||
|
self.logger.info(f"Filled textarea {name}")
|
||||||
|
elif input_type == "file":
|
||||||
|
if os.path.isabs(value) and os.path.exists(value):
|
||||||
|
element.send_keys(value)
|
||||||
|
self.logger.info(f"Uploaded file '{value}' for {name}")
|
||||||
|
else:
|
||||||
|
self.logger.warning(f"File not found: {value}")
|
||||||
|
elif input_type in ["checkbox", "radio"]:
|
||||||
is_checked = element.is_selected()
|
is_checked = element.is_selected()
|
||||||
should_be_checked = value.lower() == "checked"
|
should_be_checked = value.lower() == "checked"
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,37 @@ function findInputs(element, result = []) {
|
|||||||
displayed: isElementDisplayed(input)
|
displayed: isElementDisplayed(input)
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
// Find all <select> elements (dropdowns / multi-choice)
|
||||||
|
const selects = element.querySelectorAll('select');
|
||||||
|
selects.forEach(select => {
|
||||||
|
const options = Array.from(select.options).map(opt => ({
|
||||||
|
value: opt.value,
|
||||||
|
text: opt.textContent.trim(),
|
||||||
|
selected: opt.selected
|
||||||
|
}));
|
||||||
|
result.push({
|
||||||
|
tagName: select.tagName,
|
||||||
|
text: select.name || '',
|
||||||
|
type: 'select',
|
||||||
|
class: select.className || '',
|
||||||
|
xpath: getXPath(select),
|
||||||
|
displayed: isElementDisplayed(select),
|
||||||
|
multiple: select.multiple,
|
||||||
|
options: options
|
||||||
|
});
|
||||||
|
});
|
||||||
|
// Find all <textarea> elements
|
||||||
|
const textareas = element.querySelectorAll('textarea');
|
||||||
|
textareas.forEach(textarea => {
|
||||||
|
result.push({
|
||||||
|
tagName: textarea.tagName,
|
||||||
|
text: textarea.name || '',
|
||||||
|
type: 'textarea',
|
||||||
|
class: textarea.className || '',
|
||||||
|
xpath: getXPath(textarea),
|
||||||
|
displayed: isElementDisplayed(textarea)
|
||||||
|
});
|
||||||
|
});
|
||||||
const allElements = element.querySelectorAll('*');
|
const allElements = element.querySelectorAll('*');
|
||||||
allElements.forEach(el => {
|
allElements.forEach(el => {
|
||||||
if (el.shadowRoot) {
|
if (el.shadowRoot) {
|
||||||
|
|||||||
Reference in New Issue
Block a user