Skip to content
Source
Sign inSign up
Open History to see the last commit

phoneInteraction.test.ts

90 lines3.4 KB

1import { expect, it, vi } from "vite-plus/test";
2import { createPhoneInteraction, phoneWheelNavigation } from "./phoneInteraction.ts";
3​
4it("keeps a captured screen gesture separate from orbit and ends it once on cancellation", () => {
5 const touch = vi.fn();
6 const orbit = vi.fn();
7 const screenPoint = vi
8 .fn()
9 .mockReturnValueOnce({ x: 0.2, y: 0.3 })
10 .mockReturnValueOnce({ x: 1, y: 0.6 });
11 const input = createPhoneInteraction({ screenPoint, touch, orbit, zoomBy: vi.fn() });
12 expect(input.begin(1, { x: 0.4, y: 0.3 })).toBe(true);
13 expect(input.begin(2, { x: 0.2, y: 0.2 })).toBe(false);
14 input.move(2, { x: 0.8, y: 0.8 });
15 input.move(1, { x: 1.3, y: 0.6 });
16 input.end(2);
17 input.end();
18 input.end(1);
19 expect(touch.mock.calls).toEqual([
20 ["begin", { x: 0.2, y: 0.3 }],
21 ["move", { x: 1, y: 0.6 }],
22 ["end", { x: 1, y: 0.6 }],
23 ]);
24 expect(orbit).not.toHaveBeenCalled();
25 expect(screenPoint.mock.calls[1]?.[1]).toBe(true);
26});
27​
28it("blocks navigation during either captured gesture, then resumes without sending device touches", () => {
29 const touch = vi.fn();
30 const orbit = vi.fn();
31 const zoomBy = vi.fn();
32 const input = createPhoneInteraction({
33 screenPoint: () => ({ x: 0.5, y: 0.5 }),
34 touch,
35 orbit,
36 zoomBy,
37 });
38 input.begin(1, { x: 0.5, y: 0.5 });
39 expect(input.navigate({ type: "zoom", delta: 0.2 })).toBe(false);
40 expect(input.navigate({ type: "orbit", x: 0.1, y: 0.2 })).toBe(false);
41 input.end();
42 input.begin(2, { x: 0.5, y: 0.5 }, true);
43 expect(input.navigate({ type: "zoom", delta: 0.2 })).toBe(false);
44 input.end();
45 expect(input.navigate({ type: "zoom", delta: 0.2 })).toBe(true);
46 expect(input.navigate({ type: "orbit", x: 0.1, y: 0.2 })).toBe(true);
47 expect(zoomBy.mock.calls).toEqual([[0.2]]);
48 expect(orbit.mock.calls).toEqual([[0.1, 0.2]]);
49 expect(touch.mock.calls.map(([phase]) => phase)).toEqual(["begin", "end"]);
50});
51​
52it("ends wheel orbit without ending a captured screen touch", () => {
53 const onInteractionActive = vi.fn();
54 const input = createPhoneInteraction({
55 screenPoint: () => ({ x: 0.5, y: 0.5 }),
56 touch: vi.fn(),
57 orbit: vi.fn(),
58 zoomBy: vi.fn(),
59 onInteractionActive,
60 });
61 input.endWheel();
62 expect(onInteractionActive).toHaveBeenCalledWith(false, "orbit");
63 input.begin(1, { x: 0.5, y: 0.5 });
64 onInteractionActive.mockClear();
65 input.endWheel();
66 expect(onInteractionActive).not.toHaveBeenCalled();
67 input.end(1);
68 expect(onInteractionActive).toHaveBeenCalledWith(false, "touch");
69});
70​
71it("normalizes wheel units, distinguishes pinch, and bounds jumps from coarse scroll wheels", () => {
72 const wheel = { width: 400, height: 800, deltaX: 16, deltaY: 32, deltaMode: 0, ctrlKey: false };
73 expect(phoneWheelNavigation(wheel)).toEqual({ type: "orbit", x: -0.04, y: -0.04 });
74 expect(phoneWheelNavigation({ ...wheel, deltaX: 1, deltaY: 2, deltaMode: 1 })).toEqual(
75 phoneWheelNavigation(wheel),
76 );
77 expect(phoneWheelNavigation({ ...wheel, deltaX: 1, deltaY: 1, deltaMode: 2 })).toEqual({
78 type: "orbit",
79 x: -0.25,
80 y: -0.25,
81 });
82 expect(phoneWheelNavigation({ ...wheel, ctrlKey: true })).toEqual({ type: "zoom", delta: -0.32 });
83 expect(phoneWheelNavigation({ ...wheel, deltaY: -10000, ctrlKey: true })).toEqual({
84 type: "zoom",
85 delta: 1,
86 });
87 expect(phoneWheelNavigation({ ...wheel, width: 0 })).toBeNull();
88 expect(phoneWheelNavigation({ ...wheel, deltaY: NaN })).toBeNull();
89 expect(phoneWheelNavigation({ ...wheel, deltaMode: 9 })).toBeNull();
90});