1import { describe, expect, it } from "vite-plus/test";
2
3import {
4 resizeBrowserViewportFromRail,
5 resizeFreeformViewport,
6 resolveBrowserDeviceViewportLayout,
7 resolveFittedBrowserViewport,
8 resolveBrowserViewportLayout,
9 resolveResponsiveBrowserViewportSize,
10} from "./browserViewportLayout";
11
12describe("resolveBrowserViewportLayout", () => {
13 it("uses the current fixed viewport instead of stale fitted source dimensions", () => {
14 expect(
15 resolveFittedBrowserViewport(
16 { _tag: "freeform", width: 900, height: 600 },
17 { width: 1280, height: 800, scale: 1 },
18 ),
19 ).toEqual({ _tag: "freeform", width: 900, height: 600 });
20 });
21
22 it("preserves the last logical viewport when fitting a fill-mode surface", () => {
23 expect(
24 resolveFittedBrowserViewport({ _tag: "fill" }, { width: 320, height: 200, scale: 0.25 }),
25 ).toEqual({ _tag: "freeform", width: 1280, height: 800 });
26 });
27
28 it("fills the available surface in fill mode", () => {
29 expect(resolveBrowserViewportLayout({ width: 700, height: 500 }, { _tag: "fill" })).toEqual({
30 canvasWidth: 700,
31 canvasHeight: 500,
32 viewportX: 0,
33 viewportY: 0,
34 viewportWidth: 700,
35 viewportHeight: 500,
36 viewportScale: 1,
37 fillsPanel: true,
38 });
39 });
40
41 it("centers a smaller fixed viewport", () => {
42 expect(
43 resolveBrowserViewportLayout(
44 { width: 700, height: 1000 },
45 { _tag: "freeform", width: 393, height: 852 },
46 ),
47 ).toMatchObject({
48 canvasWidth: 700,
49 canvasHeight: 1000,
50 viewportX: 154,
51 viewportY: 74,
52 viewportWidth: 393,
53 viewportHeight: 852,
54 });
55 });
56
57 it("scales a larger fixed viewport down to fit without creating overflow", () => {
58 const layout = resolveBrowserViewportLayout(
59 { width: 600, height: 700 },
60 { _tag: "freeform", width: 1440, height: 900 },
61 );
62 expect(layout).toMatchObject({
63 canvasWidth: 600,
64 canvasHeight: 700,
65 viewportX: 0,
66 viewportY: 163,
67 viewportWidth: 600,
68 viewportHeight: 375,
69 });
70 expect(layout.viewportScale).toBeCloseTo(5 / 12);
71 });
72
73 it("keeps fixed dimensions in page CSS pixels when browser zoom changes", () => {
74 expect(
75 resolveBrowserViewportLayout(
76 { width: 800, height: 700 },
77 { _tag: "freeform", width: 400, height: 300 },
78 1.5,
79 ),
80 ).toMatchObject({
81 viewportX: 100,
82 viewportY: 125,
83 viewportWidth: 600,
84 viewportHeight: 450,
85 });
86 expect(resizeFreeformViewport({ width: 400, height: 300 }, { x: 150, y: 75 }, 1.5)).toEqual({
87 width: 500,
88 height: 350,
89 });
90 });
91
92 it("bounds freeform drag sizes and total render area", () => {
93 expect(resizeFreeformViewport({ width: 1024, height: 768 }, { x: -2000, y: -2000 })).toEqual({
94 width: 240,
95 height: 240,
96 });
97 const large = resizeFreeformViewport({ width: 1920, height: 1080 }, { x: 2000, y: 2000 });
98 expect(large.width * large.height).toBeLessThanOrEqual(3840 * 2160);
99 });
100
101 it("resizes only the axes controlled by each edge", () => {
102 expect(
103 resizeFreeformViewport({ width: 800, height: 600 }, { x: -100, y: 500 }, 1, "west"),
104 ).toEqual({ width: 900, height: 600 });
105 expect(
106 resizeFreeformViewport({ width: 800, height: 600 }, { x: 500, y: 100 }, 1, "north"),
107 ).toEqual({ width: 800, height: 500 });
108 expect(
109 resizeFreeformViewport({ width: 800, height: 600 }, { x: -100, y: -50 }, 1, "northwest"),
110 ).toEqual({ width: 900, height: 650 });
111 });
112
113 it("preserves a locked aspect ratio from either axis", () => {
114 expect(
115 resizeFreeformViewport({ width: 800, height: 600 }, { x: 200, y: 0 }, 1, "east", 4 / 3),
116 ).toEqual({ width: 1000, height: 750 });
117 expect(
118 resizeFreeformViewport({ width: 800, height: 600 }, { x: 0, y: 150 }, 1, "south", 4 / 3),
119 ).toEqual({ width: 1000, height: 750 });
120 });
121
122 it("reserves persistent device-toolbar rails around the guest viewport", () => {
123 expect(
124 resolveBrowserDeviceViewportLayout(
125 { width: 1200, height: 900 },
126 { _tag: "freeform", width: 1168, height: 846 },
127 ),
128 ).toEqual({
129 canvasWidth: 1200,
130 canvasHeight: 900,
131 viewportX: 16,
132 viewportY: 38,
133 viewportWidth: 1168,
134 viewportHeight: 846,
135 viewportScale: 1,
136 fillsPanel: false,
137 });
138 });
139
140 it("captures the available framed area when responsive mode is enabled", () => {
141 expect(resolveResponsiveBrowserViewportSize({ width: 1200, height: 900 })).toEqual({
142 width: 1168,
143 height: 846,
144 });
145 expect(resolveResponsiveBrowserViewportSize({ width: 1200, height: 900 }, 2)).toEqual({
146 width: 584,
147 height: 423,
148 });
149 });
150
151 it("keeps the grabbed rail under the pointer across centered layout boundaries", () => {
152 const available = { width: 1120, height: 818 };
153 expect(
154 resizeBrowserViewportFromRail(
155 { width: 1120, height: 818 },
156 { x: -100, y: -50 },
157 available,
158 1,
159 "southeast",
160 ),
161 ).toEqual({ width: 920, height: 718 });
162 expect(
163 resizeBrowserViewportFromRail(
164 { width: 800, height: 600 },
165 { x: 300, y: 0 },
166 { width: 1200, height: 800 },
167 1,
168 "east",
169 ),
170 ).toEqual({ width: 1300, height: 600 });
171 expect(
172 resizeBrowserViewportFromRail(
173 { width: 560, height: 409 },
174 { x: -100, y: 0 },
175 available,
176 2,
177 "east",
178 ),
179 ).toEqual({ width: 460, height: 409 });
180 });
181});