CI / verify (push) Failing after 5m9s
Align the notebook browser with the physical LCD, refresh real project captures and navigation, simplify service content, and stabilize hero hydration.
76 lines
2.8 KiB
TypeScript
76 lines
2.8 KiB
TypeScript
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);
|
|
});
|
|
});
|