import assert from "node:assert/strict"; import { readFileSync } from "node:fs"; import { test } from "node:test"; import { JSDOM } from "jsdom"; function openDemo(name) { const html = readFileSync(new URL("../demo/" + name, import.meta.url), "utf8"); const dom = new JSDOM(html, { runScripts: "outside-only" }); const { window } = dom; const observers = []; window.ResizeObserver = class { constructor(callback) { this.callback = callback; this.disconnected = false; observers.push(this); } observe(root) { this.root = root; } disconnect() { this.disconnected = true; } }; // 此處驗證事件刷新與觀察目標;矩形模型不作真實 layout 驗收。 const rect = { top: 0, bottom: 20, left: 0, right: 20, width: 20, height: 20 }; window.Element.prototype.getClientRects = () => [ rect ]; window.Range.prototype.getClientRects = () => [ rect ]; window.eval(readFileSync(new URL("../dist/juzhen.iife.js", import.meta.url), "utf8")); for (const script of window.document.querySelectorAll("script:not([src])")) { window.eval(script.textContent); } return { dom, window, document: window.document, observers }; } function change(window, id, checked) { const input = window.document.getElementById(id); input.checked = checked; input.dispatchEvent(new window.Event("change")); } test("index demo:對齊與寬度明確重排,revert 後開關不重新啟用", () => { const { dom, window, document, observers } = openDemo("index.html"); try { for (const [ id, checked ] of [ [ "justify", true ], [ "wide", true ] ]) { const oldGap = document.querySelector("jz-hws"); const oldObservers = observers.filter((observer) => !observer.disconnected); assert.ok(oldGap); change(window, id, checked); assert.equal(oldGap.isConnected, false, id + " 撤回舊產物"); assert.ok(document.querySelector("jz-hws"), id + " 重新建立產物"); assert.ok(oldObservers.every((observer) => observer.disconnected), id + " 更換 layout 安裝"); } assert.ok(document.body.classList.contains("justify")); assert.equal(document.querySelector(".narrow").style.maxWidth, "none"); document.getElementById("revert").click(); const count = observers.length; assert.equal(document.querySelector("[data-jz]"), null); change(window, "justify", false); change(window, "wide", false); change(window, "force-kaiming", true); assert.equal(document.querySelector("[data-jz]"), null, "revert 狀態仍保持"); assert.equal(observers.length, count, "停用時不新增 layout 安裝"); document.getElementById("render").click(); assert.ok(document.querySelector("jz-hws"), "手動 render 可重新啟用"); assert.ok(document.getElementById("status").textContent.includes("开明式")); } finally { dom.window.close(); } }); test("resize demo:各拖曳框各自被觀察,切換對齊刷新所有框", () => { const { dom, window, document, observers } = openDemo("resize-check.html"); try { const boxes = Array.from(document.querySelectorAll(".box.juzhen")); const targets = new Set(observers.map((observer) => observer.root)); assert.equal(targets.size, boxes.length); assert.ok(boxes.every((box) => targets.has(box))); assert.equal(targets.has(document.body), false); const oldGaps = boxes.flatMap((box) => Array.from(box.querySelectorAll("jz-hws"))); const oldObservers = observers.slice(); assert.ok(oldGaps.length > 0); change(window, "t-justify", true); assert.ok(oldGaps.every((gap) => !gap.isConnected), "所有框撤回舊間隙"); assert.ok(oldObservers.every((observer) => observer.disconnected)); const activeTargets = new Set(observers.filter((observer) => !observer.disconnected) .map((observer) => observer.root)); assert.equal(activeTargets.size, boxes.length); assert.ok(boxes.every((box) => activeTargets.has(box))); assert.ok(document.querySelector("jz-hws"), "新產物仍存在"); } finally { dom.window.close(); } });