Files
ausboss-ComfyUI-AusBoss/tests/cache_guard.test.mjs
ausboss 14db93f076 Tell a tab left open through an update to reload
Updating the pack in Manager restarts ComfyUI and reloads the workflow, but
not the page. The tab kept running the old AusBoss scripts and nothing said
so: the update guard only looked once, when the page loaded.

The guard now looks again every time the server comes back, asks once per
installed version, and its message stays until it is closed instead of
going away after 30 seconds.

Follow-up to issue #108. The missing LoRA Loader panel reported there was
old browser copies of the shared modules, fixed in 2.5.2.
2026-10-04 02:26:31 -05:00

105 lines
4.7 KiB
JavaScript

// What the update guard (js/cache_guard/index.js) tells the user, and when.
//
// The entry imports ComfyUI's own api and app, which only exist in the
// browser. It is loaded here from a copy with stand-ins for those two and for
// the shared module it reads the running version from.
import assert from "node:assert/strict";
import test from "node:test";
import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { dirname, join } from "node:path";
import { fileURLToPath, pathToFileURL } from "node:url";
const ENTRY = join(dirname(fileURLToPath(import.meta.url)), "..", "js", "cache_guard", "index.js");
const API_IMPORT = 'import { api } from "/scripts/api.js";';
const APP_IMPORT = 'import { app } from "/scripts/app.js";';
const PAGE = `
export const page = { installed: null, down: false, toasts: [], listeners: {}, extension: null };
export const api = {
async fetchApi(path) {
if (page.down) throw new Error("server is down");
const body = path === "/ausboss/pack_version" ? { version: page.installed } : { modules: ["shared/index.mjs"] };
return { json: async () => body };
},
addEventListener(name, listener) { (page.listeners[name] ||= []).push(listener); },
};
export const app = {
extensionManager: { toast: { add: (message) => page.toasts.push(message) } },
registerExtension(extension) { page.extension = extension; },
};
`;
// A page that loaded the pack's scripts at version `running` while the
// server has `installed`. Every call gets its own folder, so its own modules.
async function openPage(t, { running, installed }) {
const source = readFileSync(ENTRY, "utf-8");
assert.ok(source.includes(API_IMPORT) && source.includes(APP_IMPORT), "the entry's imports changed; update this test");
const folder = mkdtempSync(join(tmpdir(), "ausboss-guard-"));
t.after(() => rmSync(folder, { recursive: true, force: true }));
mkdirSync(join(folder, "shared"));
mkdirSync(join(folder, "cache_guard"));
writeFileSync(join(folder, "shared", "index.mjs"), `export const AUSBOSS_JS_VERSION = ${JSON.stringify(running)};\n`);
writeFileSync(join(folder, "page.mjs"), PAGE);
writeFileSync(
join(folder, "cache_guard", "index.mjs"),
source.replace(API_IMPORT, 'import { api, app } from "../page.mjs";').replace(APP_IMPORT, ""),
);
const refreshed = [];
t.mock.method(globalThis, "fetch", async (url, options) => {
refreshed.push({ url: String(url), cache: options?.cache });
return new Response("");
});
const { page } = await import(pathToFileURL(join(folder, "page.mjs")).href);
page.installed = installed;
page.refreshed = refreshed;
page.serverComesBack = async (version) => {
page.installed = version;
await Promise.all((page.listeners.reconnected || []).map((listener) => listener()));
};
await import(pathToFileURL(join(folder, "cache_guard", "index.mjs")).href);
await page.extension.setup();
return page;
}
test("a page on the installed version is left alone", async (t) => {
const page = await openPage(t, { running: "2.6.1", installed: "2.6.1" });
await page.serverComesBack("2.6.1");
assert.deepEqual(page.toasts, []);
assert.deepEqual(page.refreshed, []);
});
test("a page that loaded old files is asked to reload, and the message stays", async (t) => {
const page = await openPage(t, { running: "2.5.0", installed: "2.6.1" });
assert.equal(page.toasts.length, 1);
assert.equal(page.toasts[0].summary, "AusBoss was updated");
assert.match(page.toasts[0].detail, /v2\.6\.1 is installed.*Press F5/);
assert.equal(page.toasts[0].life, undefined, "no life: the message stays until it is closed");
assert.equal(page.refreshed.length, 1, "the stored copies are replaced before the reload");
assert.ok(page.refreshed[0].url.endsWith("/shared/index.mjs"));
assert.equal(page.refreshed[0].cache, "reload");
});
test("a tab left open through an update is asked when the server comes back", async (t) => {
const page = await openPage(t, { running: "2.6.1", installed: "2.6.1" });
assert.deepEqual(page.toasts, []);
await page.serverComesBack("2.7.0");
assert.equal(page.toasts.length, 1);
assert.match(page.toasts[0].detail, /v2\.7\.0 is installed/);
await page.serverComesBack("2.7.0");
assert.equal(page.toasts.length, 1, "one message per update, however often the server drops");
await page.serverComesBack("2.7.1");
assert.equal(page.toasts.length, 2, "a second update asks again");
});
test("a server that does not answer keeps the page quiet", async (t) => {
const page = await openPage(t, { running: "2.6.1", installed: "2.6.1" });
page.down = true;
await page.serverComesBack("2.7.0");
assert.deepEqual(page.toasts, []);
page.down = false;
await page.serverComesBack("2.7.0");
assert.equal(page.toasts.length, 1);
});