Files
ComfyAssets-ComfyUI_PromptM…/tests/js/prompt-bridge-host.test.js
T

94 lines
4.8 KiB
JavaScript

import { test } from 'node:test';
import assert from 'node:assert/strict';
import { installPromptBridge } from '../../web/js/prompt-bridge-host.js';
import { createBridgeClient, createBridgeHost } from '../../web/js/shared/toolkit/prompt-bridge.js';
function fixture() {
const runtime = new EventTarget();
runtime.location = { origin: 'https://comfy.example', href: 'https://comfy.example/team/' };
runtime.document = { title: 'My workflow' };
const warnings = []; runtime.console = { warn: (...args) => warnings.push(args) };
const hosts = [], adapter = {};
const options = { runtime, baseUrl: '/team/prompt_manager/', adapterFactory: () => adapter,
hostFactory: config => { const host = { config, disposed: 0, dispose() { this.disposed++; } }; hosts.push(host); return host; } };
return { runtime, options, hosts, adapter, warnings };
}
test('host uses the exact deployment prefix and explicit pack label', () => {
const f = fixture(), app = {};
const controller = installPromptBridge(app, f.options);
assert.equal(f.hosts.length, 1);
assert.equal(f.hosts[0].config.namespace, '/team/');
assert.equal(f.hosts[0].config.origin, 'https://comfy.example');
assert.equal(f.hosts[0].config.label, 'My workflow');
f.runtime.document.title = '';
assert.equal(f.hosts[0].config.label, 'ComfyUI');
f.runtime.document.title = 'My workflow';
assert.equal(f.hosts[0].config.adapter, f.adapter);
assert.equal(installPromptBridge(app, f.options), controller);
controller.dispose(); controller.dispose();
assert.equal(f.hosts[0].disposed, 1);
});
test('page hide disposes and cached restoration mounts exactly one fresh host', () => {
const f = fixture(), controller = installPromptBridge({}, f.options);
f.runtime.dispatchEvent(new Event('pagehide'));
assert.equal(f.hosts[0].disposed, 1);
f.runtime.dispatchEvent(new Event('pageshow'));
f.runtime.dispatchEvent(new Event('pageshow'));
assert.equal(f.hosts.length, 2);
controller.dispose();
f.runtime.dispatchEvent(new Event('pageshow'));
assert.equal(f.hosts.length, 2);
assert.equal(f.hosts[1].disposed, 1);
});
test('a disposed installation can be installed again', () => {
const f = fixture(), app = {};
installPromptBridge(app, f.options).dispose();
const next = installPromptBridge(app, f.options);
assert.equal(f.hosts.length, 2);
next.dispose();
});
test('unavailable messaging leaves the existing host usable and can recover after restoration', () => {
const f = fixture(); let unavailable = true;
const factory = f.options.hostFactory;
f.options.hostFactory = config => { if (unavailable) throw new Error('BroadcastChannel unavailable'); return factory(config); };
const controller = installPromptBridge({}, f.options);
assert.equal(f.warnings.length, 1);
unavailable = false;
f.runtime.dispatchEvent(new Event('pageshow'));
assert.equal(f.hosts.length, 1);
controller.dispose();
});
test('deployment namespace rejects external origins and unexpected paths', () => {
for (const baseUrl of ['https://comfy.example.attacker.test/prompt_manager/', '/wrong/', 'data:text/plain,hello']) {
const f = fixture();
assert.throws(() => installPromptBridge({}, { ...f.options, baseUrl }), /deployment|origin|path/i);
assert.equal(f.hosts.length, 0);
}
});
test('each discovery reports the title the tab has now, through the real Toolkit host', async () => {
const f = fixture();
f.runtime.location = { origin: 'https://comfy.example', href: 'https://comfy.example/' };
f.options.baseUrl = '/prompt_manager/';
const listeners = new Set();
const channelFactory = () => { const own = new Set(); return {
addEventListener(type, listener) { if (type === 'message') { own.add(listener); listeners.add(listener); } }, removeEventListener(type, listener) { listeners.delete(listener); },
postMessage(data) { for (const listener of [...listeners]) if (!own.has(listener)) queueMicrotask(() => listener({ data: structuredClone(data), origin: 'https://comfy.example' })); }, close() {},
}; };
// Not spread: a copy would freeze the title the host must keep reading.
f.options.hostFactory = config => { config.channelFactory = channelFactory; return createBridgeHost(config); };
f.adapter.listTargets = () => []; f.adapter.preview = () => {}; f.adapter.apply = () => {};
f.runtime.document.title = 'ComfyUI';
const controller = installPromptBridge({}, f.options);
const client = createBridgeClient({ namespace: '/', origin: 'https://comfy.example', channelFactory });
f.runtime.document.title = '*Unsaved Workflow - ComfyUI';
try {
assert.equal((await client.discover({ waitMs: 100 }))[0].label, '*Unsaved Workflow - ComfyUI');
} finally { client.dispose(); controller.dispose(); }
});