Files
JasonHoku-ComfyUI-Ultimate-…/tests/js/workflow-frames-fps.test.js
T
Jason HokuandClaude Fable 5.1 725cb79fd4 feat(sweep): mixed standard + Workflow Sweep runs; SaveWEBM/AnimatedWEBP/AnimatedPNG frame sources (Roadmap 32)
- one Generator run may hold standard configs AND workflow-sweep entries: the sweep is validated
  first (job 1 + busy check, nothing registered), the standard loop runs, then start_sweep launches
  into the same session with one global job numbering (Start At Job counts standard jobs first).
  An interrupt in the loop never starts the sweep; meta.configs_json keeps the full Builder list
  (_standard_run_meta/_completion_payload helpers; next_phase on the completion event; the
  dashboard keeps the ETA bar up with "Workflow sweep next…" and clears the 30 s hide timer on
  any later progress event)
- frame sources: FRAME_SINKS table (VHS_VideoCombine, SaveWEBM, SaveAnimatedWEBP, SaveAnimatedPNG)
  feeding the CreateVideo splice; fps read per sink, clamped to CreateVideo's 1-120 with a plan
  warning; find_output_nodes fallback names; Builder label via framesFps
- tests: 33 python (mixed routing, Start At Job translation, interrupt, pre-flight busy/invalid,
  post-loop busy, three sink fixtures, clamping, VHS golden unchanged), 2 node, 2 Playwright

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-11-04 18:48:44 -08:00

33 lines
1.5 KiB
JavaScript

// framesFps: the fps shown in the Builder's "Video" option label for VHS and the core frame sinks.
const test = require('node:test');
const assert = require('node:assert');
const fs = require('fs');
const path = require('path');
function grab(src, name) {
const m = new RegExp('(?:export )?(?:async )?function ' + name + '[(]').exec(src);
assert.ok(m, name + ' not found');
let i = src.indexOf('{', m.index), depth = 0, j = i;
for (; j < src.length; j++) {
if (src[j] === '{') depth++;
else if (src[j] === '}') { depth--; if (depth === 0) break; }
}
return src.slice(m.index, j + 1).replace(/^export /, '');
}
const sweep = fs.readFileSync(path.join(__dirname, '../../web/conf_builder/conf-builder-workflow-sweep.js'), 'utf8');
const { framesFps } = new Function(grab(sweep, 'framesFps') + '\nreturn { framesFps };')();
test('VHS frame_rate and core sink fps are read', () => {
assert.strictEqual(framesFps({ 2: { inputs: { frame_rate: 8 } } }, '2'), 8);
assert.strictEqual(framesFps({ 2: { inputs: { fps: 12.5 } } }, '2'), 12.5);
assert.strictEqual(framesFps({ 2: { inputs: { frame_rate: 16, fps: 4 } } }, '2'), 16);
});
test('links, strings and missing nodes give undefined', () => {
assert.strictEqual(framesFps({ 2: { inputs: { fps: ['3', 0] } } }, '2'), undefined);
assert.strictEqual(framesFps({ 2: { inputs: { fps: '12' } } }, '2'), undefined);
assert.strictEqual(framesFps({}, '2'), undefined);
assert.strictEqual(framesFps(null, '2'), undefined);
});