Files
cyberhirsch-seb_nodes/tests/test_camera_edit_persists.py
Seb Hirsch a0ec2d5b8b Folder batch loader, Save Image source modes, headless test suite
Load Images From Folder walks a folder one image per run, queueing the next itself once the current run has finished, or emits every image as a list. Save Image (Seb) can save next to the source or replace it in place, atomically, keeping the format. tests/ drives a real headless Chromium against a scratch ComfyUI; see tests/README.md.
2026-09-13 17:10:58 +02:00

48 lines
1.9 KiB
Python

"""Typing a camera on the node must survive the editor writing state_json.
The editor seeds a default frame and rewrites state_json on unrelated changes;
without the push-back sync that stamped 42/0/0 over whatever was typed.
"""
import json
import time
from playwright.sync_api import sync_playwright
from _common import PANO, add_read_node, finish, open_app, require_server, set_widget
require_server()
SNAP = """() => {
const n = window.app.graph._nodes.find(x => x.type === 'Read360Seb');
const g = k => n.widgets.find(w => w.name === k).value;
let sh = null; try { sh = (JSON.parse(g('state_json') || '{}').shots || [])[0] || null; } catch (e) {}
return {fov: g('fov'), yaw: g('yaw'), pitch: g('pitch'),
shot: sh && {yaw: sh.yaw_deg, pitch: sh.pitch_deg, h: sh.hFOV_deg, v: sh.vFOV_deg}}; }"""
TOUCH = """() => {
const n = window.app.graph._nodes.find(x => x.type === 'Read360Seb');
const w = n.widgets.find(x => x.name === 'state_json');
const st = JSON.parse(w.value); st.output_preset = 4096; w.value = JSON.stringify(st); }"""
rep = {}
with sync_playwright() as pw:
b, pg = open_app(pw)
add_read_node(pg, PANO)
time.sleep(3) # editor seeds its default frame
rep["seeded"] = pg.evaluate(SNAP)
for k, v in (("fov", 90), ("yaw", 35), ("pitch", -20)):
set_widget(pg, k, v)
time.sleep(3) # push-back has had its 200ms
rep["after_typing"] = pg.evaluate(SNAP)
pg.evaluate(TOUCH) # something else rewrites state_json
time.sleep(2)
rep["after_state_rewrite"] = pg.evaluate(SNAP)
b.close()
a, t = rep["after_state_rewrite"], rep["after_typing"]
rep["VERDICT"] = {
"seeded_a_frame": bool(rep["seeded"]["shot"]),
"typed_values_pushed_into_state": t["shot"] and t["shot"]["yaw"] == 35 and t["shot"]["h"] == 90,
"typed_values_survive_rewrite": a["fov"] == 90 and a["yaw"] == 35 and a["pitch"] == -20,
}
finish(rep, all(rep["VERDICT"].values()))