Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tw9fjYBYFyV8YG5YDfYPRb
105 lines
5.4 KiB
JavaScript
105 lines
5.4 KiB
JavaScript
import test from "node:test";
|
|
import assert from "node:assert/strict";
|
|
import { createDom } from "../../shell/dom.js";
|
|
import { setupDom, teardownDom } from "../../composer/tests/_dom.js";
|
|
|
|
let hub, readPrefs, createProject;
|
|
test.before(async () => {
|
|
setupDom();
|
|
globalThis.localStorage = window.localStorage;
|
|
({ createProject } = await import("../../shell/project.js"));
|
|
({ default: hub, readPrefs } = await import("./index.js"));
|
|
});
|
|
test.after(() => teardownDom());
|
|
|
|
/** A server holding two projects, as the backend does: whatever was PUT comes back on the next GET. */
|
|
function server() {
|
|
const store = {
|
|
aaaaaaaaaaaa: { id: "aaaaaaaaaaaa", name: "A", scenes: [], updated_at: 1 },
|
|
bbbbbbbbbbbb: { id: "bbbbbbbbbbbb", name: "B", scenes: [], updated_at: 1 },
|
|
};
|
|
globalThis.fetch = async (path, opts = {}) => {
|
|
if (path === "/fun/api/projects" && (!opts.method || opts.method === "GET")) return { ok: true, status: 200, json: async () => ({ projects: Object.values(store).map((p) => ({ id: p.id })) }) };
|
|
const id = decodeURIComponent(String(path).split("/").pop());
|
|
if (opts.method === "PUT") { const body = JSON.parse(opts.body); store[id] = { ...body, updated_at: 2 }; return { ok: true, status: 200, json: async () => store[id] }; }
|
|
return { ok: true, status: 200, json: async () => JSON.parse(JSON.stringify(store[id])) };
|
|
};
|
|
}
|
|
|
|
test("the wheel's settings are saved with the project and come back on a fresh browser, per project", async () => {
|
|
server();
|
|
localStorage.clear();
|
|
const project = createProject({});
|
|
await project.start(); // project A
|
|
const app = { dom: createDom(), project, pipeline: { allOff: () => false }, actions: [], editorSettings: [] };
|
|
const off = hub.setup({ host: document.createElement("div"), app });
|
|
try {
|
|
// change it through the real settings panel
|
|
const handle = app.editorSettings[0]();
|
|
document.body.appendChild(handle.node); const panel = handle.node;
|
|
const half = [...panel.querySelectorAll("button,[role=radio]")].find((b) => b.textContent.trim() === "Half wheel");
|
|
const left = [...panel.querySelectorAll("button,[role=radio]")].find((b) => b.textContent.trim() === "Left");
|
|
half.click(); left.click();
|
|
await project.flush();
|
|
assert.deepEqual(readPrefs(app), { shape: "half", side: "left", enabled: null });
|
|
|
|
// a rental with an empty browser: same project, no localStorage
|
|
localStorage.clear();
|
|
const fresh = createProject({});
|
|
await fresh.start();
|
|
assert.deepEqual(readPrefs({ project: fresh }), { shape: "half", side: "left", enabled: null }, "the choice did not travel with the project");
|
|
|
|
// another project keeps its own choice
|
|
await fresh.open("bbbbbbbbbbbb");
|
|
assert.deepEqual(readPrefs({ project: fresh }), { shape: "full", side: "right", enabled: null });
|
|
} finally { off(); }
|
|
});
|
|
|
|
test("the wheel offers Clear references and the guidance switch, both opt-in, and they act", async () => {
|
|
server();
|
|
localStorage.clear();
|
|
const project = createProject({});
|
|
await project.start();
|
|
let guidance = false;
|
|
let camera = false;
|
|
const pipeline = { allOff: () => false, cameraOff: () => camera, setCameraOff: async (on) => { camera = on; }, modulesById: () => ({ conditioning_shot_camera: {} }), guidanceOff: () => guidance, setGuidanceOff: async (on) => { guidance = on; } };
|
|
const app = { dom: createDom(), project, pipeline, actions: [], editorSettings: [], openSettings: () => {} };
|
|
const off = hub.setup({ host: document.createElement("div"), app });
|
|
try {
|
|
const find = (id) => app.actions.find((a) => a.id === id);
|
|
assert.ok(find("guidance-off") && find("clear-refs"));
|
|
assert.equal(find("guidance-off").optIn, true);
|
|
assert.equal(find("guidance-off").label, "Disable all guidance enhancements");
|
|
await find("guidance-off").run();
|
|
assert.equal(guidance, true);
|
|
assert.equal(find("guidance-off").label, "Enable guidance enhancements");
|
|
assert.equal(find("camera-off").optIn, true);
|
|
assert.equal(find("camera-off").label, "Disable camera move enhancements");
|
|
await find("camera-off").run();
|
|
assert.equal(camera, true);
|
|
assert.equal(find("camera-off").label, "Enable camera move enhancements");
|
|
assert.ok(!find("clear-refs").when(), "nothing to clear without references");
|
|
project.project.scenes.push({ id: "other", references: ["m9"] });
|
|
assert.ok(find("clear-refs").when(), "a reference in any scene counts, not only the selected one");
|
|
await find("clear-refs").run();
|
|
assert.ok(project.project.scenes.every((s) => !(s.references || []).length) && !find("clear-refs").when());
|
|
} finally { off(); }
|
|
});
|
|
|
|
test("Quick A/B is an opt-in wheel action, offered as soon as it is ticked, and starts the run", async () => {
|
|
server();
|
|
localStorage.clear();
|
|
const project = createProject({});
|
|
await project.start();
|
|
let ran = 0;
|
|
const app = { dom: createDom(), project, pipeline: { allOff: () => false, setAllOff: async () => {} }, actions: [], editorSettings: [], lastRun: { n: 0 }, runner: { quickAB: async () => { ran += 1; } } };
|
|
const off = hub.setup({ host: document.createElement("div"), app });
|
|
try {
|
|
const a = app.actions.find((x) => x.id === "quick-ab");
|
|
assert.ok(a && a.optIn && a.label === "Quick A/B");
|
|
assert.ok(a.when(), "on the wheel from the start; with no run yet it says what it needs");
|
|
await a.run();
|
|
assert.equal(ran, 1);
|
|
} finally { off(); }
|
|
});
|