- Add Next.js app structure with base configs, linting, and formatting - Implement LiveKit Meet page, types, and utility functions - Add Docker, Compose, and deployment scripts for backend and token server - Provide E2E and smoke test scaffolding with Puppeteer and Playwright helpers - Include CSS modules and global styles for UI - Add postMessage and studio integration utilities - Update package.json with dependencies and scripts for development and testing
121 lines
5.0 KiB
JavaScript
121 lines
5.0 KiB
JavaScript
// Simple E2E that uses backend-api to create a session, then opens a data: HTML page
|
|
// with a button "Entrar al Estudio" that opens the studioUrl. It clicks the button and
|
|
// verifies a new page/tab opened with that URL.
|
|
|
|
const fetch = require('node-fetch');
|
|
const puppeteer = require('puppeteer-core');
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
const LOG_DIR = path.resolve(process.cwd(), 'packages', 'broadcast-panel', 'tmp');
|
|
if (!fs.existsSync(LOG_DIR)) fs.mkdirSync(LOG_DIR, { recursive: true });
|
|
const LOG_FILE = path.join(LOG_DIR, 'e2e_mock_ui.log');
|
|
function log(...args) {
|
|
const s = `[${new Date().toISOString()}] ${args.join(' ')}\n`;
|
|
fs.appendFileSync(LOG_FILE, s);
|
|
console.log(...args);
|
|
}
|
|
|
|
(async () => {
|
|
try {
|
|
const backend = process.env.BACKEND_URL || 'http://127.0.0.1:4000';
|
|
log('Using backend:', backend);
|
|
|
|
// create session
|
|
const createResp = await fetch(`${backend}/api/session`, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ room: 'mock-room', username: 'e2e-mock' })
|
|
});
|
|
if (!createResp.ok) {
|
|
const t = await createResp.text();
|
|
throw new Error('Create session failed: ' + createResp.status + ' ' + t);
|
|
}
|
|
const createJson = await createResp.json();
|
|
log('Create response:', JSON.stringify(createJson));
|
|
const studioUrl = createJson.studioUrl || createJson.redirectUrl;
|
|
if (!studioUrl) throw new Error('studioUrl not found in create response');
|
|
|
|
// Prepare mock HTML with override hook placeholder (we will set override from puppeteer)
|
|
const html = `<!doctype html><html><head><meta charset="utf-8"><title>Mock Broadcast</title></head><body>
|
|
<h1>Mock Broadcast Panel</h1>
|
|
<button id="enter">Entrar al Estudio</button>
|
|
<script>
|
|
const url = ${JSON.stringify(studioUrl)};
|
|
document.getElementById('enter').addEventListener('click', () => {
|
|
// window.open may be overridden by test runner
|
|
if (typeof window.__TEST_OPEN === 'function') {
|
|
window.__TEST_OPEN(url);
|
|
} else {
|
|
window.open(url, '_blank');
|
|
}
|
|
});
|
|
</script>
|
|
</body></html>`;
|
|
|
|
// connect to browser
|
|
const browserUrl = process.env.PUPPETEER_BROWSER_URL; // e.g. http://127.0.0.1:9222
|
|
const browserWSEndpoint = process.env.BROWSERLESS_WSE || (process.env.BROWSERLESS_TOKEN ? `wss://browserless.bfzqqk.easypanel.host?token=${process.env.BROWSERLESS_TOKEN}` : undefined);
|
|
let browser;
|
|
if (browserUrl) {
|
|
log('Connecting to browser via browserURL:', browserUrl);
|
|
browser = await puppeteer.connect({ browserURL: browserUrl, defaultViewport: { width: 1280, height: 800 } });
|
|
} else if (browserWSEndpoint) {
|
|
log('Connecting to browserless via WSEndpoint:', browserWSEndpoint);
|
|
browser = await puppeteer.connect({ browserWSEndpoint, defaultViewport: { width: 1280, height: 800 } });
|
|
} else {
|
|
// fallback: try to launch local chrome (may fail in CI)
|
|
log('No remote browser configured, attempting local launch');
|
|
browser = await puppeteer.launch({ headless: false });
|
|
}
|
|
|
|
const page = await browser.newPage();
|
|
page.on('console', msg => log('PAGE_CONSOLE', msg.type(), msg.text()));
|
|
page.on('pageerror', err => log('PAGE_ERROR', err && err.stack ? err.stack : err));
|
|
|
|
// Ensure override is present before any script runs on the page
|
|
await page.evaluateOnNewDocument(() => {
|
|
(window as any).__TEST_OPEN = (u: string) => { (window as any).__LAST_OPENED = u; };
|
|
});
|
|
|
|
// set page content (more reliable than data URL for popup handling)
|
|
log('Setting page content (html)');
|
|
await page.setContent(html, { waitUntil: 'networkidle0' });
|
|
log('Mock page loaded.');
|
|
|
|
const btn = await page.waitForSelector('#enter', { timeout: 5000 });
|
|
await btn.click();
|
|
log('Clicked enter button. Waiting for __LAST_OPENED...');
|
|
|
|
// give a small delay for the page script to call __TEST_OPEN
|
|
await page.waitForTimeout(500);
|
|
|
|
const openedUrl = await page.evaluate(() => (window as any).__LAST_OPENED || '');
|
|
log('Captured openedUrl from page context:', openedUrl);
|
|
|
|
if (!openedUrl) {
|
|
log('WARNING: No opened URL captured from page context. Trying to detect popup...');
|
|
const pages = await browser.pages();
|
|
log('Open pages count after click:', pages.length);
|
|
if (pages.length > 1) {
|
|
const popup = pages[pages.length - 1];
|
|
const popupUrl = popup.url();
|
|
log('Popup URL:', popupUrl);
|
|
}
|
|
} else {
|
|
if (openedUrl.indexOf(studioUrl) === -1 && openedUrl.indexOf('/' + createJson.id) === -1) {
|
|
log('WARNING: opened URL does not match expected studioUrl', studioUrl);
|
|
} else {
|
|
log('SUCCESS: openedUrl matches expected studioUrl/session');
|
|
}
|
|
}
|
|
|
|
// cleanup
|
|
try { await browser.disconnect(); } catch(e) { try { await browser.close(); } catch(e2) {} }
|
|
process.exit(0);
|
|
} catch (err) {
|
|
log('FATAL', err && err.stack ? err.stack : err);
|
|
process.exit(1);
|
|
}
|
|
})();
|