- 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
122 lines
4.4 KiB
JavaScript
122 lines
4.4 KiB
JavaScript
// e2e/run_e2e_with_mock.js
|
|
// Starts an express mock server in-process, runs the local validator against it, then shuts down.
|
|
const express = require('express');
|
|
const bodyParser = require('body-parser');
|
|
const path = require('path');
|
|
const { spawn } = require('child_process');
|
|
|
|
async function startMock(port = 4001) {
|
|
const app = express();
|
|
app.use(bodyParser.json());
|
|
|
|
const sessions = new Map();
|
|
function generateId() { return 's' + Math.random().toString(36).slice(2,9); }
|
|
|
|
app.post('/api/session', (req, res) => {
|
|
const body = req.body || {};
|
|
const id = generateId();
|
|
const token = 'mocktoken-' + Math.random().toString(36).slice(2,12);
|
|
sessions.set(id, { token, room: body.room || 'room', username: body.username || 'user' });
|
|
const studioUrl = `http://localhost:${port}/studio/${id}`;
|
|
res.json({ id, studioUrl, redirectUrl: studioUrl, ttlSeconds: 300 });
|
|
});
|
|
|
|
app.get('/api/session/:id/token', (req, res) => {
|
|
const id = req.params.id;
|
|
const s = sessions.get(id);
|
|
if (!s) return res.status(404).json({ error: 'not_found' });
|
|
res.json({ token: s.token, ttlSeconds: 300, room: s.room, username: s.username, url: `ws://localhost:7880` });
|
|
});
|
|
|
|
app.get('/broadcast', (req, res) => {
|
|
res.setHeader('Content-Type', 'text/html');
|
|
res.send(`<!doctype html>
|
|
<html>
|
|
<head><meta charset="utf-8"><title>Mock Broadcast</title></head>
|
|
<body>
|
|
<h1>Broadcast Panel - Mock</h1>
|
|
<a id="enter" href="#">Entrar al estudio</a>
|
|
<script>
|
|
document.getElementById('enter').addEventListener('click', async () => {
|
|
try {
|
|
const r = await fetch('/api/session', { method: 'POST', headers: {'Content-Type':'application/json'}, body: JSON.stringify({ room: 'mock', username: 'tester' }) });
|
|
const j = await r.json();
|
|
const win = window.open(j.redirectUrl, '_blank');
|
|
setTimeout(() => {
|
|
try { win.postMessage({ type: 'LIVEKIT_PING' }, '*'); } catch(e){}
|
|
}, 500);
|
|
} catch (e) { console.error('create session error', e); }
|
|
});
|
|
window.addEventListener('message', (e) => { console.log('Broadcast received message', e.data); });
|
|
</script>
|
|
</body>
|
|
</html>`);
|
|
});
|
|
|
|
app.get('/studio/:id', (req, res) => {
|
|
const id = req.params.id;
|
|
res.setHeader('Content-Type', 'text/html');
|
|
res.send(`<!doctype html>
|
|
<html>
|
|
<head><meta charset="utf-8"><title>Mock Studio ${id}</title></head>
|
|
<body>
|
|
<h1>Studio Portal - Mock</h1>
|
|
<div id="status">loading...</div>
|
|
<script>
|
|
async function init() {
|
|
const parts = location.pathname.split('/');
|
|
const id = parts[parts.length - 1];
|
|
const qs = new URLSearchParams(location.search);
|
|
let token = qs.get('token');
|
|
if (!token) {
|
|
try {
|
|
const resp = await fetch('/api/session/' + id + '/token');
|
|
if (resp.ok) { const j = await resp.json(); token = j.token; }
|
|
} catch(e) { console.error('token fetch error', e); }
|
|
}
|
|
document.getElementById('status').innerText = token ? ('token=' + token) : 'no token';
|
|
try { if (window.opener) { window.opener.postMessage({ type: 'LIVEKIT_ACK', status: token ? 'connected' : 'error', token }, '*'); } } catch(e){}
|
|
}
|
|
window.addEventListener('message', (e)=>{ if (e.data && e.data.type === 'LIVEKIT_PING') { try { window.opener && window.opener.postMessage({ type: 'LIVEKIT_READY' }, '*'); } catch(e){} } });
|
|
init();
|
|
</script>
|
|
</body>
|
|
</html>`);
|
|
});
|
|
|
|
return new Promise((resolve, reject) => {
|
|
const server = app.listen(port, () => {
|
|
console.log('Mock server listening on', port);
|
|
resolve(server);
|
|
});
|
|
server.on('error', reject);
|
|
});
|
|
}
|
|
|
|
(async () => {
|
|
const port = 4001;
|
|
let server;
|
|
try {
|
|
server = await startMock(port);
|
|
} catch (err) {
|
|
console.error('Failed to start mock', err);
|
|
process.exit(1);
|
|
}
|
|
|
|
console.log('Running local validator against mock...');
|
|
const env = Object.assign({}, process.env, {
|
|
BROADCAST_URL: `http://localhost:${port}/broadcast`,
|
|
TOKEN: 'mock-runner-token-1',
|
|
STUDIO_URL: `http://localhost:${port}/studio`,
|
|
});
|
|
|
|
const child = spawn(process.execPath, [path.join(__dirname, 'validate-flow-domains-local.js')], { env, stdio: 'inherit' });
|
|
child.on('exit', (code) => {
|
|
console.log('Validator exited with', code);
|
|
server.close(() => {
|
|
console.log('Mock server stopped');
|
|
process.exit(code || 0);
|
|
});
|
|
});
|
|
})();
|