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

📝 Tests Exhaustivos de Sistema de Plantillas

"; $this->testTemplateDatabase(); $this->testTemplateAPIs(); $this->testTemplateValidation(); $this->testTemplateIntegration(); $this->testTemplateWorkflow(); // Limpiar plantillas de prueba $this->cleanup(); } private function testTemplateDatabase() { echo "

💾 Tests de Base de Datos de Plantillas

"; $this->templateTest("Estructura tabla message_templates", function() { $columns = $this->db->fetchAll("DESCRIBE message_templates"); $requiredColumns = [ 'id', 'name', 'template_name', 'language_code', 'category', 'status', 'created_at' ]; $existingColumns = array_column($columns, 'Field'); foreach ($requiredColumns as $col) { if (!in_array($col, $existingColumns)) { throw new Exception("Columna requerida '$col' faltante"); } } // Verificar tipos de datos $statusColumn = array_filter($columns, function($col) { return $col['Field'] === 'status'; }); $statusColumn = array_values($statusColumn)[0]; if (strpos($statusColumn['Type'], 'enum') === false) { throw new Exception("Columna status debería ser ENUM"); } if (strpos($statusColumn['Type'], 'pending') === false || strpos($statusColumn['Type'], 'approved') === false || strpos($statusColumn['Type'], 'rejected') === false) { throw new Exception("Estados de plantilla incorrectos en ENUM"); } return "Estructura de tabla message_templates correcta"; }); $this->templateTest("CRUD básico en message_templates", function() { $testName = 'Test CRUD Template ' . time(); // CREATE $id = $this->db->insert('message_templates', [ 'name' => $testName, 'template_name' => 'test_crud_' . time(), 'language_code' => 'es', 'category' => 'utility', 'status' => 'pending' ]); if (!$id) { throw new Exception("No se pudo insertar plantilla"); } $this->testTemplateIds[] = $id; // READ $template = $this->db->fetch( "SELECT * FROM message_templates WHERE id = :id", ['id' => $id] ); if ($template['name'] !== $testName) { throw new Exception("Datos incorrectos al leer plantilla"); } // UPDATE $updated = $this->db->update('message_templates', ['status' => 'approved'], ['id' => $id] ); if (!$updated) { throw new Exception("No se pudo actualizar plantilla"); } // Verificar actualización $updatedTemplate = $this->db->fetch( "SELECT status FROM message_templates WHERE id = :id", ['id' => $id] ); if ($updatedTemplate['status'] !== 'approved') { throw new Exception("Estado no se actualizó correctamente"); } // DELETE se hace en cleanup() return "CRUD completo en message_templates funciona"; }); $this->templateTest("Constrains y validaciones", function() { // Test unicidad de nombre $duplicateName = 'Unique Test ' . time(); $id1 = $this->db->insert('message_templates', [ 'name' => $duplicateName, 'template_name' => 'unique_test_1', 'language_code' => 'es', 'status' => 'pending' ]); $this->testTemplateIds[] = $id1; // Intentar insertar duplicado try { $id2 = $this->db->insert('message_templates', [ 'name' => $duplicateName, 'template_name' => 'unique_test_2', 'language_code' => 'es', 'status' => 'pending' ]); if ($id2) { $this->testTemplateIds[] = $id2; throw new Exception("Se permitió nombre duplicado"); } } catch (Exception $e) { // Error esperado por constraint if (strpos($e->getMessage(), 'Duplicate') !== false || strpos($e->getMessage(), 'UNIQUE') !== false) { return "Constraint de unicidad funciona correctamente"; } throw $e; } return "Validaciones de base de datos funcionan"; }); } private function testTemplateAPIs() { echo "

🔌 Tests de APIs de Plantillas

