// Real-URL smoke against https://canvas.flow-master.ai. // Runs Playwright with a forced DNS resolution so the local box's DNS cache // doesn't shadow the just-published A record. import { chromium } from "playwright"; const URL = "https://canvas.flow-master.ai/"; const FORCE_IP = "65.21.71.186"; function ok(label, cond, detail = "") { console.log(`${cond ? "✓" : "✗"} ${label}${detail ? " · " + detail : ""}`); if (!cond) process.exitCode = 1; } const b = await chromium.launch({ headless: true, args: [ `--host-resolver-rules=MAP canvas.flow-master.ai ${FORCE_IP}`, "--ignore-certificate-errors", ], }); const p = await b.newPage({ viewport: { width: 1440, height: 900 } }); const errors = []; p.on("pageerror", (e) => errors.push(`pageerror ${e.message}`)); p.on("console", (m) => { if (m.type() === "error") errors.push(`console.error ${m.text().slice(0, 200)}`); }); await p.goto(URL, { waitUntil: "networkidle" }); ok("landing renders at canvas.flow-master.ai", await p.locator(".landing").isVisible()); ok("hero title present", await p.locator(".hero-title").isVisible()); const cards = await p.locator(".sc-card").count(); ok("scenario cards >= 7", cards >= 7, `count=${cards}`); await p.locator(".sc-card").first().click(); await p.waitForSelector(".mc"); await p.waitForTimeout(600); ok("mission control loaded", await p.locator(".mc-strip").isVisible()); ok("blueprint canvas mounted", await p.locator(".bp-frame").isVisible()); const nodes = await p.locator(".bp-node").count(); ok("blueprint nodes rendered", nodes >= 3, `nodes=${nodes}`); // Live mode: real /api hit through nginx proxy at canvas const networkCalls = []; p.on("request", (req) => { if (req.url().includes("/api/")) networkCalls.push(req.url()); }); await p.locator(".mode-toggle").first().click(); const liveOk = await p.waitForFunction( () => Array.from(document.querySelectorAll(".mode-pill")).some((el) => el.textContent?.trim() === "LIVE"), { timeout: 15000 }, ).then(() => true).catch(() => false); ok("LIVE mode resolves against canvas /api proxy", liveOk); ok("at least one /api call observed", networkCalls.length > 0, `count=${networkCalls.length}`); await p.screenshot({ path: "qa/screenshots/canvas-live.png" }); console.log(`\nconsole errors: ${errors.length}`); errors.slice(0, 5).forEach((e) => console.log(" -", e)); await b.close();