import { getNotebookFrame, getNotebookSeekProgress } from "./notebookTimeline"; describe("notebook choreography", () => { it("opens and boots before browsing, then blanks the display before closing", () => { const frames = Array.from({ length: 1001 }, (_, index) => getNotebookFrame(index / 1000, 4), ); const phases = [...new Set(frames.map((frame) => frame.phase))]; expect(phases).toEqual([ "approach", "open", "boot", "cursor-in", "browse", "hold", "close", ]); for (const frame of frames) { if (frame.phase === "open") expect(frame.screenOpacity).toBe(0); if (frame.cursorVisible) expect(frame.screenOpacity).toBe(1); if (frame.phase === "close" && frame.lidAngle < 112) expect(frame.screenOpacity).toBe(0); } expect(getNotebookFrame(-1, 4).lidAngle).toBe(0); expect(getNotebookFrame(2, 4).lidAngle).toBe(0); }); it("keeps the previous project until cursor arrival, including reverse scroll", () => { const frames = Array.from({ length: 10001 }, (_, index) => getNotebookFrame(index / 10000, 4), ); for (let selected = 1; selected < 4; selected += 1) { const arrival = frames.findIndex( (frame) => frame.activeTabIndex === selected, ); const before = getNotebookFrame((arrival - 1) / 10000, 4); const atClick = frames[arrival]; expect(before.activeTabIndex).toBe(selected - 1); expect(before.cursorClicking).toBe(false); expect(atClick.cursorClicking).toBe(true); expect(atClick.cursorX).toBeCloseTo((selected + 0.5) / 4); const reversed = getNotebookFrame((arrival - 2) / 10000, 4); expect(reversed.activeTabIndex).toBe(selected - 1); expect(reversed.cursorX).toBeLessThan(atClick.cursorX); expect(reversed.cursorX).toBeGreaterThan((selected - 0.5) / 4); } }); it("seeks directly into a readable hold for the requested project", () => { for (const count of [1, 4]) { for (let index = 0; index < count; index += 1) { const progress = getNotebookSeekProgress(index, count); const frame = getNotebookFrame(progress, count); expect(frame.activeTabIndex).toBe(index); expect(frame.screenOpacity).toBe(1); expect(frame.cursorClicking).toBe(false); expect(getNotebookFrame(progress + 0.03, count).activeTabIndex).toBe( index, ); } } expect( getNotebookFrame(getNotebookSeekProgress(99, 4), 4).activeTabIndex, ).toBe(3); }); it("does not expose a tab or cursor for empty or invalid project counts", () => { expect(getNotebookFrame(0.6, 0)).toMatchObject({ activeTabIndex: -1, cursorVisible: false, cursorClicking: false, }); expect(getNotebookFrame(0.6, Number.NaN).activeTabIndex).toBe(-1); }); });