1// @vitest-environment jsdom
2
3import { describe, expect, it, vi } from "vite-plus/test";
4
5import { forwardWheelToTimeline } from "./timelineMinimapWheel";
6
7function setup() {
8 const timeline = document.createElement("div");
9 const minimap = document.createElement("div");
10 Object.defineProperty(timeline, "clientHeight", { value: 500 });
11 const scrollBy = vi.fn();
12 timeline.scrollBy = scrollBy as typeof timeline.scrollBy;
13 const seen: WheelEvent[] = [];
14 timeline.addEventListener("wheel", (event) => seen.push(event));
15 minimap.addEventListener("wheel", (event) => forwardWheelToTimeline(event, timeline));
16 document.body.append(timeline, minimap);
17 const wheel = (init: WheelEventInit) => {
18 const event = new WheelEvent("wheel", { bubbles: true, cancelable: true, ...init });
19 minimap.dispatchEvent(event);
20 return event;
21 };
22 return { timeline, scrollBy, seen, wheel };
23}
24
25describe("forwardWheelToTimeline", () => {
26 it("replays the wheel on the timeline and scrolls it instead of the minimap", () => {
27 const { timeline, scrollBy, seen, wheel } = setup();
28 const original = wheel({ deltaY: -120, clientX: 20, clientY: 300 });
29
30 expect(original.defaultPrevented).toBe(true);
31 expect(seen).toHaveLength(1);
32 expect(seen[0]?.target).toBe(timeline);
33 expect(seen[0]?.deltaY).toBe(-120);
34 expect(seen[0]?.clientY).toBe(300);
35 expect(scrollBy).toHaveBeenCalledWith({ top: -120 });
36 });
37
38 it.each([
39 { deltaMode: WheelEvent.DOM_DELTA_LINE, top: 48 },
40 { deltaMode: WheelEvent.DOM_DELTA_PAGE, top: 1500 },
41 ])("converts delta mode $deltaMode to pixels", ({ deltaMode, top }) => {
42 const { scrollBy, wheel } = setup();
43 wheel({ deltaY: 3, deltaMode });
44 expect(scrollBy).toHaveBeenCalledWith({ top });
45 });
46
47 it("lets a timeline listener cancel the scroll", () => {
48 const { timeline, scrollBy, wheel } = setup();
49 timeline.addEventListener("wheel", (event) => event.preventDefault());
50 wheel({ deltaY: 40 });
51 expect(scrollBy).not.toHaveBeenCalled();
52 });
53
54 it.each([{ deltaY: 40, ctrlKey: true }, { deltaX: 40 }])(
55 "leaves pinch zoom and horizontal wheels alone: %j",
56 (init) => {
57 const { scrollBy, seen, wheel } = setup();
58 expect(wheel(init).defaultPrevented).toBe(false);
59 expect(seen).toHaveLength(0);
60 expect(scrollBy).not.toHaveBeenCalled();
61 },
62 );
63});