Files
ComfyAssets-ComfyUI_PromptM…/tests/js/workspace-file-inspector.test.js
T
Vito d9537a726c feat(workspace): complete shared inspector and collection viewer (#224)
* feat(inspector): expose bounded physical file evidence

* fix(inspector): distinguish ambiguous saved associations

* feat(inspector): derive conservative generation facts

* fix(inspector): guard fact ancestry and inspection state

* feat(inspector): share complete file details and exports

* fix(inspector): preserve fact states and touch targets

* feat(viewer): navigate the loaded media collection

Refs #216

* fix(viewer): refit after current stage geometry changes

Ref #216. Observe the current media stage after readiness and wrapped title changes without rebuilding focused controls or resetting transforms at unchanged dimensions.

* feat(viewer): add lifecycle-safe slideshow and media preferences

* fix(viewer): resume gallery continuation after close (#216)

* fix(images): guard source recovery and wrap viewer actions

Clear stale root and folder intent, cancel old pages, and wait for current source discovery before loading a refreshed collection. Preserve safe retry through failed, superseded, and disposed discovery.

Wrap narrow viewer footer actions and wait for measured gallery viewport settling in responsive checks. Refs #216; addresses PR #224 review.

* test(viewer): await gallery layout after viewport changes

Require actual inner, root client, and document widths to agree after each responsive-case viewport and CSS zoom transition. Keep the existing exact frame, overflow, focus, and coarse target assertions unchanged.

Observed PR #224 CI initial mobile resize at537px before pending card relayout settled to356px. Refs #216.
2026-10-18 09:41:53 -07:00

51 lines
4.6 KiB
JavaScript

import test from 'node:test';
import assert from 'node:assert/strict';
const modulePath='../../web/js/workspace/file-inspector.mjs';
const load=()=>import(modulePath);
const rawWorkflow='{ "nodes": [], "seed": 9007199254740993, "cfg": 1.0000000000000000001 }';
function record() {
return {identity:{kind:'rooted-file',key:'2:a.png',root_index:2,path:'a.png',root_scope:'a'.repeat(64)},file:{format:'PNG'},prompts:{positive:{status:'resolved',text:'a\n猫'}},generation:{seed:{status:'known',value:'9007199254740993',source:'workflow',evidence:'configuration'}},library:{metadata_scope:'pair',tags:['saved']},download:{filename:'a.png',url:'/prompt_manager/images/serve/a.png?root=2'},metadata:{status:'available',omitted_reason:null,raw:{workflow:rawWorkflow,prompt:'{broken',parameters:'literal <svg> </pre>'},record_formats:{workflow:'original-text',prompt:'original-text',parameters:'original-text'},workflow_graph:{status:'parsed',value:{seed:'9007199254740993'}},prompt_graph:{status:'malformed',value:null},parameters:'literal <svg> </pre>'}};
}
test('metadata export retains literal raw and scoped evidence',async()=>{
const {inspectionDownloads}=await load(),source=record(),download=inspectionDownloads(source).metadata;
assert.equal(download.available,true);assert.equal(download.mime,'application/json');assert.equal(download.filename,'a.metadata.json');
const value=JSON.parse(download.bodyText);assert.equal(value.inspection_version,1);
for(const key of ['identity','file','prompts','generation','library'])assert.deepEqual(value[key],source[key]);
assert.deepEqual(value.metadata.raw,source.metadata.raw);assert.deepEqual(value.metadata.record_formats,source.metadata.record_formats);
assert.equal(value.metadata.prompt_graph,undefined);assert.equal(value.metadata.workflow_graph,undefined);
});
test('workflow export never reserializes unsafe numeric literals',async()=>{
const {inspectionDownloads}=await load();assert.equal(inspectionDownloads(record()).workflow.bodyText,rawWorkflow);
const source=record();source.metadata.workflow_graph.status='malformed';assert.equal(inspectionDownloads(source).workflow.available,false);
});
test('omitted raw forbids partial export',async()=>{
const {inspectionDownloads}=await load(),source=record();source.metadata.status='limited';source.metadata.omitted_reason='response-size-limit';source.metadata.raw={};
for(const value of Object.values(inspectionDownloads(source))) {assert.equal(value.available,false);assert.equal(value.bodyText,null);assert.equal(value.reason,'Raw metadata exceeds the response limit. Download the original file to inspect it externally.');}
assert.ok(source.download.url);
});
test('download names cannot introduce path segments',async()=>{
const {inspectionDownloads}=await load(),source=record();source.download.filename='../../evil\\nested\u0000.png';
for(const value of Object.values(inspectionDownloads(source)))assert.doesNotMatch(value.filename,/[\\/\x00-\x1f]/);
});
test('already disposed inspector creates no DOM URLs or handlers',async()=>{
const {mountFileInspector,mountPromptInspector}=await load(),parent=new AbortController();parent.abort();
const forbidden=new Proxy({}, {get(){assert.fail('disposed mount touched DOM/API');}});
for(const mount of [mountFileInspector,mountPromptInspector]) {
const view=mount(forbidden,{parentScope:{signal:parent.signal},sender:forbidden,api:forbidden,image:forbidden});
view.setState?.({record:record()});view.dispose();view.dispose();
}
});
test('reserialized container workflow never exports as original',async()=>{
const {inspectionDownloads}=await load(),source=record();source.metadata.record_formats.workflow='reserialized-json';
const workflow=inspectionDownloads(source).workflow;assert.equal(workflow.available,false);assert.equal(workflow.bodyText,null);
assert.equal(workflow.reason,'Original workflow JSON text is unavailable for this container record. Download metadata or the original file.');
});
test('metadata export preserves representation formats and omits private carrier',async()=>{
const {inspectionDownloads}=await load(),source=record();source.metadata.record_formats.workflow='reserialized-json';source.metadata.raw.private_carrier='SECRET';source.metadata.carrier='SECRET';
const download=inspectionDownloads(source).metadata,value=JSON.parse(download.bodyText);
assert.equal(value.metadata?.record_formats?.workflow,'reserialized-json');assert.equal(value.metadata.raw.workflow,rawWorkflow);assert.ok(!download.bodyText.includes('SECRET'));
assert.equal(value.metadata.representations.workflow,'Reserialized container JSON; numeric spelling/precision may differ');
});