#!/usr/bin/env python3 """ Device Details Page UI Tests Tests device details page, field updates, and delete operations """ import sys import os from selenium.webdriver.common.by import By # Add test directory to path sys.path.insert(0, os.path.dirname(__file__)) from .test_helpers import BASE_URL, API_BASE_URL, api_get, wait_for_page_load, wait_for_element_by_css, wait_for_input_value # noqa: E402 def test_device_list_page_loads(driver): """Test: Device list page loads successfully""" driver.get(f"{BASE_URL}/devices.php") wait_for_page_load(driver, timeout=10) assert "device" in driver.page_source.lower(), "Page should contain device content" def test_devices_table_present(driver): """Test: Devices table is rendered""" driver.get(f"{BASE_URL}/devices.php") wait_for_page_load(driver, timeout=10) wait_for_element_by_css(driver, "table, #devicesTable", timeout=10) table = driver.find_elements(By.CSS_SELECTOR, "table, #devicesTable") assert len(table) > 0, "Devices table should be present" def test_device_search_works(driver): """Test: Device search/filter functionality works""" driver.get(f"{BASE_URL}/devices.php") wait_for_page_load(driver, timeout=10) # Find search input (common patterns) search_inputs = driver.find_elements(By.CSS_SELECTOR, "input[type='search'], input[placeholder*='search' i], .dataTables_filter input") if len(search_inputs) > 0: search_box = search_inputs[0] assert search_box.is_displayed(), "Search box should be visible" # Type in search box and wait briefly for filter to apply search_box.clear() search_box.send_keys("test") # Wait for DOM/JS to react (at least one row or filtered content) — if datatables in use, table body should update wait_for_element_by_css(driver, "table tbody tr", timeout=5) # Verify search executed (page content changed or filter applied) assert True, "Search executed successfully" else: # If no search box, just verify page loaded assert len(driver.page_source) > 100, "Page should load content" def test_devices_api(api_token): """Test: Devices API endpoint returns data""" response = api_get("/devices", api_token) assert response.status_code == 200, "API should return 200" data = response.json() assert isinstance(data, (list, dict)), "API should return list or dict" def test_devices_totals_api(api_token): """Test: Devices totals API endpoint works""" response = api_get("/devices/totals", api_token) assert response.status_code == 200, "API should return 200" data = response.json() assert isinstance(data, (list, dict)), "API should return list or dict" assert len(data) > 0, "Response should contain data" def test_add_device_with_generated_mac_ip(driver, api_token): """Add a new device using the UI, always clicking Generate MAC/IP buttons""" import requests driver.get(f"{BASE_URL}/devices.php") wait_for_page_load(driver, timeout=10) # --- Click "Add Device" --- # Wait for the "New Device" link specifically to ensure it's loaded add_selector = "a[href*='deviceDetails.php?mac=new'], button#btnAddDevice, .btn-add-device" try: add_button = wait_for_element_by_css(driver, add_selector, timeout=10) except Exception: # Fallback to broader search if specific selector fails add_buttons = driver.find_elements(By.XPATH, "//button[contains(text(),'Add') or contains(text(),'New')] | //a[contains(text(),'Add') or contains(text(),'New')]") if add_buttons: add_button = add_buttons[0] else: assert True, "Add device button not found, skipping test" return # Use JavaScript click to bypass any transparent overlays from the chart driver.execute_script("arguments[0].click();", add_button) # Wait for the device form to appear (use the NEWDEV_devMac field as indicator) wait_for_element_by_css(driver, "#NEWDEV_devMac", timeout=10) # --- Helper to click generate button for a field --- def click_generate_button(field_id): btn = driver.find_element(By.CSS_SELECTOR, f"span[onclick*='generate_{field_id}']") driver.execute_script("arguments[0].click();", btn) # Wait for the input to be populated and return it return wait_for_input_value(driver, field_id, timeout=10) # --- Generate MAC --- test_mac = click_generate_button("NEWDEV_devMac") assert test_mac, "MAC should be generated" # --- Generate IP --- test_ip = click_generate_button("NEWDEV_devLastIP") assert test_ip, "IP should be generated" # --- Fill Name --- name_field = driver.find_element(By.ID, "NEWDEV_devName") name_field.clear() name_field.send_keys("Test Device Selenium") # --- Click Save --- save_buttons = driver.find_elements(By.CSS_SELECTOR, "button#btnSave, button#save, button[type='submit'], button.btn-primary, button[onclick*='save' i]") if not save_buttons: save_buttons = driver.find_elements(By.XPATH, "//button[contains(translate(text(),'SAVE','save'),'save')]") if not save_buttons: assert True, "Save button not found, skipping test" return driver.execute_script("arguments[0].click();", save_buttons[0]) # --- Verify device via API --- headers = {"Authorization": f"Bearer {api_token}"} verify_response = requests.get(f"{API_BASE_URL}/device/{test_mac}", headers=headers) if verify_response.status_code == 200: device_data = verify_response.json() assert device_data is not None, "Device should exist in database" else: # Fallback: check UI driver.get(f"{BASE_URL}/devices.php") wait_for_page_load(driver, timeout=10) if test_mac in driver.page_source or "Test Device Selenium" in driver.page_source: assert True, "Device appears in UI" else: error_elements = driver.find_elements(By.CSS_SELECTOR, ".alert-danger, .error-message, .callout-danger") has_error = any(elem.is_displayed() and elem.text for elem in error_elements) assert not has_error, "Save should not produce visible errors"