import assert from "node:assert/strict"; import { readFile } from "node:fs/promises"; import test from "node:test"; import { createTemplateEditContext, sceneNeedsTemplateSave, templateEditSnapshot, } from "../app/static/template-edit-model.js"; const staticRoot = new URL("../app/static/", import.meta.url); test("template edit baseline distinguishes clean, dirty, and unbound scenes", () => { const context = createTemplateEditContext({ id: "template-1", name: "测试模板", revision: "revision-1", read_only: true, }, "scene-a"); assert.equal(sceneNeedsTemplateSave(null, "scene-a"), true); assert.equal(sceneNeedsTemplateSave(context, "scene-a"), false); assert.equal(sceneNeedsTemplateSave(context, "scene-b"), true); assert.deepEqual(templateEditSnapshot(context, "scene-a"), { id: "template-1", name: "测试模板", revision: "revision-1", readOnly: true, dirty: false, }); assert.equal(templateEditSnapshot(context, "scene-b").dirty, true); }); test("template manager uses a monitor and unified four-row card actions", async () => { const [html, board, templates, style] = await Promise.all([ readFile(new URL("index.html", staticRoot), "utf8"), readFile(new URL("scene-board.js", staticRoot), "utf8"), readFile(new URL("views/templates.js", staticRoot), "utf8"), readFile(new URL("style.css", staticRoot), "utf8"), ]); assert.match(board, /MONITOR_WORKSPACES = new Set\(\["device", "settings", "templates"\]\)/); assert.match(templates, /actions\.append\(play, edit, copy, rename, remove\)/); assert.match(templates, /template-card-delete-action/); assert.match(templates, /api\/templates\/\$\{template\.id\}\/play/); assert.match(templates, /enterTemplateEdit\(full\)/); assert.match(templates, /当前内容将会丢失/); assert.match(templates, /actionButton\("上移"/); assert.match(templates, /actionButton\("下移"/); assert.match(templates, /name\.dataset\.hoverTooltip = animation\.name/); assert.match(templates, /template-card-name animation-folder-name/); assert.match(style, /\.template-card-content-actions,[\s\S]*grid-template-columns: repeat\(2/); assert.match(style, /\.template-card-delete-action\s*\{\s*grid-column: 1 \/ -1/); assert.match(html, /id="template-save-choice-dialog"/); assert.match(html, /value="current">保存到当前模板/); assert.match(html, /value="new">另存为新模板/); }); test("animation editing backs up and restores template edit ownership", async () => { const board = await readFile(new URL("scene-board.js", staticRoot), "utf8"); assert.match(board, /templateEdit: templateEdit \? \{ \.\.\.templateEdit \} : null/); assert.match(board, /templateEditContext: backup\.templateEdit/); assert.match(board, /markTemplateSaved/); });