diff --git a/__pycache__/main.cpython-313.pyc b/__pycache__/main.cpython-313.pyc new file mode 100644 index 0000000..b912e75 Binary files /dev/null and b/__pycache__/main.cpython-313.pyc differ diff --git a/automation_config.json b/automation_config.json new file mode 100644 index 0000000..d26f473 --- /dev/null +++ b/automation_config.json @@ -0,0 +1,12 @@ +{ + "login": { + "username": "pyman", + "password": "Pymaster123!" + }, + "textbox": { + "fullname": "PyMan Smith", + "email": "pyman@example.com", + "current_address": "123 Main St, New York, NY 10001", + "permanent_address": "456 Oak Ave, Los Angeles, CA 90210" + } +} \ No newline at end of file diff --git a/gui.py b/gui.py new file mode 100644 index 0000000..e03180d --- /dev/null +++ b/gui.py @@ -0,0 +1,321 @@ +import tkinter as tk +from tkinter import ttk, messagebox +import json +from selenium import webdriver +from webdriver_manager.chrome import ChromeDriverManager +from selenium.webdriver.chrome.service import Service +from selenium.webdriver.support.ui import WebDriverWait +from selenium.webdriver.support import expected_conditions as EC + +class AutomationGUI: + def __init__(self, root): + self.root = root + self.root.title("Selenium Automation GUI") + self.root.geometry("800x600") + + self.driver = None + self.elements_data = [] + + # Config button + config_btn = tk.Button(root, text="Configure Automation", command=self.open_config) + config_btn.pack(pady=10) + + # Start session button (FIRST - navigate to site) + start_btn = tk.Button(root, text="Scrape Current Page Elements", command=self.start_session) + start_btn.pack(pady=10) + + + + # Load button (load from JSON) + load_btn = tk.Button(root, text="Load Elements from File", command=self.load_elements) + load_btn.pack(pady=5) + + # Treeview to display elements + self.tree = ttk.Treeview(root, columns=("Tag", "ID", "Text", "XPath"), height=15) + self.tree.column("#0", width=50) + self.tree.column("Tag", width=60) + self.tree.column("ID", width=150) + self.tree.column("Text", width=200) + self.tree.column("XPath", width=300) + + self.tree.heading("#0", text="Index") + self.tree.heading("Tag", text="Tag") + self.tree.heading("ID", text="ID") + self.tree.heading("Text", text="Text") + self.tree.heading("XPath", text="XPath") + + self.tree.pack(fill=tk.BOTH, expand=True, padx=10, pady=10) + + # Click button + click_btn = tk.Button(root, text="Click Selected Element", command=self.click_element) + click_btn.pack(pady=5) + + # Close browser button + close_btn = tk.Button(root, text="Close Browser", command=self.close_browser) + close_btn.pack(pady=5) + + # Run automation button + run_auto_btn = tk.Button(root, text="Run Full Automation", command=self.run_automation) + run_auto_btn.pack(pady=10) + + def start_session(self): + """Scrape elements from the current page (browser must be running)""" + if not self.driver: + messagebox.showwarning("Warning", "No active browser session. Run automation first or open a browser manually.") + return + + try: + # Scrape elements from current page + self.scrape_elements() + messagebox.showinfo("Success", "Elements scraped and loaded into table!") + + except Exception as e: + messagebox.showerror("Error", f"Failed to scrape elements: {str(e)}") + + def scrape_elements(self): + """Extract elements from current page and save to JSON""" + try: + script = """ + function getElementXPath(element) { + if (element.id !== '') + return "//*[@id='" + element.id + "']"; + if (element === document.body) + return "//" + element.tagName.toLowerCase(); + + var ix = 0; + var siblings = element.parentNode.childNodes; + for (var i = 0; i < siblings.length; i++) { + var sibling = siblings[i]; + if (sibling === element) + return getElementXPath(element.parentNode) + '/' + element.tagName.toLowerCase() + '[' + (ix + 1) + ']'; + if (sibling.nodeType === 1 && sibling.tagName.toLowerCase() === element.tagName.toLowerCase()) + ix++; + } + } + + var interactive = []; + document.querySelectorAll('button, a, input, select, textarea, [onclick]').forEach(function(el) { + interactive.push({ + tag: el.tagName, + id: el.id || 'N/A', + text: (el.innerText || el.value || el.placeholder || '').substring(0, 50), + xpath: getElementXPath(el) + }); + }); + return interactive; + """ + + self.elements_data = self.driver.execute_script(script) + + # Save to file + with open("interactive_elements.json", "w") as f: + json.dump(self.elements_data, f, indent=2) + + # Display in treeview + self.display_elements() + messagebox.showinfo("Success", f"Scraped and saved {len(self.elements_data)} elements") + + except Exception as e: + messagebox.showerror("Error", f"Failed to scrape elements: {str(e)}") + + def display_elements(self): + """Display elements in treeview""" + # Clear existing items + for item in self.tree.get_children(): + self.tree.delete(item) + + # Add elements + for i, element in enumerate(self.elements_data): + self.tree.insert("", "end", text=str(i), values=( + element.get("tag", ""), + element.get("id", "N/A"), + element.get("text", ""), + element.get("xpath", "") + )) + + def load_elements(self): + """Load elements from JSON file""" + try: + with open("interactive_elements.json", "r") as f: + self.elements_data = json.load(f) + + self.display_elements() + messagebox.showinfo("Success", f"Loaded {len(self.elements_data)} elements") + except FileNotFoundError: + messagebox.showerror("Error", "interactive_elements.json not found. Click 'Start Session & Scrape Elements' first") + + def click_element(self): + """Click the selected element in the browser""" + if not self.driver: + messagebox.showwarning("Warning", "No browser session. Click 'Start Session' first") + return + + selected = self.tree.selection() + if not selected: + messagebox.showwarning("Warning", "Select an element first") + return + + try: + index = int(self.tree.item(selected[0])['text']) + element = self.elements_data[index] + xpath = element.get("xpath") + + elem = self.driver.find_element("xpath", xpath) + elem.click() + messagebox.showinfo("Success", f"Clicked: {element.get('text', 'Element')}") + except Exception as e: + messagebox.showerror("Error", f"Could not click element: {str(e)}") + + def close_browser(self): + """Close the browser""" + if self.driver: + self.driver.quit() + self.driver = None + messagebox.showinfo("Info", "Browser closed") + + def open_config(self): + """Open configuration window""" + config_window = tk.Toplevel(self.root) + config_window.title("Automation Configuration") + config_window.geometry("500x600") + + # Load existing config if available + try: + with open("automation_config.json", "r") as f: + config_data = json.load(f) + except FileNotFoundError: + config_data = { + "login": {"username": "pyman", "password": "Pymaster123!"}, + "textbox": { + "fullname": "PyMan Smith", + "email": "pyman@example.com", + "current_address": "123 Main St, New York, NY 10001", + "permanent_address": "456 Oak Ave, Los Angeles, CA 90210" + } + } + + # Create scrollable frame + canvas = tk.Canvas(config_window) + scrollbar = ttk.Scrollbar(config_window, orient="vertical", command=canvas.yview) + scrollable_frame = ttk.Frame(canvas) + + scrollable_frame.bind( + "", + lambda e: canvas.configure(scrollregion=canvas.bbox("all")) + ) + + canvas.create_window((0, 0), window=scrollable_frame, anchor="nw") + canvas.configure(yscrollcommand=scrollbar.set) + + # Login Section + ttk.Label(scrollable_frame, text="Login Credentials", font=("Arial", 12, "bold")).pack(pady=10) + + ttk.Label(scrollable_frame, text="Username:").pack() + username_var = tk.StringVar(value=config_data["login"]["username"]) + ttk.Entry(scrollable_frame, textvariable=username_var, width=40).pack() + + ttk.Label(scrollable_frame, text="Password:").pack() + password_var = tk.StringVar(value=config_data["login"]["password"]) + ttk.Entry(scrollable_frame, textvariable=password_var, show="*", width=40).pack() + + # TextBox Section + ttk.Label(scrollable_frame, text="TextBox Form Data", font=("Arial", 12, "bold")).pack(pady=10) + + ttk.Label(scrollable_frame, text="Full Name:").pack() + fullname_var = tk.StringVar(value=config_data["textbox"]["fullname"]) + ttk.Entry(scrollable_frame, textvariable=fullname_var, width=40).pack() + + ttk.Label(scrollable_frame, text="Email:").pack() + email_var = tk.StringVar(value=config_data["textbox"]["email"]) + ttk.Entry(scrollable_frame, textvariable=email_var, width=40).pack() + + ttk.Label(scrollable_frame, text="Current Address:").pack() + current_addr_var = tk.StringVar(value=config_data["textbox"]["current_address"]) + ttk.Entry(scrollable_frame, textvariable=current_addr_var, width=40).pack() + + ttk.Label(scrollable_frame, text="Permanent Address:").pack() + permanent_addr_var = tk.StringVar(value=config_data["textbox"]["permanent_address"]) + ttk.Entry(scrollable_frame, textvariable=permanent_addr_var, width=40).pack() + + # Save button + def save_config(): + new_config = { + "login": { + "username": username_var.get(), + "password": password_var.get() + }, + "textbox": { + "fullname": fullname_var.get(), + "email": email_var.get(), + "current_address": current_addr_var.get(), + "permanent_address": permanent_addr_var.get() + } + } + + with open("automation_config.json", "w") as f: + json.dump(new_config, f, indent=2) + + messagebox.showinfo("Success", "Configuration saved to automation_config.json") + config_window.destroy() + + ttk.Button(scrollable_frame, text="Save Configuration", command=save_config).pack(pady=10) + + canvas.pack(side="left", fill="both", expand=True) + scrollbar.pack(side="right", fill="y") + + def run_automation(self): + """Run the full automation workflow using saved config""" + try: + # Load config + with open("automation_config.json", "r") as f: + config = json.load(f) + except FileNotFoundError: + messagebox.showerror("Error", "Config file not found. Click 'Configure Automation' first") + return + + try: + # Import WebAutomation from main.py + from main import WebAutomation + + # Create automation instance + automation = WebAutomation() + + # Run the workflow + messagebox.showinfo("Starting", "Automation workflow starting...") + + automation.login( + config["login"]["username"], + config["login"]["password"] + ) + messagebox.showinfo("Step 1", "Login complete") + + automation.complete_textbox( + config["textbox"]["fullname"], + config["textbox"]["email"], + config["textbox"]["current_address"], + config["textbox"]["permanent_address"] + ) + messagebox.showinfo("Step 2", "TextBox complete") + + automation.check_box_list() + messagebox.showinfo("Step 3", "CheckBox complete") + + automation.radio_button_list() + messagebox.showinfo("Step 4", "RadioButton complete") + + automation.web_tables() + messagebox.showinfo("Step 5", "WebTables complete") + + automation.download() + messagebox.showinfo("Step 6", "Download complete") + + automation.close() + messagebox.showinfo("Success", "Automation workflow completed!") + + except Exception as e: + messagebox.showerror("Error", f"Automation failed: {str(e)}") + +if __name__ == "__main__": + root = tk.Tk() + gui = AutomationGUI(root) + root.mainloop() diff --git a/interactive_elements.json b/interactive_elements.json new file mode 100644 index 0000000..146467d --- /dev/null +++ b/interactive_elements.json @@ -0,0 +1,236 @@ +[ + { + "id": "N/A", + "tag": "A", + "text": "", + "xpath": "//*[@id='root']/header[1]/a[1]" + }, + { + "id": "N/A", + "tag": "BUTTON", + "text": "", + "xpath": "//*[@id='root']/div[1]/div[1]/div[1]/div[1]/nav[1]/button[1]" + }, + { + "id": "N/A", + "tag": "A", + "text": "Text Box", + "xpath": "//*[@id='item-0']/a[1]" + }, + { + "id": "N/A", + "tag": "A", + "text": "Check Box", + "xpath": "//*[@id='item-1']/a[1]" + }, + { + "id": "N/A", + "tag": "A", + "text": "Radio Button", + "xpath": "//*[@id='item-2']/a[1]" + }, + { + "id": "N/A", + "tag": "A", + "text": "Web Tables", + "xpath": "//*[@id='item-3']/a[1]" + }, + { + "id": "N/A", + "tag": "A", + "text": "Buttons", + "xpath": "//*[@id='item-4']/a[1]" + }, + { + "id": "N/A", + "tag": "A", + "text": "Links", + "xpath": "//*[@id='item-5']/a[1]" + }, + { + "id": "N/A", + "tag": "A", + "text": "Broken Links - Images", + "xpath": "//*[@id='item-6']/a[1]" + }, + { + "id": "N/A", + "tag": "A", + "text": "Upload and Download", + "xpath": "//*[@id='item-7']/a[1]" + }, + { + "id": "N/A", + "tag": "A", + "text": "Dynamic Properties", + "xpath": "//*[@id='item-8']/a[1]" + }, + { + "id": "N/A", + "tag": "A", + "text": "Practice Form", + "xpath": "//*[@id='item-0']/a[1]" + }, + { + "id": "N/A", + "tag": "A", + "text": "Browser Windows", + "xpath": "//*[@id='item-0']/a[1]" + }, + { + "id": "N/A", + "tag": "A", + "text": "Alerts", + "xpath": "//*[@id='item-1']/a[1]" + }, + { + "id": "N/A", + "tag": "A", + "text": "Frames", + "xpath": "//*[@id='item-2']/a[1]" + }, + { + "id": "N/A", + "tag": "A", + "text": "Nested Frames", + "xpath": "//*[@id='item-3']/a[1]" + }, + { + "id": "N/A", + "tag": "A", + "text": "Modal Dialogs", + "xpath": "//*[@id='item-4']/a[1]" + }, + { + "id": "N/A", + "tag": "A", + "text": "Accordian", + "xpath": "//*[@id='item-0']/a[1]" + }, + { + "id": "N/A", + "tag": "A", + "text": "Auto Complete", + "xpath": "//*[@id='item-1']/a[1]" + }, + { + "id": "N/A", + "tag": "A", + "text": "Date Picker", + "xpath": "//*[@id='item-2']/a[1]" + }, + { + "id": "N/A", + "tag": "A", + "text": "Slider", + "xpath": "//*[@id='item-3']/a[1]" + }, + { + "id": "N/A", + "tag": "A", + "text": "Progress Bar", + "xpath": "//*[@id='item-4']/a[1]" + }, + { + "id": "N/A", + "tag": "A", + "text": "Tabs", + "xpath": "//*[@id='item-5']/a[1]" + }, + { + "id": "N/A", + "tag": "A", + "text": "Tool Tips", + "xpath": "//*[@id='item-6']/a[1]" + }, + { + "id": "N/A", + "tag": "A", + "text": "Menu", + "xpath": "//*[@id='item-7']/a[1]" + }, + { + "id": "N/A", + "tag": "A", + "text": "Select Menu", + "xpath": "//*[@id='item-8']/a[1]" + }, + { + "id": "N/A", + "tag": "A", + "text": "Sortable", + "xpath": "//*[@id='item-0']/a[1]" + }, + { + "id": "N/A", + "tag": "A", + "text": "Selectable", + "xpath": "//*[@id='item-1']/a[1]" + }, + { + "id": "N/A", + "tag": "A", + "text": "Resizable", + "xpath": "//*[@id='item-2']/a[1]" + }, + { + "id": "N/A", + "tag": "A", + "text": "Droppable", + "xpath": "//*[@id='item-3']/a[1]" + }, + { + "id": "N/A", + "tag": "A", + "text": "Dragabble", + "xpath": "//*[@id='item-4']/a[1]" + }, + { + "id": "N/A", + "tag": "A", + "text": "Login", + "xpath": "//*[@id='item-0']/a[1]" + }, + { + "id": "N/A", + "tag": "A", + "text": "Book Store", + "xpath": "//*[@id='item-2']/a[1]" + }, + { + "id": "N/A", + "tag": "A", + "text": "Profile", + "xpath": "//*[@id='item-3']/a[1]" + }, + { + "id": "N/A", + "tag": "A", + "text": "Book Store API", + "xpath": "//*[@id='item-4']/a[1]" + }, + { + "id": "userName", + "tag": "INPUT", + "text": "UserName", + "xpath": "//*[@id='userName']" + }, + { + "id": "password", + "tag": "INPUT", + "text": "Password", + "xpath": "//*[@id='password']" + }, + { + "id": "login", + "tag": "BUTTON", + "text": "Login", + "xpath": "//*[@id='login']" + }, + { + "id": "newUser", + "tag": "BUTTON", + "text": "New User", + "xpath": "//*[@id='newUser']" + } +] \ No newline at end of file diff --git a/main.py b/main.py index e6e4f28..853bcd6 100644 --- a/main.py +++ b/main.py @@ -1,4 +1,285 @@ from selenium import webdriver -from selenium.webdriver.common.by import Service +from webdriver_manager.chrome import ChromeDriverManager +from selenium.webdriver.chrome.service import Service +from selenium.webdriver.chrome.options import Options +from selenium.webdriver.support.ui import WebDriverWait +from selenium.webdriver.support import expected_conditions as EC +from selenium.webdriver.common.by import By +import os +import json +import tkinter as tk +from tkinter import ttk, messagebox +import re -service = Service("chrome-win64/chromedriver.exe") \ No newline at end of file +class WebAutomation: + def __init__(self): + chrome_options = Options() + chrome_options.add_argument("--disable-search-engine-choice-screen") + + download_path = os.getcwd() + prefs = { + "download.default_directory": download_path,} + chrome_options.add_experimental_option("prefs", prefs) + + + service = Service(ChromeDriverManager().install()) + + self.driver = webdriver.Chrome(options=chrome_options, service=service) + + def login(self, username, password): + self.driver.get("https://demoqa.com/login") + + # Important elements are located using WebDriverWait to ensure they are visible before interacting with them + username_field = WebDriverWait(self.driver, 10).until(EC.visibility_of_element_located((By.ID, 'userName'))) + password_field = WebDriverWait(self.driver, 10).until(EC.visibility_of_element_located((By.ID, 'password'))) + press_login = WebDriverWait(self.driver, 10).until(EC.element_to_be_clickable((By.ID, 'login'))) + + + username_field.send_keys(username) + password_field.send_keys(password) + press_login.click() + + + def complete_textbox(self, fullname, email, current_address, permanent_address): + elements = WebDriverWait(self.driver, 10).until(EC.visibility_of_element_located((By.XPATH, '//*[@id="root"]/div/div/div/div[1]/div/div/div[1]/span/div'))) + elements.click() + + text_box = WebDriverWait(self.driver, 10).until(EC.element_to_be_clickable((By.XPATH, '//*[@id="item-0"]/a'))) + self.driver.execute_script("arguments[0].click();", text_box) # Click "Text Box" using JavaScript + + # Locate the form fields + full_name_field = WebDriverWait(self.driver, 10).until(EC.visibility_of_element_located((By.ID, 'userName'))) + email_field = WebDriverWait(self.driver, 10).until(EC.visibility_of_element_located((By.XPATH, '//*[@id="userEmail"]'))) + current_address_field = WebDriverWait(self.driver, 10).until(EC.visibility_of_element_located((By.XPATH, '//*[@id="currentAddress"]'))) + permanent_address_field = WebDriverWait(self.driver, 10).until(EC.visibility_of_element_located((By.XPATH, '//*[@id="permanentAddress"]'))) + submit_button = self.driver.find_element(By.XPATH, '//*[@id="submit"]') + + # Fill out the form fields and submit the form + full_name_field.send_keys(fullname) + email_field.send_keys(email) + current_address_field.send_keys(current_address) + permanent_address_field.send_keys(permanent_address) + self.driver.execute_script("arguments[0].click();", submit_button) # Click "Submit" using JavaScript + + def get_all_xpaths(self): + """Extract all XPaths and element info from the page""" + script = """ + function getElementXPath(element) { + if (element.id !== '') + return "//*[@id='" + element.id + "']"; + if (element === document.body) + return "//" + element.tagName.toLowerCase(); + + var ix = 0; + var siblings = element.parentNode.childNodes; + for (var i = 0; i < siblings.length; i++) { + var sibling = siblings[i]; + if (sibling === element) + return getElementXPath(element.parentNode) + '/' + element.tagName.toLowerCase() + '[' + (ix + 1) + ']'; + if (sibling.nodeType === 1 && sibling.tagName.toLowerCase() === element.tagName.toLowerCase()) + ix++; + } + } + + var elements = []; + document.querySelectorAll('*').forEach(function(el) { + elements.push({ + tag: el.tagName, + id: el.id || 'N/A', + class: el.className || 'N/A', + xpath: getElementXPath(el), + text: (el.innerText || '').substring(0, 50), + clickable: el.onclick !== null || el.tagName.match(/button|a|input/i) + }); + }); + return elements; + """ + + elements = self.driver.execute_script(script) + return elements + + def get_interactive_elements(self): + """Get only clickable/interactive elements (buttons, links, inputs)""" + script = """ + function getElementXPath(element) { + if (element.id !== '') + return "//*[@id='" + element.id + "']"; + if (element === document.body) + return "//" + element.tagName.toLowerCase(); + + var ix = 0; + var siblings = element.parentNode.childNodes; + for (var i = 0; i < siblings.length; i++) { + var sibling = siblings[i]; + if (sibling === element) + return getElementXPath(element.parentNode) + '/' + element.tagName.toLowerCase() + '[' + (ix + 1) + ']'; + if (sibling.nodeType === 1 && sibling.tagName.toLowerCase() === element.tagName.toLowerCase()) + ix++; + } + } + + var interactive = []; + document.querySelectorAll('button, a, input, select, textarea, [onclick]').forEach(function(el) { + interactive.push({ + tag: el.tagName, + id: el.id || 'N/A', + text: (el.innerText || el.value || el.placeholder || '').substring(0, 50), + xpath: getElementXPath(el) + }); + }); + return interactive; + """ + + return self.driver.execute_script(script) + + def save_xpaths_to_file(self, filename="xpaths.json", interactive_only=False): + """Save extracted XPaths to a JSON file""" + if interactive_only: + elements = self.get_interactive_elements() + else: + elements = self.get_all_xpaths() + + with open(filename, "w") as f: + json.dump(elements, f, indent=2) + + print(f"Saved {len(elements)} elements to {filename}") + return elements + + def check_box_list(self): + # Locate the Check box list element and click it + check_box_list = WebDriverWait(self.driver, 10).until(EC.visibility_of_element_located((By.XPATH, '//*[@id="item-1"]/a'))) + self.driver.execute_script("arguments[0].click();", check_box_list) # Click "Check Box List" using JavaScript + + check_box = WebDriverWait(self.driver, 10).until(EC.visibility_of_element_located((By.CLASS_NAME, 'rc-tree-checkbox'))) + self.driver.execute_script("arguments[0].click();", check_box) + + def radio_button_list(self): + # locate the next item in the list and click it + radio_button_list = WebDriverWait(self.driver, 10).until(EC.visibility_of_element_located((By.XPATH, '//*[@id="item-2"]/a'))) + self.driver.execute_script("arguments[0].click();", radio_button_list) + + # locate the radio button and click it + radio_button = WebDriverWait(self.driver, 10).until(EC.visibility_of_element_located((By.ID, 'yesRadio'))) + self.driver.execute_script("arguments[0].click();", radio_button) + + # TODO [SCRUM-20]: add logic to export data from web tables into a xls file + def web_tables(self): + web_tables = WebDriverWait(self.driver, 10).until(EC.visibility_of_element_located((By.XPATH, '//*[@id="item-3"]/a'))) + self.driver.execute_script("arguments[0].click();", web_tables) + + + def download(self): + # Locate the Download item and click it + download = WebDriverWait(self.driver, 10).until(EC.visibility_of_element_located((By.XPATH, '//*[@id="item-7"]/a'))) + self.driver.execute_script("arguments[0].click();", download) + + #click the button + download_button = WebDriverWait(self.driver, 10).until(EC.visibility_of_element_located((By.ID, 'downloadButton'))) + self.driver.execute_script("arguments[0].click();", download_button) + + def close(self): + self.driver.quit() + +class ConfigurationTab: + def __init__(self, root): + self.frame = ttk.Frame(root) + self.config_data = {} + + # Login Section + ttk.Label(self.frame, text="Login Credentials", font=("Arial", 12, "bold")).pack(pady=10) + + ttk.Label(self.frame, text="Username:").pack() + self.username_var = tk.StringVar(value="pyman") + ttk.Entry(self.frame, textvariable=self.username_var, width=30).pack() + + ttk.Label(self.frame, text="Password:").pack() + self.password_var = tk.StringVar(value="Pymaster123!") + ttk.Entry(self.frame, textvariable=self.password_var, show="*", width=30).pack() + + # TextBox Section + ttk.Label(self.frame, text="TextBox Form Data", font=("Arial", 12, "bold")).pack(pady=10) + + ttk.Label(self.frame, text="Full Name:").pack() + self.fullname_var = tk.StringVar(value="PyMan Smith") + ttk.Entry(self.frame, textvariable=self.fullname_var, width=30).pack() + + ttk.Label(self.frame, text="Email:").pack() + self.email_var = tk.StringVar(value="pyman@example.com") + ttk.Entry(self.frame, textvariable=self.email_var, width=30).pack() + + ttk.Label(self.frame, text="Current Address:").pack() + self.current_addr_var = tk.StringVar(value="123 Main St, New York, NY 10001") + ttk.Entry(self.frame, textvariable=self.current_addr_var, width=30).pack() + + ttk.Label(self.frame, text="Permanent Address:").pack() + self.permanent_addr_var = tk.StringVar(value="456 Oak Ave, Los Angeles, CA 90210") + ttk.Entry(self.frame, textvariable=self.permanent_addr_var, width=30).pack() + + # Save button + ttk.Button(self.frame, text="Save Configuration", command=self.save_config).pack(pady=10) + + self.status_label = ttk.Label(self.frame, text="", foreground="green") + self.status_label.pack() + + def save_config(self): + """Save configuration to JSON file""" + self.config_data = { + "login": { + "username": self.username_var.get(), + "password": self.password_var.get() + }, + "textbox": { + "fullname": self.fullname_var.get(), + "email": self.email_var.get(), + "current_address": self.current_addr_var.get(), + "permanent_address": self.permanent_addr_var.get() + } + } + + with open("automation_config.json", "w") as f: + json.dump(self.config_data, f, indent=2) + + self.status_label.config(text="Configuration saved successfully!") + messagebox.showinfo("Success", "Configuration saved to automation_config.json") + +def load_config(filename="automation_config.json"): + """Load automation configuration from JSON file""" + try: + with open(filename, "r") as f: + return json.load(f) + except FileNotFoundError: + print(f"Config file {filename} not found. Using defaults.") + return { + "login": {"username": "pyman", "password": "Pymaster123!"}, + "textbox": { + "fullname": "PyMan Smith", + "email": "pyman@example.com", + "current_address": "123 Main St, New York, NY 10001", + "permanent_address": "456 Oak Ave, Los Angeles, CA 90210" + } + } + + + + + + +if __name__ == "__main__": + config = load_config() + + web_automation = WebAutomation() + web_automation.login( + config["login"]["username"], + config["login"]["password"] + ) + web_automation.complete_textbox( + config["textbox"]["fullname"], + config["textbox"]["email"], + config["textbox"]["current_address"], + config["textbox"]["permanent_address"] + ) + web_automation.check_box_list() + web_automation.radio_button_list() + web_automation.web_tables() + web_automation.download() + web_automation.close()