diff --git a/test-live.mjs b/test-live.mjs new file mode 100644 index 0000000..475b96c --- /dev/null +++ b/test-live.mjs @@ -0,0 +1,136 @@ +import http from 'http'; +import { spawn } from 'child_process'; + +const PORT = 3055; +const BASE_URL = `http://127.0.0.1:${PORT}`; + +async function sleep(ms) { + return new Promise((resolve) => setTimeout(resolve, ms)); +} + +async function request(path, options = {}) { + const url = `${BASE_URL}${path}`; + const headers = { 'Content-Type': 'application/json', ...(options.headers || {}) }; + const res = await fetch(url, { + method: options.method || 'GET', + headers, + body: options.body ? JSON.stringify(options.body) : undefined, + }); + const data = await res.json().catch(() => ({ text: '' })); + return { status: res.status, ok: res.ok, data }; +} + +async function runTests() { + console.log('🧪 Iniciando pruebas automáticas de funcionalidad en vivo...'); + + // 1. Levantar servidor en puerto dedicado 3055 + const serverProcess = spawn('node', ['dist-server/index.js'], { + env: { ...process.env, PORT: String(PORT), NODE_ENV: 'production' }, + stdio: 'pipe', + }); + + serverProcess.stdout.on('data', (d) => process.stdout.write(`[SERVER] ${d}`)); + serverProcess.stderr.on('data', (d) => process.stderr.write(`[SERVER ERR] ${d}`)); + + await sleep(2000); + + try { + // 2. Health check + console.log('\n1. Test Health Check:'); + const health = await request('/api/health'); + console.log(' Status:', health.status, 'Response:', JSON.stringify(health.data)); + if (!health.ok || health.data.status !== 'ok') throw new Error('Health check failed'); + console.log(' ✅ Health check OK'); + + // 3. Obtener votos iniciales + console.log('\n2. Test GET /api/votes:'); + const initialVotes = await request('/api/votes'); + console.log(' Initial votes count:', initialVotes.data.total); + console.log(' ✅ GET /api/votes OK'); + + // 4. Conectar al stream Server-Sent Events (SSE) + console.log('\n3. Test Live SSE Stream (/api/stream):'); + let sseReceivedCount = 0; + const sseReq = http.get(`${BASE_URL}/api/stream`, (res) => { + res.on('data', (chunk) => { + const text = chunk.toString(); + if (text.includes('event: votes') || text.includes('event: initial')) { + sseReceivedCount++; + console.log(` ⚡ Evento SSE recibido en tiempo real! (total eventos: ${sseReceivedCount})`); + } + }); + }); + + await sleep(500); + + // 5. Emitir Voto Válido 1 (SERVANDO vota por ANNA) + console.log('\n4. Test Emitir Voto (SERVANDO -> ANNA):'); + const vote1 = await request('/api/vote', { + method: 'POST', + body: { voter: 'SERVANDO PEREZ', candidate: 'ANNA' }, + }); + console.log(' Vote 1 status:', vote1.status, 'Data:', vote1.data); + if (!vote1.ok || !vote1.data.success) throw new Error('Vote 1 failed'); + console.log(' ✅ Voto 1 registrado'); + + await sleep(400); + + // 6. Emitir Voto Válido 2 (MELINA vota por URIEL) + console.log('\n5. Test Emitir Voto (MELINA -> URIEL):'); + const vote2 = await request('/api/vote', { + method: 'POST', + body: { voter: 'MELINA GOMEZ', candidate: 'URIEL' }, + }); + console.log(' Vote 2 status:', vote2.status, 'Data:', vote2.data); + if (!vote2.ok || !vote2.data.success) throw new Error('Vote 2 failed'); + console.log(' ✅ Voto 2 registrado'); + + await sleep(400); + + // 7. Test Anti-Autovoto (URIEL intenta votar por URIEL) + console.log('\n6. Test Bloqueo de Autovoto (URIEL -> URIEL):'); + const selfVote = await request('/api/vote', { + method: 'POST', + body: { voter: 'URIEL JARETH', candidate: 'URIEL' }, + }); + console.log(' Self-vote status:', selfVote.status, 'Data:', selfVote.data); + if (selfVote.status !== 400) throw new Error('Anti-autovoto no bloqueó la petición'); + console.log(' ✅ Autovoto bloqueado correctamente con 400 Bad Request'); + + // 8. Verificar lista de votos actualizada + console.log('\n7. Test Verificación de Conteo y Persistencia:'); + const updatedVotes = await request('/api/votes'); + console.log(' Votos registrados:', updatedVotes.data.votes); + if (updatedVotes.data.total < 2) throw new Error('Total de votos incorrecto'); + console.log(' ✅ Conteo verificado: Total =', updatedVotes.data.total); + + // 9. Test Restablecer Voto (Admin DELETE) + console.log('\n8. Test Panel Admin - Restablecer Voto (/api/vote/:voter):'); + const deleteRes = await request('/api/vote/SERVANDO%20PEREZ', { + method: 'DELETE', + headers: { 'x-admin-key': 'RESETEOE3' }, + }); + console.log(' Delete status:', deleteRes.status, 'Data:', deleteRes.data); + if (!deleteRes.ok) throw new Error('Delete vote failed'); + console.log(' ✅ Voto de SERVANDO restablecido'); + + await sleep(500); + + // 10. Confirmar estado final + const finalVotes = await request('/api/votes'); + console.log('\n9. Estado final de votos:', finalVotes.data.votes); + + sseReq.destroy(); + + console.log('\n========================================='); + console.log('🎉 TODAS LAS PRUEBAS EN VIVO PASARON CON ÉXITO (100% FUNCIONAL)'); + console.log('=========================================\n'); + } finally { + serverProcess.kill(); + } +} + +runTests().catch((err) => { + console.error('❌ Error en pruebas:', err); + process.exit(1); +});