Files

129 lines
6.4 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 浏览器实测:刷新速度按链路各存一份(DOM + localStorage 往返)。
* 单测覆盖不到的部分:输入框回填、切链路自动换、刷新页面后仍各自独立。
*/
const CDP_BASE = "http://127.0.0.1:9333";
async function ws() {
const list = await (await fetch(CDP_BASE + "/json/list")).json();
const page = list.find((t) => t.type === "page");
return page.webSocketDebuggerUrl;
}
const { WebSocket } = await import("node:http").then(() => import("ws")).catch(() => ({}));
// 没有 ws 依赖时用原生 WebSocket(Node 22+)
const WSImpl = globalThis.WebSocket || WebSocket;
const url = await ws();
const sock = new WSImpl(url);
let id = 0;
const pending = new Map();
await new Promise((r, j) => { sock.onopen = r; sock.onerror = j; });
sock.onmessage = (ev) => {
const m = JSON.parse(ev.data);
if (m.id && pending.has(m.id)) { pending.get(m.id)(m); pending.delete(m.id); }
};
function send(method, params = {}) {
const myId = ++id;
return new Promise((res) => { pending.set(myId, res); sock.send(JSON.stringify({ id: myId, method, params })); });
}
async function evaluate(expr) {
const r = await send("Runtime.evaluate", { expression: expr, awaitPromise: true, returnByValue: true });
if (r.result && r.result.exceptionDetails) throw new Error(JSON.stringify(r.result.exceptionDetails));
return r.result && r.result.result && r.result.result.value;
}
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
let pass = 0, fail = 0;
const out = [];
function check(name, cond, detail) {
if (cond) { pass++; out.push(" \u2713 " + name); }
else { fail++; out.push(" \u2717 " + name + (detail ? " \u2014 " + detail : "")); }
}
await send("Runtime.enable");
await send("Page.enable");
/* 页面服务端口可传参:node scripts/xxx.mjs [port](默认 2625) */
const PORT = Number(process.argv[2] || 2625);
const PAGE = `http://127.0.0.1:${PORT}/pages/motor.html`;
async function goto(u) {
await send("Page.navigate", { url: u });
await sleep(2500);
}
/* 干净起点:清掉本页 localStorage 再载入 */
await goto(PAGE);
await evaluate(`localStorage.removeItem("dcu_motor_ui_v2"); localStorage.removeItem("dcu_motor_transport"); "ok"`);
await goto(PAGE);
out.push("\n[A] 首次进入(无历史数据)");
let s = await evaluate(`JSON.stringify({tp: motorDbg.state.tpId, input: document.querySelector("#refreshRate").value, eff: motorDbg.state.refreshIntervalMs, map: motorDbg.state.refreshByTp})`);
let o = JSON.parse(s);
check("默认链路 wifi", o.tp === "wifi", s);
check("输入框显示 250", o.input === "250", s);
check("生效值 250", o.eff === 250, s);
check("两份都在(wifi250/ecat50)", o.map.wifi === 250 && o.map.ecat === 50, s);
out.push("\n[B] 切到 EtherCAT → 自动换成 50ms");
await evaluate(`(() => { const s=document.querySelector("#transportSelect"); s.value="ecat"; s.dispatchEvent(new Event("change")); return "ok"; })()`);
await sleep(1200);
s = await evaluate(`JSON.stringify({tp: motorDbg.state.tpId, input: document.querySelector("#refreshRate").value, eff: motorDbg.state.refreshIntervalMs})`);
o = JSON.parse(s);
check("链路已切到 ecat", o.tp === "ecat", s);
check("输入框自动变 50(不是留在 250)", o.input === "50", s);
check("生效值 50", o.eff === 50, s);
out.push("\n[C] 在 ECAT 下改成 120ms,只改这一份");
await evaluate(`(() => { const i=document.querySelector("#refreshRate"); i.value="120"; i.dispatchEvent(new Event("change")); return "ok"; })()`);
await sleep(600);
s = await evaluate(`JSON.stringify({eff: motorDbg.state.refreshIntervalMs, map: motorDbg.state.refreshByTp, ls: JSON.parse(localStorage.getItem("dcu_motor_ui_v2")||"{}").refreshByTp})`);
o = JSON.parse(s);
check("ecat 生效 120", o.eff === 120, s);
check("wifi 那一份仍是 250(没被污染)", o.map.wifi === 250, s);
check("已写入 localStorage", o.ls && o.ls.ecat === 120 && o.ls.wifi === 250, s);
out.push("\n[D] 切回 WiFi → 自动换回 250ms");
await evaluate(`(() => { const s=document.querySelector("#transportSelect"); s.value="wifi"; s.dispatchEvent(new Event("change")); return "ok"; })()`);
await sleep(1200);
s = await evaluate(`JSON.stringify({tp: motorDbg.state.tpId, input: document.querySelector("#refreshRate").value, eff: motorDbg.state.refreshIntervalMs, map: motorDbg.state.refreshByTp})`);
o = JSON.parse(s);
check("链路回到 wifi", o.tp === "wifi", s);
check("输入框换回 250(没带着 ECAT 的 120)", o.input === "250", s);
check("生效值 250", o.eff === 250, s);
check("ecat 那一份仍记着 120", o.map.ecat === 120, s);
out.push("\n[E] 在 WiFi 下改成 800ms,再刷新页面");
await evaluate(`(() => { const i=document.querySelector("#refreshRate"); i.value="800"; i.dispatchEvent(new Event("change")); return "ok"; })()`);
await sleep(600);
await goto(PAGE);
s = await evaluate(`JSON.stringify({tp: motorDbg.state.tpId, input: document.querySelector("#refreshRate").value, eff: motorDbg.state.refreshIntervalMs, map: motorDbg.state.refreshByTp})`);
o = JSON.parse(s);
check("刷新后仍是 wifi 链路", o.tp === "wifi", s);
check("刷新后输入框恢复 800", o.input === "800", s);
check("刷新后生效值 800", o.eff === 800, s);
check("刷新后 ecat 那一份仍是 120", o.map.ecat === 120, s);
out.push("\n[F] 刷新后切到 ECAT,仍取回自己的 120");
await evaluate(`(() => { const s=document.querySelector("#transportSelect"); s.value="ecat"; s.dispatchEvent(new Event("change")); return "ok"; })()`);
await sleep(1200);
s = await evaluate(`JSON.stringify({input: document.querySelector("#refreshRate").value, eff: motorDbg.state.refreshIntervalMs})`);
o = JSON.parse(s);
check("输入框 120(跨刷新持久化 + 切换自动换都成立)", o.input === "120", s);
check("生效值 120", o.eff === 120, s);
out.push("\n[G] 旧数据迁移(模拟老版本只存单个 refreshRate)");
await evaluate(`(() => { localStorage.setItem("dcu_motor_ui_v2", JSON.stringify({refreshRate:"400"})); localStorage.setItem("dcu_motor_transport","wifi"); return "ok"; })()`);
await goto(PAGE);
s = await evaluate(`JSON.stringify({input: document.querySelector("#refreshRate").value, map: motorDbg.state.refreshByTp})`);
o = JSON.parse(s);
check("旧单值 400 迁到 wifi 并生效", o.input === "400", s);
check("ecat 不继承旧值,仍是默认 50", o.map.ecat === 50, s);
console.log(out.join("\n"));
console.log("\n" + "=".repeat(56));
console.log(`通过 ${pass} 项,失败 ${fail} 项`);
sock.close();
process.exit(fail === 0 ? 0 : 1);