import fetch from 'node-fetch'; import fs from 'fs'; const LOG_PATH = '/tmp/e2e_node_runner.log'; function log(...args) { try { fs.appendFileSync(LOG_PATH, args.map(a=>typeof a==='string'?a:JSON.stringify(a)).join(' ') + '\n') }catch(e){} console.log(...args) } let playwrightAvailable = true; let playwright = null; try { // dynamic import to allow fallback if playwright not installed playwright = await import('playwright'); } catch (err) { playwrightAvailable = false; log('Playwright not available, will fallback to HTTP checks:', String(err)); } const TOKEN_SERVER = process.env.TOKEN_SERVER_URL || 'http://localhost:4000'; const TIMEOUT = Number(process.env.E2E_TIMEOUT_MS || 30000); (async () => { try { log('Creating session at token server:', TOKEN_SERVER); const res = await fetch(`${TOKEN_SERVER}/api/session`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ room: 'e2e-room', username: 'node-runner' }) }); if (!res.ok) { log('Token server returned', res.status); log(await res.text()); process.exitCode = 2; return; } const body = await res.json(); log('Session created:', body); const url = body.redirectUrl || body.studioUrl || (body.id ? `${(process.env.STUDIO_URL||'http://localhost:3020')}/studio_receiver.html?token=${encodeURIComponent(body.token||'')}` : null); if (!url) { log('No redirectUrl'); process.exitCode = 3; return } // If playwright available, open browser and verify #status text if (playwrightAvailable && playwright) { log('Launching Playwright chromium'); const { chromium } = playwright; const browser = await chromium.launch({ headless: true }); const context = await browser.newContext(); const page = await context.newPage(); log('Opening studio page:', url); const resp = await page.goto(url, { waitUntil: 'domcontentloaded', timeout: TIMEOUT }); log('Loaded page status:', resp && resp.status()); const status = page.locator('#status'); try { await status.waitFor({ timeout: TIMEOUT }); const text = await status.textContent(); log('Status text:', (text||'').slice(0,400)); if ((text || '').includes('Token recibido')) { log('Studio received token OK'); } else { log('Studio status did not include expected text'); } } catch (err) { log('Timeout waiting for #status', String(err)); } const shot1 = '/tmp/e2e_studio_runner.png'; await page.screenshot({ path: shot1, fullPage: true }); log('Screenshot saved:', shot1); await browser.close(); process.exitCode = 0; return; } // Fallback: simple HTTP checks log('Playwright not available: performing HTTP-only checks for', url); try { const r = await fetch(url, { method: 'GET' }); log('GET redirectUrl status', r.status, 'content-type', r.headers.get('content-type')); const text = await r.text(); // look for token in body or in url const hasTokenInBody = /token=/.test(text) || /Token recibido/.test(text) || /LIVEKIT_ACK/.test(text); const hasTokenInUrl = /token=/.test(url); log('hasTokenInBody', hasTokenInBody, 'hasTokenInUrl', hasTokenInUrl); } catch (err) { log('Error fetching redirectUrl:', String(err)); } // Also check session retrieval via API if (body.id) { try { const s = await fetch(`${TOKEN_SERVER}/api/session/${body.id}`); log('/api/session/:id status', s.status); if (s.ok) { const js = await s.json(); log('session lookup:', js); } else log('session lookup failed'); } catch (err) { log('session lookup error', String(err)) } } process.exitCode = 0; } catch (err) { log('E2E runner error', String(err)); process.exitCode = 1; } })();