"; // Configurar sesión de admin $_SESSION['admin_logged_in'] = true; $_SESSION['last_activity'] = time(); $this->templateTest("API get_templates.php", function() { ob_start(); include 'api/get_templates.php'; $output = ob_get_clean(); $templates = json_decode($output, true); if (!is_array($templates)) { throw new Exception("get_templates debe retornar array JSON"); } return "API get_templates responde correctamente"; }); $this->templateTest("API save_template.php - plantilla válida", function() { $testData = [ 'name' => 'API Test Template ' . time(), 'template_name' => 'api_test_' . time(), 'language_code' => 'es', 'category' => 'utility' ]; $_POST = $testData; $GLOBALS['HTTP_RAW_POST_DATA'] = json_encode($testData); $_SERVER['REQUEST_METHOD'] = 'POST'; ob_start(); try { include 'api/save_template.php'; $output = ob_get_clean(); $result = json_decode($output, true); if (!$result['success']) { throw new Exception("Error creando plantilla: " . ($result['error'] ?? 'Unknown')); } // Verificar que se creó en BD $created = $this->db->fetch( "SELECT * FROM message_templates WHERE name = :name", ['name' => $testData['name']] ); if (!$created) { throw new Exception("Plantilla no se guardó en base de datos"); } $this->testTemplateIds[] = $created['id']; return "API save_template crea plantilla correctamente"; } finally { unset($_POST); unset($GLOBALS['HTTP_RAW_POST_DATA']); ob_end_clean(); } }); $this->templateTest("API save_template.php - validaciones", function() { $invalidData = [ ['name' => '', 'template_name' => 'test', 'error_expected' => 'nombre es requerido'], ['name' => 'Test', 'template_name' => '', 'error_expected' => 'nombre de la plantilla'], [/* datos vacíos */ 'error_expected' => 'inválidos'] ]; foreach ($invalidData as $testCase) { $_POST = $testCase; unset($testCase['error_expected']); $GLOBALS['HTTP_RAW_POST_DATA'] = json_encode($testCase); $_SERVER['REQUEST_METHOD'] = 'POST'; ob_start(); try { include 'api/save_template.php'; $output = ob_get_clean(); $result = json_decode($output, true); if ($result['success']) { throw new Exception("Debería rechazar datos inválidos"); } } finally { unset($_POST); unset($GLOBALS['HTTP_RAW_POST_DATA']); } } return "API save_template valida datos correctamente"; }); $this->templateTest("API update_template_status.php", function() { // Crear plantilla para probar $id = $this->db->insert('message_templates', [ 'name' => 'Status Update Test', 'template_name' => 'status_update_test', 'language_code' => 'es', 'status' => 'pending' ]); $this->testTemplateIds[] = $id; $updateData = [ 'id' => $id, 'status' => 'approved' ]; $_POST = $updateData; $GLOBALS['HTTP_RAW_POST_DATA'] = json_encode($updateData); $_SERVER['REQUEST_METHOD'] = 'POST'; ob_start(); try { include 'api/update_template_status.php'; $output = ob_get_clean(); $result = json_decode($output, true); if (!$result['success']) { throw new Exception("Error actualizando estado: " . ($result['error'] ?? 'Unknown')); } // Verificar actualización en BD $updated = $this->db->fetch( "SELECT status FROM message_templates WHERE id = :id", ['id' => $id] ); if ($updated['status'] !== 'approved') { throw new Exception("Estado no se actualizó en base de datos"); } return "API update_template_status funciona correctamente"; } finally { unset($_POST); unset($GLOBALS['HTTP_RAW_POST_DATA']); } }); } private function testTemplateValidation() { echo "✅ Tests de Validación de Plantillas"; $this->templateTest("Validación de nombres", function() { $invalidNames = [ '', // Vacío str_repeat('a', 200), // Muy largo '', // XSS 'SELECT * FROM users', // SQL-like 'template with \x00 null byte' ]; foreach ($invalidNames as $name) { try { $id = $this->db->insert('message_templates', [ 'name' => $name, 'template_name' => 'test_validation_' . time(), 'language_code' => 'es', 'status' => 'pending' ]); if ($id) { $this->testTemplateIds[] = $id; // Verificar que se sanitizó o rechazó apropiadamente $saved = $this->db->fetch( "SELECT name FROM message_templates WHERE id = :id", ['id' => $id] ); if ($saved['name'] === $name && ( strpos($name, '