import { describe, it, expect, expectTypeOf } from "vitest"; import type { Fiber, Effect } from "../src/host/fiber.js"; const baseFiber: Omit, "instance" | "tag" | "props" | "key"> = { children: [], parent: null, effect: null, signalDisposers: [], prevProps: null, cachedNode: null, }; describe("Fiber interface", () => { it("has all required fields", () => { const fiber: Fiber = { instance: "inst-1", tag: "div", props: { class: "test" }, key: "a", ...baseFiber, }; expect(fiber.instance).toBe("inst-1"); expect(fiber.tag).toBe("div"); expect(fiber.props.class).toBe("test"); expect(fiber.key).toBe("a"); expect(fiber.children).toEqual([]); expect(fiber.parent).toBeNull(); expect(fiber.effect).toBeNull(); expect(fiber.signalDisposers).toEqual([]); expect(fiber.prevProps).toBeNull(); expect(fiber.cachedNode).toBeNull(); }); it("supports key as undefined", () => { const fiber: Fiber = { instance: "inst-2", tag: "span", props: {}, key: undefined, ...baseFiber, }; expect(fiber.key).toBeUndefined(); }); it("supports parent reference", () => { const parent: Fiber = { instance: "parent-inst", tag: "div", props: {}, key: undefined, ...baseFiber, }; const child: Fiber = { instance: "child-inst", tag: "span", props: {}, key: "child-1", ...baseFiber, parent, }; parent.children.push(child); expect(child.parent).toBe(parent); expect(parent.children[0]).toBe(child); }); it("supports signalDisposers array", () => { const disposed: string[] = []; const fiber: Fiber = { instance: "inst", tag: "div", props: {}, key: undefined, ...baseFiber, signalDisposers: [() => disposed.push("a"), () => disposed.push("b")], }; fiber.signalDisposers.forEach((d) => d()); expect(disposed).toEqual(["a", "b"]); }); }); describe("Effect union type", () => { it("update effect", () => { const effect: Effect = { type: "update", payload: { class: "new" } }; expect(effect.type).toBe("update"); expect((effect as { type: "update"; payload: unknown }).payload).toEqual({ class: "new" }); }); it("insert effect with before=null (append)", () => { const effect: Effect = { type: "insert", before: null }; expect(effect.type).toBe("insert"); }); it("insert effect with before=fiber", () => { const before: Fiber = { instance: "existing", tag: "span", props: {}, key: undefined, ...baseFiber, }; const effect: Effect = { type: "insert", before }; expect(effect.type).toBe("insert"); expect(effect.before).toBe(before); }); it("move effect with before=fiber", () => { const before: Fiber = { instance: "target", tag: "span", props: {}, key: undefined, ...baseFiber, }; const effect: Effect = { type: "move", before }; expect(effect.type).toBe("move"); expect(effect.before).toBe(before); }); it("move effect with before=null (append at end)", () => { const effect: Effect = { type: "move", before: null }; expect(effect.type).toBe("move"); }); it("remove effect", () => { const effect: Effect = { type: "remove" }; expect(effect.type).toBe("remove"); }); it("effect field on Fiber accepts all variants", () => { const fiber: Fiber = { instance: 1, tag: "div", props: {}, key: undefined, ...baseFiber, effect: { type: "update", payload: "x" }, prevProps: {}, }; expect(fiber.effect!.type).toBe("update"); fiber.effect = { type: "remove" }; expect(fiber.effect.type).toBe("remove"); fiber.effect = { type: "insert", before: null }; expect(fiber.effect.type).toBe("insert"); fiber.effect = { type: "move", before: null }; expect(fiber.effect.type).toBe("move"); fiber.effect = null; expect(fiber.effect).toBeNull(); }); }); describe("Fiber re-export from barrel", () => { it("Fiber and Effect types are importable from src/mod.ts", async () => { type _FiberCheck = import("../src/mod.js").Fiber; type _EffectCheck = import("../src/mod.js").Effect; const _fiber: _FiberCheck = { instance: "inst", tag: "div", props: {}, key: undefined, ...baseFiber, }; const _effect: _EffectCheck = { type: "remove" }; expect(_fiber.instance).toBe("inst"); expect(_effect.type).toBe("remove"); }); });