Nodes can push a status line to their own badge through the new push_node_status helper, which is a silent no-op without a live PromptServer so a status update can never fail the run reporting it. The LaMa inpainter emits "frame i/N" alongside its progress bar, threading the node id in through a hidden UNIQUE_ID input -- hidden entries never become widgets, so its visible inputs and saved widgets_values are unchanged. The badge rides its own Chrome setting, on by default: unlike the runtime badge it only exists while a node is running, and it is retired when the node moves on or the run ends, fails, or is stopped.
189 lines
7.1 KiB
JavaScript
189 lines
7.1 KiB
JavaScript
import test from "node:test";
|
|
import assert from "node:assert/strict";
|
|
|
|
import {
|
|
advanceExecution,
|
|
applyStatus,
|
|
badgeFor,
|
|
clearStatuses,
|
|
composeTitle,
|
|
createRunState,
|
|
createStatusState,
|
|
formatDuration,
|
|
stripQueuePrefix,
|
|
} from "../js/shared/chrome.mjs";
|
|
|
|
test("composeTitle prefixes the queue depth", () => {
|
|
assert.equal(composeTitle("ComfyUI", 3), "(3) ComfyUI");
|
|
assert.equal(composeTitle("ComfyUI", 1), "(1) ComfyUI");
|
|
assert.equal(composeTitle("ComfyUI", "12"), "(12) ComfyUI");
|
|
});
|
|
|
|
test("composeTitle restores the bare title at zero", () => {
|
|
assert.equal(composeTitle("ComfyUI", 0), "ComfyUI");
|
|
assert.equal(composeTitle("(4) ComfyUI", 0), "ComfyUI");
|
|
});
|
|
|
|
test("composeTitle never double-prefixes an already-prefixed title", () => {
|
|
assert.equal(composeTitle("(2) ComfyUI", 5), "(5) ComfyUI");
|
|
assert.equal(composeTitle("(2) (3) ComfyUI", 1), "(1) (3) ComfyUI");
|
|
});
|
|
|
|
test("composeTitle treats junk queue depths as idle", () => {
|
|
assert.equal(composeTitle("ComfyUI", -1), "ComfyUI");
|
|
assert.equal(composeTitle("ComfyUI", NaN), "ComfyUI");
|
|
assert.equal(composeTitle("ComfyUI", undefined), "ComfyUI");
|
|
assert.equal(composeTitle("(7) ComfyUI", "junk"), "ComfyUI");
|
|
});
|
|
|
|
test("stripQueuePrefix only removes the exact prefix form", () => {
|
|
assert.equal(stripQueuePrefix("(3) ComfyUI"), "ComfyUI");
|
|
assert.equal(stripQueuePrefix("(3)ComfyUI"), "(3)ComfyUI");
|
|
assert.equal(stripQueuePrefix("(three) ComfyUI"), "(three) ComfyUI");
|
|
assert.equal(stripQueuePrefix("My (3) tabs"), "My (3) tabs");
|
|
assert.equal(stripQueuePrefix("ComfyUI"), "ComfyUI");
|
|
assert.equal(stripQueuePrefix(undefined), "");
|
|
});
|
|
|
|
test("formatDuration picks the unit for the magnitude", () => {
|
|
assert.equal(formatDuration(0.049), "49ms");
|
|
assert.equal(formatDuration(0), "0ms");
|
|
assert.equal(formatDuration(0.9994), "999ms");
|
|
assert.equal(formatDuration(1.5), "1.50s");
|
|
assert.equal(formatDuration(59.99), "59.99s");
|
|
assert.equal(formatDuration(95), "1m35s");
|
|
assert.equal(formatDuration(60), "1m0s");
|
|
assert.equal(formatDuration(3599), "59m59s");
|
|
});
|
|
|
|
test("formatDuration carries rounded-up boundaries into the next unit", () => {
|
|
assert.equal(formatDuration(0.9996), "1.00s");
|
|
assert.equal(formatDuration(59.999), "1m0s");
|
|
});
|
|
|
|
test("formatDuration rejects junk", () => {
|
|
assert.equal(formatDuration(-1), "");
|
|
assert.equal(formatDuration(NaN), "");
|
|
assert.equal(formatDuration(Infinity), "");
|
|
assert.equal(formatDuration("soon"), "");
|
|
});
|
|
|
|
test("advanceExecution closes out the previous node", () => {
|
|
const state = createRunState();
|
|
assert.deepEqual(advanceExecution(state, "5", 1000), []);
|
|
assert.equal(state.runningId, "5");
|
|
const updates = advanceExecution(state, "7", 3500);
|
|
assert.deepEqual(updates, [{ id: "5", seconds: 2.5 }]);
|
|
assert.equal(state.totals.get("5"), 2.5);
|
|
assert.equal(state.runningId, "7");
|
|
});
|
|
|
|
test("advanceExecution accumulates revisits so batched loops sum", () => {
|
|
const state = createRunState();
|
|
advanceExecution(state, "5", 0);
|
|
advanceExecution(state, "7", 1000);
|
|
advanceExecution(state, "5", 1500);
|
|
const updates = advanceExecution(state, null, 3500);
|
|
assert.deepEqual(updates, [{ id: "5", seconds: 3 }]);
|
|
assert.equal(state.totals.get("5"), 3);
|
|
assert.equal(state.totals.get("7"), 0.5);
|
|
assert.equal(state.runningId, null);
|
|
});
|
|
|
|
test("advanceExecution is a no-op while idle", () => {
|
|
const state = createRunState();
|
|
assert.deepEqual(advanceExecution(state, null, 100), []);
|
|
assert.equal(state.runningId, null);
|
|
assert.equal(state.totals.size, 0);
|
|
});
|
|
|
|
test("advanceExecution normalizes ids and clamps a backwards clock", () => {
|
|
const state = createRunState();
|
|
advanceExecution(state, 5, 2000);
|
|
assert.equal(state.runningId, "5");
|
|
const updates = advanceExecution(state, null, 1000);
|
|
assert.deepEqual(updates, [{ id: "5", seconds: 0 }]);
|
|
});
|
|
|
|
test("applyStatus stores a normalized entry per node id", () => {
|
|
const state = createStatusState();
|
|
assert.equal(applyStatus(state, { node_id: 5, text: "frame 2/9", progress: 0.25 }), "5");
|
|
assert.deepEqual(state.entries.get("5"), { text: "frame 2/9", progress: 0.25 });
|
|
});
|
|
|
|
test("applyStatus clamps progress and treats junk as no progress", () => {
|
|
const state = createStatusState();
|
|
applyStatus(state, { node_id: "1", text: "a", progress: 2 });
|
|
assert.equal(state.entries.get("1").progress, 1);
|
|
applyStatus(state, { node_id: "1", text: "a", progress: -0.5 });
|
|
assert.equal(state.entries.get("1").progress, 0);
|
|
for (const progress of [null, undefined, NaN, "soon"]) {
|
|
applyStatus(state, { node_id: "1", text: "a", progress });
|
|
assert.equal(state.entries.get("1").progress, null);
|
|
}
|
|
});
|
|
|
|
test("applyStatus keeps badge text to one capped ASCII line", () => {
|
|
const state = createStatusState();
|
|
applyStatus(state, { node_id: "1", text: " frame\n3/4 — ok " });
|
|
assert.equal(state.entries.get("1").text, "frame 3/4 ok");
|
|
applyStatus(state, { node_id: "1", text: "x".repeat(40) });
|
|
assert.equal(state.entries.get("1").text, "x".repeat(24));
|
|
});
|
|
|
|
test("applyStatus retracts a badge on empty text", () => {
|
|
const state = createStatusState();
|
|
applyStatus(state, { node_id: "1", text: "working" });
|
|
assert.equal(applyStatus(state, { node_id: "1", text: "" }), "1");
|
|
assert.equal(state.entries.has("1"), false);
|
|
// Nothing to retract the second time around.
|
|
assert.equal(applyStatus(state, { node_id: "1", text: " " }), null);
|
|
});
|
|
|
|
test("applyStatus rejects payloads without a node id", () => {
|
|
const state = createStatusState();
|
|
for (const detail of [undefined, {}, { node_id: null, text: "a" }, { node_id: "", text: "a" }]) {
|
|
assert.equal(applyStatus(state, detail), null);
|
|
}
|
|
assert.equal(state.entries.size, 0);
|
|
});
|
|
|
|
test("clearStatuses retires everything and reports what it cleared", () => {
|
|
const state = createStatusState();
|
|
applyStatus(state, { node_id: "1", text: "a" });
|
|
applyStatus(state, { node_id: "2", text: "b" });
|
|
assert.deepEqual(clearStatuses(state).sort(), ["1", "2"]);
|
|
assert.equal(state.entries.size, 0);
|
|
assert.deepEqual(clearStatuses(state), []);
|
|
});
|
|
|
|
test("clearStatuses keeps the node still executing", () => {
|
|
const state = createStatusState();
|
|
applyStatus(state, { node_id: "1", text: "a" });
|
|
applyStatus(state, { node_id: "2", text: "b" });
|
|
assert.deepEqual(clearStatuses(state, 2), ["1"]);
|
|
assert.deepEqual([...state.entries.keys()], ["2"]);
|
|
});
|
|
|
|
test("badgeFor prefers a live status over the runtime badge", () => {
|
|
const badge = badgeFor({ text: "frame 2/9", progress: 0.25 }, 12.5);
|
|
assert.deepEqual(badge, { kind: "live", text: "frame 2/9", progress: 0.25 });
|
|
});
|
|
|
|
test("badgeFor falls back to the runtime badge once the status is gone", () => {
|
|
assert.deepEqual(badgeFor(null, 1.5), { kind: "runtime", text: "1.50s", progress: null });
|
|
assert.deepEqual(badgeFor(undefined, 0), { kind: "runtime", text: "0ms", progress: null });
|
|
assert.deepEqual(badgeFor({ text: "" }, 1.5), {
|
|
kind: "runtime",
|
|
text: "1.50s",
|
|
progress: null,
|
|
});
|
|
});
|
|
|
|
test("badgeFor draws nothing without a status or a runtime", () => {
|
|
assert.equal(badgeFor(null, undefined), null);
|
|
assert.equal(badgeFor({ text: " " }, null), null);
|
|
assert.equal(badgeFor(null, "12"), null);
|
|
assert.equal(badgeFor(null, -1), null);
|
|
});
|