Files
whatsapp/tests/service_tests.php
T
2026-01-21 08:28:54 -05:00

380 lines
14 KiB
PHP

<?php
/**
* Tests para WhatsAppService y BotService
* Fecha: 3 de enero de 2026
*/
class ServiceTestSuite {
private $whatsappService;
private $botService;
private $db;
public function __construct() {
$this->db = Database::getInstance();
}
public function runAllServiceTests() {
echo "<h2>🔧 Tests Exhaustivos de Servicios</h2>";
$this->testWhatsAppService();
$this->testBotService();
$this->testWebhookClass();
}
private function testWhatsAppService() {
echo "<h3>📱 Tests WhatsAppService</h3>";
$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 "<h3>🤖 Tests BotService</h3>";
$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 "<h3>🔗 Tests Clase WhatsAppWebhook</h3>";
$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 "<div class='alert alert-success'><i class='fas fa-check-circle'></i> <strong>$name:</strong> $result</div>";
} catch (Exception $e) {
echo "<div class='alert alert-danger'><i class='fas fa-times-circle'></i> <strong>$name:</strong> " . $e->getMessage() . "</div>";
}
}
}
// 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();
}
?>