#!/usr/bin/env node // Simulated E2E flow for Studio Panel // - POST /api/session to token server // - open studio receiver URL or studio page and assert token reception // - save screenshots to /tmp import fs from 'fs'; import fetch from 'node-fetch'; const TOKEN_SERVER = process.env.TOKEN_SERVER_URL || 'http://localhost:4000'; const STUDIO_BASE = process.env.STUDIO_URL || 'http://localhost:3020'; const TIMEOUT = Number(process.env.E2E_TIMEOUT_MS || 30000); function log(...args) { console.log(new Date().toISOString(), ...args); } async function createSession() { log('Creating session at', TOKEN_SERVER); const res = await fetch(`${TOKEN_SERVER}/api/session`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ room: 'e2e-room', username: 'sim-scripter' }) }); if (!res.ok) { const t = await res.text(); throw new Error(`Token server returned ${res.status}: ${t}`); } const body = await res.json(); log('Session created:', body.id || '(no id)', 'studioUrl=', body.studioUrl); return body; } async function runPlaywright(url) { log('Attempting Playwright flow for', url); let playwright; try { playwright = await import('playwright'); } catch (e) { log('Playwright not available:', e.message); return { available: false }; } const { chromium } = playwright; const browser = await chromium.launch({ headless: true }); const context = await browser.newContext(); const page = await context.newPage(); const resp = await page.goto(url, { waitUntil: 'domcontentloaded', timeout: TIMEOUT }); log('Page loaded status', resp && resp.status()); // try to find #status text try { const status = page.locator('#status'); await status.waitFor({ timeout: 5000 }); const txt = await status.textContent(); log('#status text:', txt && txt.slice(0,200)); } catch (e) { log('No #status element or timeout:', e.message); } const shot = `/tmp/e2e_playwright_${Date.now()}.png`; await page.screenshot({ path: shot, fullPage: true }); log('Saved screenshot', shot); await browser.close(); return { available: true, screenshot: shot }; } async function fallbackHttp(url, sessionId, token) { log('Fallback HTTP: GET', url); try { const r = await fetch(url); log('GET status', r.status, 'content-type', r.headers.get('content-type')); const txt = await r.text(); const found = txt.includes('Token recibido') || txt.includes('LIVEKIT_TOKEN') || txt.includes(token); log('Token present in body?', found); const shotPath = `/tmp/e2e_http_${Date.now()}.html`; fs.writeFileSync(shotPath, txt); log('Saved page HTML to', shotPath); return { ok: true, found, path: shotPath }; } catch (e) { log('HTTP fallback failed', e.message); return { ok: false, error: e.message }; } } (async () => { try { const session = await createSession(); const studioUrl = session.redirectUrl || session.studioUrl || (session.id ? `${STUDIO_BASE}/${session.id}` : null); if (!studioUrl) throw new Error('No studio url returned by token server'); // Prefer Playwright flow const pw = await runPlaywright(studioUrl); if (pw.available) { log('Playwright flow done'); process.exit(0); } // fallback: HTTP check const fb = await fallbackHttp(studioUrl, session.id, session.token || ''); if (fb.ok) process.exit(0); process.exit(2); } catch (err) { log('E2E error', err.message); process.exit(1); } })();