--- /dev/null
+import { chromium } from "playwright";
+
+const PUB = "https://aidemo.istation.cloud/t/stationbuilder/";
+
+const runOnce = async (n) => {
+ const browser = await chromium.launch();
+ const ctx = await browser.newContext();
+ const page = await ctx.newPage();
+ const started = new Map(); // url -> t
+ const done = new Map(); // url -> {status,size,enc,ms}
+ const failed = new Map();
+ page.on("request", (r) => { started.set(r.url(), Date.now()); });
+ page.on("response", (r) => {
+ const h = r.headers();
+ done.set(r.url(), { status: r.status(), size: Number(h["content-length"]||0), enc: h["content-encoding"]||"-", ms: Date.now()-(started.get(r.url())||Date.now()) });
+ });
+ page.on("requestfailed", (r) => { failed.set(r.url(), r.failure()?.errorText || "?"); });
+
+ const t0 = Date.now();
+ let resolved = null;
+ try {
+ await page.goto(PUB, { waitUntil: "commit", timeout: 60000 });
+ await page.waitForFunction(() => {
+ const els = Array.from(document.querySelectorAll(".empty-state"));
+ return !els.some(e => /加载中/.test(e.textContent||""));
+ }, undefined, { timeout: 60000 });
+ resolved = Date.now() - t0;
+ } catch (e) {
+ resolved = "TIMEOUT/HANG";
+ }
+
+ const hung = [...started.keys()].filter(u => !done.has(u) && !failed.has(u));
+ const apiDone = [...done.keys()].filter(u => u.includes("/api/"));
+ console.log(`\n===== run ${n}: resolved=${resolved}ms =====`);
+ console.log(`requests started=${started.size} done=${done.size} failed=${failed.size}`);
+ console.log(`API responses received: ${apiDone.length}`);
+ for (const u of apiDone) console.log(` API OK ${done.get(u).status} ${done.get(u).ms}ms ${u.replace(PUB,"").slice(0,70)}`);
+ if (failed.size) { console.log("failed:"); for (const [u,e] of failed) console.log(` ${e} ${u.replace(PUB,"").slice(0,90)}`); }
+ if (hung.length) {
+ console.log(`HUNG requests (${hung.length}) — sent but no response ever:`);
+ for (const u of hung) console.log(` HUNG [${((Date.now()-started.get(u))/1000).toFixed(0)}s] ${u.slice(0,110)}`);
+ // server-side check of same paths while browser is hung
+ console.log("server-side direct check of hung paths (from node, same moment):");
+ for (const u of hung.slice(0, 6)) {
+ const t = Date.now();
+ try {
+ const r = await fetch(u, { headers: { host: "aidemo.istation.cloud" }, signal: AbortSignal.timeout(8000) });
+ await r.text();
+ console.log(` direct ${r.status} in ${Date.now()-t}ms ${u.replace(PUB,"").slice(0,70)}`);
+ } catch (e) { console.log(` direct ERR ${Date.now()-t}ms ${e.message} ${u.replace(PUB,"").slice(0,70)}`); }
+ }
+ }
+ // slowest responses
+ const slow = [...done.entries()].filter(([,v])=>v.ms>3000).sort((a,b)=>b[1].ms-a[1].ms).slice(0,6);
+ if (slow.length) { console.log("responses slower than 3s:"); for (const [u,v] of slow) console.log(` ${v.ms}ms ${(v.size/1024).toFixed(0)}KB ${u.replace(PUB,"").slice(0,80)}`); }
+ await browser.close();
+};
+
+for (let i = 1; i <= 3; i++) await runOnce(i);
+process.exit(0);
--- /dev/null
+import { chromium } from "playwright";
+
+const PUB = "https://aidemo.istation.cloud/t/stationbuilder/";
+
+const browser = await chromium.launch();
+const ctx = await browser.newContext();
+const page = await ctx.newPage();
+let wireBytes = 0, reqCount = 0;
+page.on("response", async (r) => {
+ reqCount++;
+ wireBytes += Number(r.headers()["content-length"] || 0);
+});
+const t0 = Date.now();
+await page.goto(PUB, { waitUntil: "commit", timeout: 60000 });
+// real completion: app shell mounted AND no 加载中 anywhere
+await page.waitForSelector(".company-side-nav", { timeout: 60000 });
+await page.waitForFunction(() => {
+ const els = Array.from(document.querySelectorAll(".empty-state"));
+ return !els.some(e => /加载中/.test(e.textContent || ""));
+}, undefined, { timeout: 60000 });
+const loadMs = Date.now() - t0;
+await page.waitForTimeout(1500);
+console.log(`first load complete: ${loadMs}ms, requests=${reqCount}, wireBytes(with content-length)=${(wireBytes/1024).toFixed(0)}KB`);
+console.log(`protocol check: response headers via CDP skipped; side-nav visible + data loaded OK`);
+await browser.close();
+process.exit(0);