105 lines
4.8 KiB
JavaScript
105 lines
4.8 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);
|
|
});
|