Files
BlackVortexAI-bv_nodepack/tests/node_preview_projection.test.mjs

217 lines
12 KiB
JavaScript

import assert from "node:assert/strict";
import test from "node:test";
import {
applyNodePreviewProjection,
nodePreviewPolicy,
previewRowName,
previewTargetsForMutationRoot,
syncPreviewDetailSections,
} from "../ui/src/regional/nodePreviewProjection.ts";
import { setLegacyDebugVisible } from "../ui/src/regional/legacyPorts.ts";
test("Regional Prompt declares its ghost-only action widgets outside the backend schema", () => {
assert.deepEqual(nodePreviewPolicy("BV Regional Prompt"), {
actions: ["Open Regional Editor", "Quick Edit Prompts"],
});
});
test("technical and dynamic nodes declare shared ghost projections",()=>{
assert.deepEqual(nodePreviewPolicy("BV Inspect Any"),{rows:[{label:"Value preview available after execution",kind:"value"}]});
assert.deepEqual(nodePreviewPolicy("BV Seed")?.actions,["🎲 Randomize Each Time","🎲 New Fixed Random","♻️ (Use Last Queued Seed)"]);
assert.deepEqual(nodePreviewPolicy("BV Smart Pipe"),{actions:["Configure Smart Pipe"]});
assert.deepEqual(nodePreviewPolicy("BV Pipe"),{actions:[]});
assert.deepEqual(nodePreviewPolicy("BV Regional LoRA"),{actions:["Open LoRA Editor"]});
assert.deepEqual(nodePreviewPolicy("BV Regional Native Conditioning"),{actions:[]});
assert.equal(nodePreviewPolicy("BV Regional Debug"),undefined);
assert.deepEqual(nodePreviewPolicy("BV LoRA Registry"),{actions:["Open LoRA Registry"]});
});
test("preview projection appends native-looking button rows only to the Vue preview body", () => {
const appended = [];
let widgetsMounted = false;
const widgetRows = [
"regional_json",
"lora_bindings_json",
"lora_v3_config_json",
"detailer_v3_config_json",
"lut_v3_config_json",
"unrelated_widget",
].map((textContent) => ({ textContent, hidden: false, style: { display: "" } }));
const body = {
querySelector: () => null,
querySelectorAll: (selector) => selector === '[data-testid="node-widget"]' && widgetsMounted ? widgetRows : [],
append: (node) => appended.push(node),
};
const preview = {
dataset: { nodeId: "preview-BV Regional Prompt" },
querySelector: (selector) => selector === '[data-testid="node-body-preview-BV Regional Prompt"]' ? body : null,
};
const documentLike = {
createElement(tagName) {
return {
tagName,
className: "",
dataset: {},
attributes: {},
children: [],
append(...children) { this.children.push(...children); },
setAttribute(name, value) { this.attributes[name] = value; },
textContent: "",
};
},
};
assert.equal(applyNodePreviewProjection(preview, documentLike), true);
assert.equal(appended.length, 1);
assert.equal(appended[0].dataset.bvPreviewActions, "BV Regional Prompt");
assert.deepEqual(appended[0].children.map((row) => row.children[1].children[0].textContent), [
"Open Regional Editor",
"Quick Edit Prompts",
]);
assert.equal(preview.dataset.bvPreviewProjected, "BV Regional Prompt");
widgetsMounted = true;
assert.equal(applyNodePreviewProjection(preview, documentLike), true);
assert.equal(appended.length, 1);
assert.deepEqual(widgetRows.map((row) => row.hidden), [true, true, true, true, true, false]);
assert.deepEqual(widgetRows.map((row) => row.style.display), ["none", "none", "none", "none", "none", ""]);
});
function previewFixture(nodeType,bodyRows,detailRows=[]){
const body={querySelectorAll(selector){
if(selector==='[data-testid="node-widget"]')return bodyRows;
if(selector==='.lg-slot--input, .lg-slot--output')return bodyRows.filter(row=>row.classList?.contains?.("lg-slot--input")||row.classList?.contains?.("lg-slot--output"));
return[];
},append(){}};
return {dataset:{nodeId:`preview-${nodeType}`,bvPreviewProjected:nodeType},querySelector:selector=>selector===`[data-testid="node-body-preview-${nodeType}"]`?body:null,querySelectorAll:selector=>selector==='[data-bv-preview-port]'?detailRows:[]};
}
test("Smart Pipe reserve ports stay hidden in the debug Ghost",()=>{
const row={textContent:"v_001",hidden:false,style:{display:""},dataset:{bvPreviewPort:"input"}};
setLegacyDebugVisible(true);
try{assert.equal(applyNodePreviewProjection(previewFixture("BV Smart Pipe",[row],[row]),{createElement(){throw new Error("no projected rows expected")}}),true);assert.equal(row.hidden,true);assert.equal(row.style.display,"none")}
finally{setLegacyDebugVisible(false)}
});
test("normal preview hides legacy inputs and outputs in body and lower details",()=>{
const rows=["pipe","v_001","pipe","out_001"].map((textContent,index)=>({textContent,hidden:false,style:{display:""},dataset:{bvPreviewPort:index<2?"input":"output"}}));
const preview=previewFixture("BV Smart Pipe",[],rows);
assert.equal(applyNodePreviewProjection(preview,{createElement(){throw new Error("no projected rows expected")}}),true);
assert.deepEqual(rows.map(row=>row.hidden),[false,true,false,true]);
});
test("a legacy-only Pipe Ghost keeps its public pipe input and output instead of reserve fallbacks",()=>{
const rows=[
{textContent:"pipe",hidden:false,style:{display:""},dataset:{bvPreviewPort:"input"}},
{textContent:"v_001",hidden:false,style:{display:""},dataset:{bvPreviewPort:"input"}},
{textContent:"pipe",hidden:false,style:{display:""},dataset:{bvPreviewPort:"output"}},
{textContent:"out_001",hidden:false,style:{display:""},dataset:{bvPreviewPort:"output"}},
];
assert.equal(applyNodePreviewProjection(previewFixture("BV Pipe",rows,rows),{createElement(){throw new Error("no projected rows expected")}}),true);
assert.deepEqual(rows.map(row=>row.hidden),[false,true,false,true]);
});
test("Regional Prompt ghost projects body and detail rows through semantic presentation roles",()=>{
const rows=[
{textContent:"regional",hidden:false,style:{display:""},dataset:{bvPreviewPort:"output"}},
{textContent:"lora_bindings",hidden:false,style:{display:""},dataset:{bvPreviewPort:"output"}},
{textContent:"regional_json STRING",hidden:false,style:{display:""},dataset:{bvPreviewPort:"input"}},
{textContent:"resource_provider_1 BV_RUNTIME_RESOURCE_PROVIDER",hidden:false,style:{display:""},dataset:{bvPreviewPort:"input"}},
];
const preview=previewFixture("BV Regional Prompt",[],rows);
assert.equal(applyNodePreviewProjection(preview,{createElement(){throw new Error("no projected rows expected")}}),true);
assert.deepEqual(rows.map(row=>row.hidden),[false,true,true,true]);
setLegacyDebugVisible(true);
try{
assert.equal(applyNodePreviewProjection(preview,{createElement(){throw new Error("no projected rows expected")}}),true);
assert.deepEqual(rows.map(row=>row.hidden),[false,false,true,true]);
}finally{setLegacyDebugVisible(false)}
});
test("Regional LoRA ghost hides internal and provider rows in body and lower details",()=>{
const bodyRows=[
{textContent:"regional BV_REGIONAL",hidden:false,style:{display:""},classList:{contains:name=>name==="lg-slot--input"}},
{textContent:"regional BV_REGIONAL",hidden:false,style:{display:""},classList:{contains:name=>name==="lg-slot--output"}},
{textContent:"operation COMBO",hidden:false,style:{display:""}},
{textContent:"config_json STRING",hidden:false,style:{display:""}},
{textContent:"resource_provider_1 BV_RUNTIME_RESOURCE_PROVIDER",hidden:false,style:{display:""},classList:{contains:name=>name==="lg-slot--input"}},
];
const detailRows=[
{textContent:"regional BV_REGIONAL",hidden:false,style:{display:""},dataset:{bvPreviewPort:"input"}},
{textContent:"regional BV_REGIONAL",hidden:false,style:{display:""},dataset:{bvPreviewPort:"output"}},
{textContent:"operation COMBO",hidden:false,style:{display:""},dataset:{bvPreviewPort:"input"}},
{textContent:"config_json STRING",hidden:false,style:{display:""},dataset:{bvPreviewPort:"input"}},
{textContent:"resource_provider_1 BV_RUNTIME_RESOURCE_PROVIDER",hidden:false,style:{display:""},dataset:{bvPreviewPort:"input"}},
];
const preview=previewFixture("BV Regional LoRA",bodyRows,detailRows);
for(const legacyDebug of [false,true]){
setLegacyDebugVisible(legacyDebug);
assert.equal(applyNodePreviewProjection(preview,{createElement(){return{className:"",dataset:{},append(){},setAttribute(){},textContent:""}}}),true);
assert.deepEqual(bodyRows.map(row=>row.hidden),[false,false,true,true,true]);
assert.deepEqual(detailRows.map(row=>row.hidden),[false,false,true,true,true]);
}
setLegacyDebugVisible(false);
});
test("Smart Pipe Merge ghost hides every reserve and its real JSON row in body and details",()=>{
const slot=(textContent,direction)=>({textContent,hidden:false,style:{display:""},classList:{contains:name=>name===`lg-slot--${direction}`}});
const bodyRows=[
slot("pipe_001 BV_SMART_PIPE","input"),
slot("pipe_016 BV_SMART_PIPE","input"),
slot("pipe BV_SMART_PIPE","output"),
{textContent:"bv_smart_pipe_merge_json STRING",hidden:false,style:{display:""}},
];
const detailRows=[
{textContent:"pipe_001 BV_SMART_PIPE",hidden:false,style:{display:""},dataset:{bvPreviewPort:"input"}},
{textContent:"pipe_016 BV_SMART_PIPE",hidden:false,style:{display:""},dataset:{bvPreviewPort:"input"}},
{textContent:"bv_smart_pipe_merge_json STRING",hidden:false,style:{display:""},dataset:{bvPreviewPort:"input"}},
{textContent:"pipe BV_SMART_PIPE",hidden:false,style:{display:""},dataset:{bvPreviewPort:"output"}},
];
const preview=previewFixture("BV Smart Pipe Merge",bodyRows,detailRows);
for(const legacyDebug of[false,true]){
setLegacyDebugVisible(legacyDebug);
assert.equal(applyNodePreviewProjection(preview,{createElement(){return{className:"",dataset:{},append(){},setAttribute(){},textContent:""}}}),true);
assert.deepEqual(bodyRows.map(row=>row.hidden),[true,true,false,true]);
assert.deepEqual(detailRows.map(row=>row.hidden),[true,true,true,false]);
}
setLegacyDebugVisible(false);
});
test("a late lower-detail mutation resolves the sibling preview through its card",()=>{
const preview={dataset:{nodeId:"preview-BV Regional Prompt"}};
const card={querySelector:selector=>selector==='[data-node-id^="preview-"]'?preview:null};
const detailRow={closest:selector=>selector==='[data-testid="node-preview-card"]'?card:null};
assert.deepEqual(previewTargetsForMutationRoot(detailRow),[preview]);
});
test("lower detail names come from the label span instead of concatenated row text",()=>{
const label={textContent:"regional_json"};
const row={textContent:"regional_jsonSTRING",querySelector:selector=>selector==="span"?label:null};
assert.equal(previewRowName(row),"regional_json");
});
test("an empty lower detail section is hidden while a public section remains",()=>{
const heading={textContent:"INPUTS"};
const hiddenRow={hidden:true,style:{display:"none"}};
const visibleRow={hidden:false,style:{display:""}};
const hiddenSection={children:[heading,hiddenRow],hidden:false,style:{display:""}};
heading.parentElement=hiddenSection;
const outputHeading={textContent:"OUTPUTS"};
const visibleSection={children:[outputHeading,visibleRow],hidden:false,style:{display:""}};
outputHeading.parentElement=visibleSection;
const card={querySelectorAll:()=>[heading,outputHeading]};
syncPreviewDetailSections({closest:()=>card});
assert.equal(hiddenSection.hidden,true);
assert.equal(hiddenSection.style.display,"none");
assert.equal(visibleSection.hidden,false);
});
test("lower detail cleanup leaves unrelated card sections untouched",()=>{
const heading={textContent:"Description"};
const section={children:[heading],hidden:false,style:{display:""}};
heading.parentElement=section;
syncPreviewDetailSections({closest:()=>({querySelectorAll:()=>[heading]})});
assert.equal(section.hidden,false);
assert.equal(section.style.display,"");
});