db = Database::getInstance(); } public function runAllServiceTests() { echo "

🔧 Tests Exhaustivos de Servicios

"; $this->testWhatsAppService(); $this->testBotService(); $this->testWebhookClass(); } private function testWhatsAppService() { echo "

📱 Tests WhatsAppService

"; $this->serviceTest("Inicialización WhatsAppService", function() { $this->whatsappService = new WhatsAppService(); if (!$this->whatsappService) { throw new Exception("No se pudo crear instancia de WhatsAppService"); } // Verificar propiedades mediante reflexión $reflection = new ReflectionClass($this->whatsappService); $properties = $reflection->getProperties(); $requiredProps = ['token', 'phoneNumberId', 'apiUrl', 'db']; foreach ($requiredProps as $prop) { $found = false; foreach ($properties as $property) { if ($property->getName() === $prop) { $found = true; break; } } if (!$found) { throw new Exception("Propiedad requerida '$prop' no encontrada"); } } return "WhatsAppService inicializado con todas las propiedades"; }); $this->serviceTest("Método formatPhoneNumber", function() { if (!$this->whatsappService) { $this->whatsappService = new WhatsAppService(); } $reflection = new ReflectionClass($this->whatsappService); $method = $reflection->getMethod('formatPhoneNumber'); $method->setAccessible(true); // Tests de diferentes formatos $tests = [ ['input' => '573001234567', 'expected' => '573001234567'], ['input' => '+573001234567', 'expected' => '573001234567'], ['input' => '57 300 123 4567', 'expected' => '573001234567'], ['input' => '+57 (300) 123-4567', 'expected' => '573001234567'], ]; foreach ($tests as $test) { $result = $method->invokeArgs($this->whatsappService, [$test['input']]); if ($result !== $test['expected']) { throw new Exception("Formato incorrecto para '{$test['input']}': esperado '{$test['expected']}', obtenido '$result'"); } } return "Formateo de números funciona para todos los casos"; }); $this->serviceTest("Validación de estructura de mensaje de texto", function() { if (!$this->whatsappService) { $this->whatsappService = new WhatsAppService(); } $reflection = new ReflectionClass($this->whatsappService); // Verificar que el método sendTextMessage existe if (!$reflection->hasMethod('sendTextMessage')) { throw new Exception("Método sendTextMessage no existe"); } return "Método sendTextMessage existe y es accesible"; }); $this->serviceTest("Validación de estructura de template message", function() { if (!$this->whatsappService) { $this->whatsappService = new WhatsAppService(); } $reflection = new ReflectionClass($this->whatsappService); // Verificar que el método sendTemplateMessage existe if (!$reflection->hasMethod('sendTemplateMessage')) { throw new Exception("Método sendTemplateMessage no existe"); } $method = $reflection->getMethod('sendTemplateMessage'); $params = $method->getParameters(); // Verificar parámetros esperados $expectedParams = ['to', 'templateName', 'language', 'parameters']; if (count($params) < 2) { throw new Exception("sendTemplateMessage debe tener al menos 2 parámetros"); } return "Método sendTemplateMessage tiene estructura correcta"; }); $this->serviceTest("Test método buildMessage", function() { if (!$this->whatsappService) { $this->whatsappService = new WhatsAppService(); } $reflection = new ReflectionClass($this->whatsappService); if ($reflection->hasMethod('buildMessage')) { $method = $reflection->getMethod('buildMessage'); $method->setAccessible(true); // Test con datos de texto $textData = [ 'messaging_product' => 'whatsapp', 'to' => '573001234567', 'type' => 'text', 'text' => ['body' => 'Test message'] ]; $result = $method->invokeArgs($this->whatsappService, [$textData]); if ($result !== 'Test message') { throw new Exception("buildMessage no procesó correctamente mensaje de texto"); } return "buildMessage funciona correctamente"; } return "Método buildMessage no existe (puede ser privado o diferente implementación)"; }); $this->serviceTest("Configuración de tokens", function() { if (!defined('WHATSAPP_TOKEN') || empty(WHATSAPP_TOKEN) || WHATSAPP_TOKEN === 'TU_TOKEN_DE_WHATSAPP_AQUI') { throw new Exception("WHATSAPP_TOKEN no está configurado correctamente"); } if (!defined('WHATSAPP_PHONE_NUMBER_ID') || empty(WHATSAPP_PHONE_NUMBER_ID) || WHATSAPP_PHONE_NUMBER_ID === 'TU_PHONE_ID_AQUI') { throw new Exception("WHATSAPP_PHONE_NUMBER_ID no está configurado correctamente"); } if (!defined('WHATSAPP_API_URL') || empty(WHATSAPP_API_URL)) { throw new Exception("WHATSAPP_API_URL no está configurado"); } return "Todos los tokens de WhatsApp están configurados"; }); } private function testBotService() { echo "

🤖 Tests BotService

"; $this->serviceTest("Inicialización BotService", function() { $this->botService = new BotService(); if (!$this->botService) { throw new Exception("No se pudo crear instancia de BotService"); } return "BotService inicializado correctamente"; }); $this->serviceTest("Método processMessage existe", function() { if (!$this->botService) { $this->botService = new BotService(); } $reflection = new ReflectionClass($this->botService); if (!$reflection->hasMethod('processMessage')) { throw new Exception("Método processMessage no existe"); } $method = $reflection->getMethod('processMessage'); $params = $method->getParameters(); if (count($params) < 1) { throw new Exception("processMessage debe recibir al menos 1 parámetro"); } return "Método processMessage tiene estructura correcta"; }); $this->serviceTest("Test de respuestas automáticas", function() { // Verificar que hay respuestas automáticas configuradas $responses = $this->db->fetchAll( "SELECT * FROM autoresponses WHERE trigger_type = 'keyword'" ); if (empty($responses)) { throw new Exception("No hay respuestas automáticas configuradas"); } // Verificar estructura de respuestas $firstResponse = $responses[0]; $requiredFields = ['trigger_value', 'response_text']; foreach ($requiredFields as $field) { if (!isset($firstResponse[$field])) { throw new Exception("Campo requerido '$field' faltante en autoresponses"); } } return "Respuestas automáticas configuradas correctamente: " . count($responses) . " respuestas"; }); $this->serviceTest("Test procesamiento de menús", function() { // Verificar que hay menús configurados $menus = $this->db->fetchAll( "SELECT * FROM menus WHERE is_active = 1" ); if (empty($menus)) { throw new Exception("No hay menús activos configurados"); } // Verificar que el menú raíz existe $rootMenu = $this->db->fetch( "SELECT * FROM menus WHERE is_root = 1 AND is_active = 1" ); if (!$rootMenu) { throw new Exception("No hay menú raíz configurado"); } // Verificar opciones del menú raíz $options = $this->db->fetchAll( "SELECT * FROM menu_options WHERE menu_id = :id ORDER BY option_number", ['id' => $rootMenu['id']] ); return "Sistema de menús configurado: " . count($menus) . " menús, " . count($options) . " opciones en menú raíz"; }); $this->serviceTest("Test gestión de usuarios", function() { $testPhone = '573168950803'; // Crear usuario de prueba $userId = $this->db->insert('users', [ 'phone_number' => $testPhone, 'name' => 'Usite', 'status' => 'active', 'current_step' => 0, 'created_at' => date('Y-m-d H:i:s') ]); if (!$userId) { throw new Exception("No se pudo crear usuario de prueba"); } // Verificar que se creó correctamente $user = $this->db->fetch( "SELECT * FROM users WHERE id = :id", ['id' => $userId] ); if ($user['phone_number'] !== $testPhone) { throw new Exception("Usuario no se creó correctamente"); } // Test actualización de estado $updated = $this->db->update('users', ['current_step' => 1], 'id = :id', ['id' => $userId] ); if (!$updated) { throw new Exception("No se pudo actualizar usuario"); } // Limpiar $this->db->execute("DELETE FROM users WHERE id = :id", ['id' => $userId]); return "Gestión de usuarios funciona correctamente"; }); } private function testWebhookClass() { echo "

🔗 Tests Clase WhatsAppWebhook

"; $this->serviceTest("Clase WhatsAppWebhook existe", function() { if (!class_exists('WhatsAppWebhook')) { // Intentar cargar el archivo if (file_exists(__DIR__ . '/../api/webhook.php')) { // Cambiar directorio temporalmente $originalDir = getcwd(); chdir(__DIR__ . '/..'); include_once 'api/webhook.php'; // Restaurar directorio chdir($originalDir); } if (!class_exists('WhatsAppWebhook')) { throw new Exception("Clase WhatsAppWebhook no existe"); } } return "Clase WhatsAppWebhook disponible"; }); $this->serviceTest("Inicialización WhatsAppWebhook", function() { $webhook = new WhatsAppWebhook(); if (!$webhook) { throw new Exception("No se pudo crear instancia de WhatsAppWebhook"); } return "WhatsAppWebhook inicializado correctamente"; }); $this->serviceTest("Métodos requeridos en webhook", function() { $webhook = new WhatsAppWebhook(); $reflection = new ReflectionClass($webhook); $requiredMethods = ['handleRequest']; foreach ($requiredMethods as $method) { if (!$reflection->hasMethod($method)) { throw new Exception("Método requerido '$method' no existe en WhatsAppWebhook"); } } return "Webhook tiene todos los métodos requeridos"; }); $this->serviceTest("Token de verificación webhook", function() { if (!defined('WEBHOOK_VERIFY_TOKEN') || empty(WEBHOOK_VERIFY_TOKEN)) { throw new Exception("WEBHOOK_VERIFY_TOKEN no está definido"); } if (WEBHOOK_VERIFY_TOKEN === 'mi_token_secreto_123') { return "⚠️ Usando token por defecto - cambiar en producción"; } return "Token de webhook configurado correctamente"; }); } private function serviceTest($name, $callable) { try { $result = $callable(); echo "
$name: $result
"; } catch (Exception $e) { echo "
$name: " . $e->getMessage() . "
"; } } } // No ejecutar si es incluido por el runner principal if (basename($_SERVER['PHP_SELF']) === 'service_tests.php') { $configPath = __DIR__ . '/../config/config.php'; if (file_exists($configPath)) { require_once $configPath; } $suite = new ServiceTestSuite(); $suite->runAllServiceTests(); } ?>