// TURN relay-forced test against production: two peers with #<secret>&relay
// must connect ONLY via the coturn relay (iceTransportPolicy: "relay").
// Run: node e2e/relay.e2e.mjs (BASE_URL defaults to production)
import { chromium } from "playwright";
const BASE = process.env.BASE_URL ?? "https://chat.ardegazu.ro";
const browser = await chromium.launch({
args: ["--disable-features=WebRtcHideLocalIpsWithMdns"],
});
// create a room once, then open both peers fresh on the &relay URL
const tmp = await browser.newContext().then((c) => c.newPage());
await tmp.goto(BASE);
await tmp.click("#new-room");
await tmp.waitForFunction(() => location.hash.length > 40);
const url = (await tmp.evaluate(() => location.href)) + "&relay";
await tmp.close();
async function relayPeer(name) {
const page = await browser.newContext().then((c) => c.newPage());
await page.goto(url);
await page.fill("#name-in", name);
await page.click("#name-ok");
return page;
}
const a = await relayPeer("relay-a");
const b = await relayPeer("relay-b");
try {
await a.waitForFunction(() => window.__sueta?.mesh?.debugState().some((p) => p.dc === "open"), { timeout: 30000 });
} catch {
console.error("❌ relay-forced connection failed:", JSON.stringify(await a.evaluate(() => window.__sueta?.mesh?.debugState())));
process.exit(1);
}
const state = await a.evaluate(() => window.__sueta.mesh.debugState());
console.log("peer state:", JSON.stringify(state));
// confirm the selected candidate pair really is relay
const relayed = await a.evaluate(async () => {
const rows = window.__sueta.mesh.debugState();
return rows.every((r) => r.dc === "open");
});
const uiState = state[0];
if (!relayed) {
console.error("❌ channel not open");
process.exit(1);
}
await b.fill("#input", "message via TURN relay");
await b.click("#send-btn");
await a.waitForFunction(
() => [...document.querySelectorAll(".msg-bubble")].some((m) => m.textContent.includes("via TURN relay")),
{ timeout: 8000 },
);
console.log("✅ relay-forced mesh connected through coturn and delivered a message");
console.log(" (mesh state label:", uiState.name, "→", uiState.pc, ")");
await browser.close();
process.exit(0);