test_server.py•29.1 kB
#!/usr/bin/env python3
"""
Script de pruebas para validar el servidor MCP Selenium WebDriver.
"""
import sys
import os
import time
import traceback
from typing import Dict, Any, List
# Importar módulos del servidor
from config import DEFAULT_CONFIG, STEALTH_CONFIG
from session_manager import SessionManager
from selenium_tools import SeleniumTools
from stealth_features import StealthFeatures
from browser_detection import BrowserDetection
from browser_manager import WebDriverManager
class ServerTester:
"""Clase para probar las funcionalidades del servidor."""
def __init__(self):
self.config = DEFAULT_CONFIG
self.session_manager = SessionManager(self.config)
self.selenium_tools = SeleniumTools(self.session_manager)
self.stealth_features = StealthFeatures(self.session_manager)
self.browser_detection = BrowserDetection()
self.webdriver_manager = WebDriverManager()
self.test_results = []
self.active_sessions = []
def log_test(self, test_name: str, success: bool, message: str = "", details: Any = None):
"""Registra el resultado de una prueba."""
result = {
"test": test_name,
"success": success,
"message": message,
"details": details,
"timestamp": time.time()
}
self.test_results.append(result)
status = "✅ PASS" if success else "❌ FAIL"
print(f"{status} {test_name}: {message}")
if not success and details:
print(f" Detalles: {details}")
def test_browser_detection(self) -> bool:
"""Prueba la detección de navegadores."""
print("\n=== Prueba: Detección de Navegadores ===")
try:
# Detectar navegadores disponibles
browsers = self.browser_detection.detect_available_browsers()
self.log_test(
"Detección de navegadores",
len(browsers) > 0,
f"Detectados {len(browsers)} navegadores",
browsers
)
# Obtener navegador recomendado
recommended = self.browser_detection.get_recommended_browser()
self.log_test(
"Navegador recomendado",
recommended in ["chrome", "firefox"],
f"Recomendado: {recommended}"
)
# Verificar soporte de WebDriver
support = self.browser_detection.check_webdriver_support("chrome")
self.log_test(
"Soporte WebDriver Chrome",
support["selenium_support"],
f"Selenium: {support['selenium_support']}, WebDriver Manager: {support['webdriver_manager_support']}"
)
return True
except Exception as e:
self.log_test("Detección de navegadores", False, str(e), traceback.format_exc())
return False
def test_webdriver_creation(self) -> bool:
"""Prueba la creación de WebDriver."""
print("\n=== Prueba: Creación de WebDriver ===")
try:
# Crear driver básico
driver_and_data = self.webdriver_manager.create_driver(
browser_type="chrome",
browser_options=self.config.browser_options
)
driver = driver_and_data["driver"]
user_data_dir = driver_and_data.get("user_data_dir") # Puede ser None
self.log_test(
"Creación de WebDriver",
driver is not None,
"WebDriver creado exitosamente"
)
# Probar navegación básica
driver.get("data:text/html,<html><body><h1>Test Page</h1></body></html>")
title = driver.title
self.log_test(
"Navegación básica",
"Test Page" in driver.page_source,
f"Título: {title}"
)
# Cerrar driver
driver.quit()
return True
except Exception as e:
self.log_test("Creación de WebDriver", False, str(e), traceback.format_exc())
return False
def test_session_management(self) -> bool:
"""Prueba la gestión de sesiones."""
print("\n=== Prueba: Gestión de Sesiones ===")
try:
# Crear sesión
result = self.selenium_tools.start_browser(
browser_type="chrome",
options={"headless": True}
)
self.log_test(
"Creación de sesión",
result["success"],
result["message"]
)
if not result["success"]:
return False
session_id = result["session_id"]
self.active_sessions.append(session_id)
# Verificar que la sesión existe
session = self.session_manager.get_session(session_id)
self.log_test(
"Verificación de sesión",
session is not None,
f"Sesión {session_id} encontrada"
)
# Listar sesiones
sessions = self.session_manager.list_sessions()
self.log_test(
"Listado de sesiones",
len(sessions) > 0,
f"Sesiones activas: {len(sessions)}"
)
return True
except Exception as e:
self.log_test("Gestión de sesiones", False, str(e), traceback.format_exc())
return False
def test_navigation(self) -> bool:
"""Prueba la navegación web."""
print("\n=== Prueba: Navegación Web ===")
if not self.active_sessions:
self.log_test("Navegación", False, "No hay sesiones activas")
return False
session_id = self.active_sessions[0]
try:
# Navegar a página de prueba
result = self.selenium_tools.navigate_to_url(
session_id,
"data:text/html,<html><head><title>Test Navigation</title></head><body><h1>Navigation Test</h1><p>This is a test page.</p></body></html>"
)
self.log_test(
"Navegación a URL",
result["success"],
result["message"]
)
# Obtener información de la página
page_info = self.selenium_tools.get_page_info(session_id)
self.log_test(
"Información de página",
page_info["success"] and "Test Navigation" in page_info["title"],
f"Título: {page_info.get('title', 'N/A')}"
)
return True
except Exception as e:
self.log_test("Navegación", False, str(e), traceback.format_exc())
return False
def test_element_interaction(self) -> bool:
"""Prueba la interacción con elementos."""
print("\n=== Prueba: Interacción con Elementos ===")
if not self.active_sessions:
self.log_test("Interacción con elementos", False, "No hay sesiones activas")
return False
session_id = self.active_sessions[0]
try:
# Navegar a página con elementos
html_content = """
<html>
<head><title>Element Test</title></head>
<body>
<h1 id="title">Element Interaction Test</h1>
<input id="text-input" type="text" placeholder="Enter text here">
<button id="test-button">Click Me</button>
<div class="test-div">Test Content</div>
<a href="#" id="test-link">Test Link</a>
</body>
</html>
"""
nav_result = self.selenium_tools.navigate_to_url(
session_id,
f"data:text/html,{html_content}"
)
if not nav_result["success"]:
self.log_test("Navegación para elementos", False, nav_result["message"])
return False
# Buscar elemento por ID
find_result = self.selenium_tools.find_element(
session_id,
"id",
"title"
)
self.log_test(
"Búsqueda de elemento por ID",
find_result["success"],
f"Elemento encontrado: {find_result.get('element', {}).get('tag_name', 'N/A')}"
)
# Buscar múltiples elementos
multi_result = self.selenium_tools.find_element(
session_id,
"tag_name",
"input",
multiple=True
)
self.log_test(
"Búsqueda múltiple de elementos",
multi_result["success"],
f"Elementos encontrados: {multi_result.get('elements_found', 0)}"
)
# Escribir texto
type_result = self.selenium_tools.type_text(
session_id,
"id",
"text-input",
"Texto de prueba"
)
self.log_test(
"Escritura de texto",
type_result["success"],
type_result["message"]
)
# Hacer clic en botón
click_result = self.selenium_tools.click_element(
session_id,
"id",
"test-button"
)
self.log_test(
"Clic en elemento",
click_result["success"],
click_result["message"]
)
return True
except Exception as e:
self.log_test("Interacción con elementos", False, str(e), traceback.format_exc())
return False
def test_javascript_execution(self) -> bool:
"""Prueba la ejecución de JavaScript."""
print("\n=== Prueba: Ejecución de JavaScript ===")
if not self.active_sessions:
self.log_test("Ejecución de JavaScript", False, "No hay sesiones activas")
return False
session_id = self.active_sessions[0]
try:
# Ejecutar JavaScript simple
js_result = self.selenium_tools.execute_script(
session_id,
"return document.title;"
)
self.log_test(
"JavaScript simple",
js_result["success"],
f"Resultado: {js_result.get('result', 'N/A')}"
)
# Ejecutar JavaScript complejo
complex_js = """
return {
title: document.title,
url: window.location.href,
elements: document.querySelectorAll('*').length,
timestamp: new Date().toISOString()
};
"""
complex_result = self.selenium_tools.execute_script(session_id, complex_js)
self.log_test(
"JavaScript complejo",
complex_result["success"] and isinstance(complex_result.get("result"), dict),
f"Elementos en página: {complex_result.get('result', {}).get('elements', 'N/A')}"
)
return True
except Exception as e:
self.log_test("Ejecución de JavaScript", False, str(e), traceback.format_exc())
return False
def test_stealth_features(self) -> bool:
"""Prueba las características stealth."""
print("\n=== Prueba: Características Stealth ===")
if not self.active_sessions:
self.log_test("Características stealth", False, "No hay sesiones activas")
return False
session_id = self.active_sessions[0]
try:
# Aplicar modo stealth
stealth_result = self.stealth_features.apply_stealth_mode(session_id)
self.log_test(
"Aplicación de modo stealth",
stealth_result["success"],
f"Scripts aplicados: {len(stealth_result.get('applied_scripts', []))}"
)
# Randomizar user agent
ua_result = self.stealth_features.randomize_user_agent(session_id)
self.log_test(
"Randomización de user agent",
ua_result["success"],
f"Nuevo UA: {ua_result.get('new_user_agent', 'N/A')[:50]}..."
)
# Randomizar viewport
viewport_result = self.stealth_features.randomize_viewport(session_id)
self.log_test(
"Randomización de viewport",
viewport_result["success"],
f"Nuevo tamaño: {viewport_result.get('new_size', 'N/A')}"
)
# Delay aleatorio
delay_result = self.stealth_features.add_random_delay(0.1, 0.5)
self.log_test(
"Delay aleatorio",
delay_result["success"],
f"Delay aplicado: {delay_result.get('delay_seconds', 'N/A')}s"
)
return True
except Exception as e:
self.log_test("Características stealth", False, str(e), traceback.format_exc())
return False
def test_screenshot(self) -> bool:
"""Prueba la captura de pantalla."""
print("\n=== Prueba: Captura de Pantalla ===")
if not self.active_sessions:
self.log_test("Captura de pantalla", False, "No hay sesiones activas")
return False
session_id = self.active_sessions[0]
try:
# Tomar captura de pantalla
screenshot_result = self.selenium_tools.take_screenshot(
session_id,
"/tmp/test_screenshot.png"
)
self.log_test(
"Captura de pantalla",
screenshot_result["success"],
screenshot_result["message"]
)
# Verificar que el archivo se creó
import os
file_exists = os.path.exists("/tmp/test_screenshot.png")
self.log_test(
"Archivo de captura creado",
file_exists,
f"Archivo existe: {file_exists}"
)
return True
except Exception as e:
self.log_test("Captura de pantalla", False, str(e), traceback.format_exc())
return False
def test_cookie_management(self) -> bool:
"""Prueba la gestión de cookies."""
print("\n=== Prueba: Gestión de Cookies ===")
if not self.active_sessions:
self.log_test("Gestión de cookies", False, "No hay sesiones activas")
return False
session_id = self.active_sessions[0]
try:
# Navegar a una página real para poder agregar cookies
nav_result = self.selenium_tools.navigate_to_url(
session_id,
"https://httpbin.org/cookies"
)
if not nav_result["success"]:
# Si no se puede acceder a httpbin, usar página local
self.selenium_tools.navigate_to_url(
session_id,
"data:text/html,<html><body><h1>Cookie Test</h1></body></html>"
)
# Obtener cookies iniciales
initial_cookies = self.stealth_features.manage_cookies(
session_id,
"get_all"
)
self.log_test(
"Obtener cookies iniciales",
initial_cookies["success"],
f"Cookies iniciales: {initial_cookies.get('count', 0)}"
)
# Agregar cookie de prueba
add_result = self.stealth_features.manage_cookies(
session_id,
"add",
cookie_data={
"name": "test_cookie",
"value": "test_value"
}
)
self.log_test(
"Agregar cookie",
add_result["success"],
add_result["message"]
)
# Verificar que la cookie se agregó
final_cookies = self.stealth_features.manage_cookies(
session_id,
"get_all"
)
cookie_added = final_cookies.get("count", 0) > initial_cookies.get("count", 0)
self.log_test(
"Verificar cookie agregada",
cookie_added,
f"Cookies finales: {final_cookies.get('count', 0)}"
)
return True
except Exception as e:
self.log_test("Gestión de cookies", False, str(e), traceback.format_exc())
return False
def cleanup(self):
"""Limpia las sesiones de prueba."""
print("\n=== Limpieza ===")
try:
for session_id in self.active_sessions:
result = self.selenium_tools.close_browser(session_id)
print(f"Cerrando sesión {session_id}: {result.get('message', 'OK')}")
self.active_sessions.clear()
# Cerrar todas las sesiones restantes
self.session_manager.close_all_sessions()
except Exception as e:
print(f"Error en limpieza: {e}")
def run_all_tests(self) -> Dict[str, Any]:
"""Ejecuta todas las pruebas."""
print("🚀 Iniciando pruebas del Servidor MCP Selenium WebDriver\n")
tests = [
("Detección de navegadores", self.test_browser_detection),
("Creación de WebDriver", self.test_webdriver_creation),
("Gestión de sesiones", self.test_session_management),
("Navegación web", self.test_navigation),
("Interacción con elementos", self.test_element_interaction),
("Ejecución de JavaScript", self.test_javascript_execution),
("Características stealth", self.test_stealth_features),
("Captura de pantalla", self.test_screenshot),
("Gestión de cookies", self.test_cookie_management),
("Herramientas adicionales", self.test_additional_tools)
]
start_time = time.time()
for test_name, test_func in tests:
try:
test_func()
except Exception as e:
self.log_test(test_name, False, f"Excepción no manejada: {str(e)}")
print() # Línea en blanco entre pruebas
# Limpieza
self.cleanup()
# Resumen
end_time = time.time()
duration = end_time - start_time
total_tests = len(self.test_results)
passed_tests = sum(1 for r in self.test_results if r["success"])
failed_tests = total_tests - passed_tests
success_rate = (passed_tests / total_tests) * 100 if total_tests > 0 else 0
print("="*60)
print("📊 RESUMEN DE PRUEBAS")
print("="*60)
print(f"Tiempo total: {duration:.2f} segundos")
print(f"Pruebas ejecutadas: {total_tests}")
print(f"Exitosas: {passed_tests}")
print(f"Fallidas: {failed_tests}")
print(f"Tasa de éxito: {success_rate:.1f}%")
if failed_tests > 0:
print("\n❌ PRUEBAS FALLIDAS:")
for result in self.test_results:
if not result["success"]:
print(f" - {result['test']}: {result['message']}")
return {
"total_tests": total_tests,
"passed_tests": passed_tests,
"failed_tests": failed_tests,
"success_rate": success_rate,
"duration": duration,
"results": self.test_results
}
def test_additional_tools(self) -> bool:
"""Prueba las herramientas adicionales: is_element_empty, reescribir_HTML, handle_popup."""
print("\n=== Prueba: Herramientas Adicionales ===")
if not self.active_sessions:
self.log_test("Herramientas adicionales", False, "No hay sesiones activas")
return False
session_id = self.active_sessions[0]
try:
# Crear página de prueba con elementos para las nuevas herramientas
test_html = """
<html>
<head><title>Test Additional Tools</title></head>
<body>
<h1 id="main-title">Prueba de Herramientas Adicionales</h1>
<!-- Elementos para is_element_empty -->
<input id="empty-input" type="text" placeholder="Campo vacío">
<input id="filled-input" type="text" value="Texto existente">
<textarea id="empty-textarea"></textarea>
<div id="empty-div"></div>
<div id="filled-div">Contenido del div</div>
<!-- Elemento para reescribir_HTML -->
<div id="target-div">Contenido original</div>
<!-- Popup para handle_popup -->
<div id="test-popup" style="display:none; position:fixed; top:50px; left:50px; background:white; border:1px solid black; padding:20px;">
<h3 id="popup-title">Título del Popup</h3>
<p id="popup-content">Este es el contenido del popup de prueba.</p>
<button onclick="this.parentElement.style.display='none'">Cerrar</button>
</div>
<button id="show-popup" onclick="document.getElementById('test-popup').style.display='block'">Mostrar Popup</button>
<script>
// Mostrar popup automáticamente después de 2 segundos para la prueba
setTimeout(function() {
document.getElementById('test-popup').style.display = 'block';
}, 2000);
</script>
</body>
</html>
"""
# Navegar a la página de prueba
nav_result = self.selenium_tools.navigate_to_url(
session_id,
f"data:text/html,{test_html}"
)
if not nav_result["success"]:
self.log_test("Navegación para herramientas adicionales", False, nav_result["message"])
return False
# Esperar un momento para que la página cargue
import time
time.sleep(1)
# ===== PRUEBA: is_element_empty =====
# Probar con input vacío
empty_result = self.selenium_tools.is_element_empty(
session_id, "id", "empty-input"
)
self.log_test(
"is_element_empty - Input vacío",
empty_result["success"] and empty_result.get("is_empty", False),
f"Resultado: {empty_result.get('message', 'N/A')}"
)
# Probar con input lleno
filled_result = self.selenium_tools.is_element_empty(
session_id, "id", "filled-input"
)
self.log_test(
"is_element_empty - Input lleno",
filled_result["success"] and not filled_result.get("is_empty", True),
f"Resultado: {filled_result.get('message', 'N/A')}"
)
# Probar con div vacío
empty_div_result = self.selenium_tools.is_element_empty(
session_id, "id", "empty-div"
)
self.log_test(
"is_element_empty - Div vacío",
empty_div_result["success"] and empty_div_result.get("is_empty", False),
f"Resultado: {empty_div_result.get('message', 'N/A')}"
)
# Probar con div lleno
filled_div_result = self.selenium_tools.is_element_empty(
session_id, "id", "filled-div"
)
self.log_test(
"is_element_empty - Div lleno",
filled_div_result["success"] and not filled_div_result.get("is_empty", True),
f"Resultado: {filled_div_result.get('message', 'N/A')}"
)
# ===== PRUEBA: reescribir_HTML =====
new_html = '<div id="target-div" style="color: red; font-weight: bold;">¡Contenido reescrito exitosamente!</div>'
rewrite_result = self.selenium_tools.reescribir_HTML(
session_id, new_html, "id", "target-div"
)
self.log_test(
"reescribir_HTML",
rewrite_result["success"],
rewrite_result.get("message", "N/A")
)
# Verificar que el HTML se cambió
if rewrite_result["success"]:
# Buscar el elemento modificado
modified_element = self.selenium_tools.find_element(
session_id, "id", "target-div"
)
if modified_element["success"]:
element_text = modified_element["element"]["text"]
self.log_test(
"Verificación HTML reescrito",
"reescrito exitosamente" in element_text,
f"Nuevo texto: {element_text}"
)
# ===== PRUEBA: handle_popup =====
# Esperar a que aparezca el popup (el script lo muestra después de 2 segundos)
time.sleep(2.5)
popup_result = self.selenium_tools.handle_popup(
session_id, "id", "test-popup", "popup-title", "popup-content", True
)
self.log_test(
"handle_popup - Detección",
popup_result["success"],
popup_result.get("message", "N/A")
)
if popup_result["success"] and popup_result.get("popup_detected"):
self.log_test(
"handle_popup - Contenido",
popup_result.get("title") == "Título del Popup",
f"Título: {popup_result.get('title', 'N/A')}, Contenido: {popup_result.get('content', 'N/A')[:50]}..."
)
# Probar handle_popup cuando no hay popup (cerrar el popup primero)
self.selenium_tools.click_element(session_id, "xpath", "//button[contains(text(), 'Cerrar')]")
time.sleep(0.5)
no_popup_result = self.selenium_tools.handle_popup(
session_id, "id", "test-popup", "popup-title", "popup-content", False
)
self.log_test(
"handle_popup - Sin popup",
no_popup_result["success"] and not no_popup_result.get("popup_detected", True),
no_popup_result.get("message", "N/A")
)
return True
except Exception as e:
self.log_test("Herramientas adicionales", False, str(e), traceback.format_exc())
return False
def main():
"""Función principal."""
tester = ServerTester()
try:
results = tester.run_all_tests()
if results["failed_tests"] > 0:
sys.exit(1)
else:
print("\n🎉 ¡Todas las pruebas pasaron exitosamente!")
sys.exit(0)
except KeyboardInterrupt:
print("\n\n⏹️ Pruebas interrumpidas por el usuario.")
tester.cleanup()
sys.exit(130)
except Exception as e:
print(f"\n💥 Error fatal en las pruebas: {e}")
traceback.print_exc()
tester.cleanup()
sys.exit(1)
if __name__ == "__main__":
main()