Files

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);
});