import fs from 'fs'; let playwright; try { playwright = await import('playwright'); } catch (e) { fs.appendFileSync('/tmp/playwright_debug.log', `Playwright import error: ${e}\n`); process.exit(2); } const { chromium } = playwright; const LOG = '/tmp/playwright_debug.log'; function log(msg){ const line = `[${new Date().toISOString()}] ${msg}\n`; try{ fs.appendFileSync(LOG, line); } catch(e) {} } (async ()=>{ log('Starting playwright_postmessage_test'); let browser; try{ browser = await chromium.launch({ headless: true, args: ['--no-sandbox','--disable-dev-shm-usage'] }); log('Chromium launched'); const context = await browser.newContext(); const page = await context.newPage(); page.on('console', m => log('PAGE LOG: ' + m.text())); let studioConsoleLogs = []; // Use environment variables if provided, otherwise default to production domains const BROADCAST_URL = process.env.BROADCAST_URL || 'https://avanzacast-broadcastpanel.bfzqqk.easypanel.host/post_token_to_studio.html?auto=1'; const STUDIO_ORIGIN = process.env.STUDIO_ORIGIN || 'https://avanzacast-studio.bfzqqk.easypanel.host'; log('Navigating to broadcast URL: ' + BROADCAST_URL); await page.goto(BROADCAST_URL, { waitUntil: 'networkidle', timeout: 30000 }); log('Broadcast page loaded'); // Wait briefly for auto-run, otherwise click the open button if present try{ // if the page has a button with id 'run' or 'openSend', try to click it as fallback const runBtn = await page.$('#run') || await page.$('#openSend'); if (runBtn) { log('Found run/open button on page; clicking to trigger flow'); await runBtn.click(); } } catch(e){ log('No run button click fallback: ' + e); } // Wait up to 12s for the redirect to the studio (the broadcast page may open a popup or redirect) log('Waiting for a new page whose origin matches ' + STUDIO_ORIGIN + ' (timeout 12s)'); let studioPage = null; const start = Date.now(); const timeoutMs = 12000; while (!studioPage && (Date.now() - start) < timeoutMs){ const pages = context.pages(); for (const p of pages){ try{ const u = p.url(); if (u && u.startsWith(STUDIO_ORIGIN)) { studioPage = p; break; } }catch(e){} } if (studioPage) break; await new Promise(r=>setTimeout(r, 300)); } if (!studioPage){ log('Studio page not opened automatically; attempting to open studio receiver directly at ' + STUDIO_ORIGIN + '/studio_receiver.html'); // open the studio receiver in the same context studioPage = await context.newPage(); await studioPage.goto(STUDIO_ORIGIN + '/studio_receiver.html', { waitUntil: 'networkidle', timeout: 30000 }).catch(e=>{ log('Goto studio_receiver failed: '+e); }); } if (!studioPage) { log('ERROR: Could not open studio page'); } else { // capture console logs from studio page to detect connected/ACK messages studioPage.on('console', m => { try { const txt = m.text(); studioConsoleLogs.push(txt); log('STUDIO PAGE LOG: ' + txt); } catch(e) {} }); log('Studio page ready at ' + studioPage.url()); try{ // wait for #status element that studio_receiver exposes // try a slightly longer wait and fallback to scanning page text try { await studioPage.waitForSelector('#status', { timeout: 16000 }); } catch (e) { log('waitForSelector #status timed out, will fallback to scanning page content'); } const statusText = await studioPage.evaluate(() => { const el = document.getElementById('status'); if (el) return el.textContent; return document.body ? document.body.innerText || document.body.textContent : null; }).catch(()=>null); log('Studio #status text (initial): ' + statusText); } catch(e){ log('No #status element or timeout: ' + (e && e.message)); } // Now wait for the simulator page log (broadcast) to show ACK or for studio to update try{ // Wait up to 10s for ACK to appear in any page logs (simulator) or studio status const ackStart = Date.now(); let ackSeen = false; const ackTimeout = 20000; // increase to 20s while (!ackSeen && (Date.now() - ackStart) < ackTimeout){ // check studio console logs first try{ for (const cmsg of studioConsoleLogs){ if (cmsg && (cmsg.toLowerCase().includes('conectado') || cmsg.toLowerCase().includes('connected') || cmsg.toLowerCase().includes('ack'))) { ackSeen = true; log('ACK/connected found in studio console logs: ' + cmsg); break; } } }catch(e){} if (ackSeen) break; // check simulator page (first page) for log element try{ const simulatorPages = context.pages(); for (const sp of simulatorPages){ try{ const content = await sp.evaluate(()=>{ const el = document.getElementById('log'); if (el && el.textContent) return el.textContent; return document.body ? (document.body.innerText || document.body.textContent) : null; }); if (content && (content.includes('ACK') || /connected/i.test(content) || /conectado/i.test(content))) { ackSeen = true; log('ACK/connected found in simulator page content'); break; } }catch(e){} } }catch(e){ } // also check studio status try{ const s = await studioPage.evaluate(()=>{ const st = document.getElementById('status'); if (st && st.textContent) return st.textContent; return document.body ? (document.body.innerText || document.body.textContent) : null; }); if (s && (s.toLowerCase().includes('ack') || s.toLowerCase().includes('connected') || s.toLowerCase().includes('conectado'))) { ackSeen = true; log('ACK/connected found in studio content: '+s); } }catch(e){} if (!ackSeen) await new Promise(r=>setTimeout(r, 300)); } if (!ackSeen) log('Timeout waiting for ACK ('+ (ackTimeout/1000) +'s)'); } catch(e){ log('Error while waiting for ACK: '+e); } // take screenshots const simShot = '/tmp/sim_postmessage_simulator.png'; const studioShot = '/tmp/sim_postmessage_studio.png'; try{ await page.screenshot({ path: simShot, fullPage: true }); log('Saved simulator screenshot: ' + simShot); } catch(e){ log('Failed saving simulator screenshot: ' + e); } try{ await studioPage.screenshot({ path: studioShot, fullPage: true }); log('Saved studio screenshot: ' + studioShot); } catch(e){ log('Failed saving studio screenshot: ' + e); } } } catch (err) { log('Unhandled error: ' + (err && err.stack ? err.stack : String(err))); process.exitCode = 2; } finally { try { if (browser) await browser.close(); log('Browser closed'); } catch(e) { log('Error closing browser: ' + e); } } log('Test finished'); })();