Files

81 lines
5.3 KiB
JavaScript

import test from "node:test";
import assert from "node:assert/strict";
import { setupDom, teardownDom } from "../../composer/tests/_dom.js";
import { createDom } from "../../shell/dom.js";
let enhance;
test.before(async () => { setupDom(); ({ enhance } = await import("./enhance.js")); });
test.after(() => teardownDom());
test("the Enhance tab follows the open project's pipeline: no enhancer there, no toggle shown", async () => {
let live = [{ id: "e", node: "FunUIEnhancePrompt", inputs: { enabled: true } }], heard;
const ps = { slots: () => live, ensureLoaded: async () => {}, save: async () => {}, subscribe: (fn) => { heard = fn; return () => {}; } };
const api = { enhancerEncoders: async () => ({ files: [], families: [] }), enhancerDefaults: async () => ({}), enhancerRuns: async () => ({ runs: [] }) };
const page = enhance({ dom: createDom(), pipeline: ps, api }, () => {});
document.body.append(page.node);
assert.match(page.node.textContent, /Enhance prompt/);
live = [{ id: "s", node: "FunUISampler", inputs: {} }]; // another project opened
heard(live);
assert.match(page.node.textContent, /No prompt enhancer here/);
});
test("a run that ends while Enhance is open shows its final prompt without reopening the tab", async () => {
const ps = { slots: () => [{ id: "e", node: "FunUIEnhancePrompt", inputs: {} }], ensureLoaded: async () => {}, save: async () => {}, subscribe: () => () => {} };
let runs = [], tell;
const api = { enhancerEncoders: async () => ({ files: [], families: [] }), enhancerDefaults: async () => ({}), enhancerRuns: async () => ({ runs }) };
const generate = { subscribe: (fn) => { tell = fn; fn({ phase: "idle" }); return () => {}; } };
const page = enhance({ dom: createDom(), pipeline: ps, api, generate }, () => {});
await new Promise((r) => setTimeout(r, 0));
assert.match(page.node.textContent, /Nothing yet/);
runs = [{ prompt_id: "p", status: "off: the prompt ran as typed", before: "a red fox", after: "a red fox at dusk" }];
tell({ phase: "running" }); tell({ phase: "done" });
await new Promise((r) => setTimeout(r, 0));
assert.match(page.node.textContent, /a red fox at dusk/);
});
test("Chat on a pipeline with no enhancer says so instead of taking comments that would reach nothing", async () => {
const { chat } = await import("./chat.js");
let slots = [{ id: "s", node: "Sampler" }], heard;
const app = { dom: createDom(), project: { project: { id: "P", scenes: [] }, pref: (_k, d) => d, setPref: () => {} }, selection: {}, lastRun: { n: 0 },
api: { enhancerRuns: async () => ({ runs: [] }) }, on: () => () => {}, pipeline: { slots: () => slots, subscribe: (fn) => { heard = fn; return () => {}; } } };
const page = chat(app, () => {});
assert.match(page.node.textContent, /No prompt enhancer here/);
assert.equal(page.node.querySelector("textarea"), null);
slots = [{ id: "e", node: "FunUIEnhancePrompt" }];
heard(slots, "edit");
assert.ok(page.node.querySelector("textarea"));
});
test("the Encoder pick lists the encoder files, and its family shows only once a file is picked", async () => {
let inputs = { enabled: true }, saved;
const ps = { slots: () => [{ id: "e", node: "FunUIEnhancePrompt", inputs }], ensureLoaded: async () => {}, save: async (b) => { saved = b; inputs = { ...inputs, ...b.inputs.e }; }, subscribe: () => () => {} };
const api = { enhancerEncoders: async () => ({ files: ["gemma4.safetensors"], families: ["stable_diffusion", "ltxv"] }), enhancerDefaults: async () => ({}), enhancerRuns: async () => ({ runs: [] }) };
const page = enhance({ dom: createDom(), pipeline: ps, api }, () => {});
document.body.append(page.node);
await new Promise((r) => setTimeout(r, 0));
assert.match(page.node.textContent, /Encoder/);
assert.match(page.node.textContent, /gemma4\.safetensors/);
assert.doesNotMatch(page.node.textContent, /Encoder family/);
inputs = { enabled: true, encoder_file: "gemma4.safetensors" };
const ps2 = { ...ps, slots: () => [{ id: "e", node: "FunUIEnhancePrompt", inputs }] };
const again = enhance({ dom: createDom(), pipeline: ps2, api }, () => {});
document.body.append(again.node);
await new Promise((r) => setTimeout(r, 0));
assert.match(again.node.textContent, /Encoder family/);
});
test("Style picks the built-in instructions shown as the placeholder, and choosing Dynamic saves it", async () => {
const saved = [];
const slot = { id: "e", node: "FunUIEnhancePrompt", inputs: { enabled: true } };
const ps = { slots: () => [slot], ensureLoaded: async () => {}, save: async (...a) => { saved.push(a); }, subscribe: () => () => {} };
const api = { enhancerEncoders: async () => ({ files: [], families: [] }), enhancerRuns: async () => ({ runs: [] }),
enhancerDefaults: async () => ({ instructions: "DEFAULT TEXT", reference_intro: "", styles: { default: "DEFAULT TEXT", dynamic: "DYNAMIC TEXT" } }) };
const page = enhance({ dom: createDom(), pipeline: ps, api }, () => {});
document.body.append(page.node);
await new Promise((r) => setTimeout(r, 0));
assert.match(page.node.textContent, /Style/);
assert.match(page.node.textContent, /Dynamic \(more motion\)/);
const area = [...page.node.querySelectorAll("textarea")].find((t) => t.placeholder === "DEFAULT TEXT");
assert.ok(area, "the default style shows the default instructions");
});