// e2e/validate-session-id-flow.js // 1) create a session in token-server // 2) open broadcast panel at /:id // 3) verify sessionStorage contains session // 4) optionally fetch token endpoint and decode token const fs = require('fs'); const path = require('path'); const fetch = require('node-fetch'); const puppeteer = require('puppeteer-core'); (async ()=>{ const outDir = path.resolve(__dirname); const results = { startedAt: new Date().toISOString(), steps: [], console: [] }; const TOKEN_SERVER = process.env.TOKEN_SERVER_URL || 'https://avanzacast-servertokens.bfzqqk.easypanel.host'; const BROADCAST_BASE = process.env.BROADCAST_URL || 'https://avanzacast-broadcastpanel.bfzqqk.easypanel.host'; const BROWSER_WS = process.env.BROWSER_WS || process.env.BROWSERLESS_WS; const BROWSERLESS_TOKEN = process.env.BROWSERLESS_TOKEN || ''; if(!BROWSER_WS){ console.error('BROWSER_WS required'); process.exit(2); } let ws = BROWSER_WS; if(BROWSERLESS_TOKEN && ws.includes('?')) ws = `${ws}&token=${encodeURIComponent(BROWSERLESS_TOKEN)}`; else if(BROWSERLESS_TOKEN) ws = `${ws}?token=${encodeURIComponent(BROWSERLESS_TOKEN)}`; try{ // create session const room = 'e2e_room'; const username = 'e2e_user'; const createResp = await fetch(`${TOKEN_SERVER.replace(/\/$/, '')}/api/session`, { method:'POST', headers:{'Content-Type':'application/json'}, body: JSON.stringify({ room, username }) }); const createJson = await createResp.json(); results.steps.push({ name:'create_session', ok: createResp.ok, status:createResp.status, body:createJson }); if(!createResp.ok) { fs.writeFileSync(path.join(outDir,'validate-session-id-flow-result.json'), JSON.stringify(results,null,2)); process.exit(1); } const sessionId = createJson.id; // open browser const browser = await puppeteer.connect({ browserWSEndpoint: ws, ignoreHTTPSErrors:true }); const page = await browser.newPage(); page.on('console', m=> results.console.push({ type:m.type(), text:m.text() })); await page.goto(`${BROADCAST_BASE.replace(/\/$/, '')}/${encodeURIComponent(sessionId)}`, { waitUntil:'networkidle2' }); await page.waitForTimeout(1500); // read sessionStorage in page const storeKey = 'avanzacast_studio_session'; const stored = await page.evaluate((k)=> { try { return sessionStorage.getItem(k); } catch(e) { return null } }, storeKey); results.steps.push({ name:'sessionStorage', key: storeKey, value: stored ? JSON.parse(stored) : null }); // verify token endpoint const tokenResp = await fetch(`${TOKEN_SERVER.replace(/\/$/, '')}/api/session/${encodeURIComponent(sessionId)}/token`); const tokenJson = await tokenResp.json().catch(()=>null); results.steps.push({ name:'get_token', ok: tokenResp.ok, status: tokenResp.status, body: tokenJson }); // screenshot const shot = path.join(outDir,'validate-session-id-flow.png'); await page.screenshot({ path: shot, fullPage:true }); results.screenshot = shot; results.endedAt = new Date().toISOString(); const outJson = path.join(outDir,'validate-session-id-flow-result.json'); fs.writeFileSync(outJson, JSON.stringify(results,null,2)); await page.close(); await browser.disconnect(); console.log('Wrote', outJson); process.exit(0); }catch(err){ console.error('err', err); results.error = String(err && err.stack?err.stack:err); results.endedAt = new Date().toISOString(); fs.writeFileSync(path.join(outDir,'validate-session-id-flow-result.json'), JSON.stringify(results,null,2)); process.exit(1); } })();