import { getNotebookFrame } from "./notebookTimeline"; describe("getNotebookFrame", () => { it("clamps progress below zero and starts with a closed device", () => { expect(getNotebookFrame(-1, 4)).toMatchObject({ phase: "approach", lidAngle: 0, activeTabIndex: -1, cursorVisible: false, }); }); it("clamps progress above one and ends with a closed device", () => { expect(getNotebookFrame(2, 4)).toMatchObject({ phase: "close", lidAngle: 0, activeTabIndex: -1, cursorVisible: false, }); }); it("keeps the phase boundaries deterministic", () => { expect(getNotebookFrame(0.1, 4).phase).toBe("open"); expect(getNotebookFrame(0.25, 4).phase).toBe("boot"); expect(getNotebookFrame(0.34, 4).phase).toBe("cursor-in"); expect(getNotebookFrame(0.44, 4).phase).toBe("browse"); expect(getNotebookFrame(0.78, 4).phase).toBe("hold"); expect(getNotebookFrame(0.87, 4).phase).toBe("close"); }); it("opens the lid before the browser starts", () => { const frame = getNotebookFrame(0.22, 4); expect(frame.phase).toBe("open"); expect(frame.lidAngle).toBeGreaterThan(0); expect(frame.screenOpacity).toBe(0); }); it("boots the screen before the cursor enters", () => { expect(getNotebookFrame(0.25, 4).screenOpacity).toBe(0); expect(getNotebookFrame(0.34, 4).screenOpacity).toBe(1); expect(getNotebookFrame(0.4, 4).cursorVisible).toBe(true); }); it("selects each tab only inside the browse window", () => { expect(getNotebookFrame(0.43, 4).activeTabIndex).toBe(-1); expect(getNotebookFrame(0.48, 4).activeTabIndex).toBe(0); expect(getNotebookFrame(0.57, 4).activeTabIndex).toBe(1); expect(getNotebookFrame(0.67, 4).activeTabIndex).toBe(2); expect(getNotebookFrame(0.76, 4).activeTabIndex).toBe(3); }); it("holds the final tab until the closing phase", () => { expect(getNotebookFrame(0.84, 4)).toMatchObject({ phase: "hold", activeTabIndex: 3, cursorVisible: true, }); expect(getNotebookFrame(0.88, 4)).toMatchObject({ phase: "close", activeTabIndex: -1, cursorVisible: false, }); }); it("emits a deterministic cursor click pulse for each tab", () => { const first = getNotebookFrame(0.447, 4); const later = getNotebookFrame(0.53, 4); expect(first.cursorClicking).toBe(true); expect(later.cursorClicking).toBe(true); expect(first.cursorX).toBeGreaterThanOrEqual(0); expect(first.cursorX).toBeLessThanOrEqual(1); expect(first.cursorY).toBeGreaterThanOrEqual(0); expect(first.cursorY).toBeLessThanOrEqual(1); }); it("is deterministic when rewound to the same progress", () => { expect(getNotebookFrame(0.61, 4)).toEqual(getNotebookFrame(0.61, 4)); }); it("does not expose an invalid tab when there are no projects", () => { expect(getNotebookFrame(0.6, 0)).toMatchObject({ activeTabIndex: -1, cursorVisible: false, cursorClicking: false, }); }); });