117 lines
5.0 KiB
JavaScript
117 lines
5.0 KiB
JavaScript
/** Smoke-test the WS write paths used by the new section cards.
|
|
*
|
|
* 1. Enable vacation via vacation/update → expect enabled=true
|
|
* 2. Set start/end + buffer → expect persisted
|
|
* 3. Disable vacation → expect enabled=false
|
|
* 4. Set monthly + yearly budget via global/update → expect persisted
|
|
* 5. Create + rename + delete a group → expect roundtrip
|
|
*/
|
|
import http from "http";
|
|
import WebSocket from "ws";
|
|
|
|
const HA = "http://localhost:8125";
|
|
const WSURL = "ws://localhost:8125/api/websocket";
|
|
|
|
function post(p, body, ct = "application/json") {
|
|
return new Promise((resolve, reject) => {
|
|
const data = typeof body === "string" ? body : JSON.stringify(body);
|
|
const opts = { hostname: "localhost", port: 8125, path: p, method: "POST",
|
|
headers: { "Content-Type": ct, "Content-Length": Buffer.byteLength(data) } };
|
|
const req = http.request(opts, (r) => { let d = ""; r.on("data", (c) => (d += c)); r.on("end", () => resolve(JSON.parse(d))); });
|
|
req.on("error", reject); req.write(data); req.end();
|
|
});
|
|
}
|
|
|
|
async function getToken() {
|
|
const flow = await post("/auth/login_flow", { client_id: HA + "/", handler: ["homeassistant", null], redirect_uri: HA + "/" });
|
|
const auth = await post(`/auth/login_flow/${flow.flow_id}`, { client_id: HA + "/", username: "dev", password: "dev" });
|
|
const tok = await post("/auth/token", `grant_type=authorization_code&code=${auth.result}&client_id=${HA}/`, "application/x-www-form-urlencoded");
|
|
return tok.access_token;
|
|
}
|
|
|
|
async function main() {
|
|
const token = await getToken();
|
|
const ws = new WebSocket(WSURL);
|
|
let id = 1;
|
|
const pending = new Map();
|
|
|
|
ws.on("message", (raw) => {
|
|
const m = JSON.parse(raw);
|
|
if (m.type === "auth_required") {
|
|
ws.send(JSON.stringify({ type: "auth", access_token: token }));
|
|
} else if (m.type === "auth_ok") {
|
|
pending.get("auth")?.resolve();
|
|
} else if (m.type === "result") {
|
|
const p = pending.get(m.id);
|
|
if (p) {
|
|
if (m.success === false) p.reject(new Error(JSON.stringify(m.error)));
|
|
else p.resolve(m.result);
|
|
pending.delete(m.id);
|
|
}
|
|
}
|
|
});
|
|
|
|
await new Promise((resolve) => { ws.once("open", resolve); });
|
|
await new Promise((resolve) => pending.set("auth", { resolve }));
|
|
|
|
function call(payload) {
|
|
return new Promise((resolve, reject) => {
|
|
const i = id++;
|
|
pending.set(i, { resolve, reject });
|
|
ws.send(JSON.stringify({ id: i, ...payload }));
|
|
});
|
|
}
|
|
|
|
let ok = 0, total = 0;
|
|
function check(label, cond, value) {
|
|
total++;
|
|
if (cond) ok++;
|
|
console.log(` ${cond ? "✓" : "✗"} ${label}${value !== undefined ? " — " + value : ""}`);
|
|
}
|
|
|
|
console.log("\n=== Vacation enable + dates ===");
|
|
await call({ type: "maintenance_supporter/vacation/update", enabled: true, start: "2026-06-01", end: "2026-06-15", buffer_days: 3 });
|
|
let s = await call({ type: "maintenance_supporter/vacation/state" });
|
|
check("enabled=true", s.enabled === true);
|
|
check("start=2026-06-01", s.start === "2026-06-01", s.start);
|
|
check("end=2026-06-15", s.end === "2026-06-15", s.end);
|
|
check("buffer_days=3", s.buffer_days === 3, s.buffer_days);
|
|
|
|
console.log("\n=== Vacation disable ===");
|
|
await call({ type: "maintenance_supporter/vacation/update", enabled: false });
|
|
s = await call({ type: "maintenance_supporter/vacation/state" });
|
|
check("enabled=false after disable", s.enabled === false);
|
|
check("dates preserved", s.start === "2026-06-01" && s.end === "2026-06-15");
|
|
|
|
console.log("\n=== Budget update via global/update ===");
|
|
await call({ type: "maintenance_supporter/global/update", settings: { budget_monthly: 200, budget_yearly: 2000 } });
|
|
let bs = await call({ type: "maintenance_supporter/budget_status" });
|
|
check("monthly=200", bs.monthly_budget === 200, bs.monthly_budget);
|
|
check("yearly=2000", bs.yearly_budget === 2000, bs.yearly_budget);
|
|
|
|
// Restore previous values
|
|
await call({ type: "maintenance_supporter/global/update", settings: { budget_monthly: 150, budget_yearly: 1500 } });
|
|
|
|
console.log("\n=== Groups: create + rename + delete ===");
|
|
const created = await call({ type: "maintenance_supporter/group/create", name: "TmpTestGroup" });
|
|
check("group created with id", typeof created.group_id === "string");
|
|
const gid = created.group_id;
|
|
|
|
let g = await call({ type: "maintenance_supporter/groups" });
|
|
check("new group present", !!g.groups[gid] && g.groups[gid].name === "TmpTestGroup", g.groups[gid]?.name);
|
|
|
|
await call({ type: "maintenance_supporter/group/update", group_id: gid, name: "RenamedGroup" });
|
|
g = await call({ type: "maintenance_supporter/groups" });
|
|
check("renamed", g.groups[gid]?.name === "RenamedGroup", g.groups[gid]?.name);
|
|
|
|
await call({ type: "maintenance_supporter/group/delete", group_id: gid });
|
|
g = await call({ type: "maintenance_supporter/groups" });
|
|
check("deleted", !g.groups[gid]);
|
|
|
|
console.log(`\n=== SUMMARY ===\n ${ok}/${total} checks passed`);
|
|
ws.close();
|
|
process.exit(ok === total ? 0 : 1);
|
|
}
|
|
|
|
main().catch((e) => { console.error(e); process.exit(1); });
|