vueless 1.2.10-beta.1 → 1.2.10-beta.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/composables/useRequestQueue.ts +47 -0
- package/constants.d.ts +1 -0
- package/constants.js +1 -0
- package/icons/storybook/arrow_forward_ios.svg +1 -0
- package/index.d.ts +4 -1
- package/index.ts +4 -1
- package/package.json +2 -2
- package/types.ts +2 -0
- package/ui.button/UButton.vue +2 -6
- package/ui.button/config.ts +5 -0
- package/ui.button/tests/UButton.test.ts +1 -1
- package/ui.container-drawer/UDrawer.vue +365 -0
- package/ui.container-drawer/config.ts +128 -0
- package/ui.container-drawer/constants.ts +5 -0
- package/ui.container-drawer/storybook/docs.mdx +16 -0
- package/ui.container-drawer/storybook/stories.ts +255 -0
- package/ui.container-drawer/tests/UDrawer.test.ts +680 -0
- package/ui.container-drawer/types.ts +67 -0
- package/ui.container-modal/storybook/stories.ts +4 -1
- package/ui.container-modal-confirm/storybook/stories.ts +29 -24
- package/ui.form-calendar/UCalendarMonthView.vue +4 -4
- package/ui.form-calendar/tests/UCalendar.test.ts +8 -8
- package/ui.form-calendar/tests/UCalendarMonthView.test.ts +1 -1
- package/ui.form-calendar/utilCalendar.ts +2 -2
- package/ui.form-date-picker-range/UDatePickerRangeInputs.vue +20 -19
- package/ui.loader-overlay/useLoaderOverlay.ts +4 -4
- package/ui.loader-progress/ULoaderProgress.vue +41 -46
- package/ui.loader-progress/storybook/docs.mdx +24 -13
- package/ui.loader-progress/storybook/stories.ts +0 -9
- package/ui.loader-progress/types.ts +2 -2
- package/ui.loader-progress/useLoaderProgress.ts +36 -26
- package/ui.loader-progress/utilLoaderProgress.ts +12 -18
- package/ui.navigation-tabs/UTabs.vue +0 -1
- package/utils/requestQueue.ts +21 -0
|
@@ -0,0 +1,680 @@
|
|
|
1
|
+
import { mount } from "@vue/test-utils";
|
|
2
|
+
import { describe, it, expect, vi } from "vitest";
|
|
3
|
+
|
|
4
|
+
import UDrawer from "../UDrawer.vue";
|
|
5
|
+
import UHeader from "../../ui.text-header/UHeader.vue";
|
|
6
|
+
|
|
7
|
+
import type { Props } from "../types";
|
|
8
|
+
|
|
9
|
+
describe("UDrawer", () => {
|
|
10
|
+
const modelValue = true;
|
|
11
|
+
|
|
12
|
+
// Wait for an async component to load
|
|
13
|
+
function sleep(ms: number = 0) {
|
|
14
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Props tests
|
|
18
|
+
describe("Props", () => {
|
|
19
|
+
it("ModelValue – renders when true", () => {
|
|
20
|
+
const component = mount(UDrawer, {
|
|
21
|
+
props: {
|
|
22
|
+
modelValue,
|
|
23
|
+
},
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
expect(component.isVisible()).toBe(modelValue);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it("ModelValue – does not render when false", () => {
|
|
30
|
+
const modelValue = false;
|
|
31
|
+
|
|
32
|
+
const component = mount(UDrawer, {
|
|
33
|
+
props: {
|
|
34
|
+
modelValue,
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
expect(component.find("[vl-key='overlay']").exists()).toBe(modelValue);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it("Title – renders with title prop", () => {
|
|
42
|
+
const title = "Drawer Title";
|
|
43
|
+
|
|
44
|
+
const component = mount(UDrawer, {
|
|
45
|
+
props: {
|
|
46
|
+
modelValue,
|
|
47
|
+
title,
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
const header = component.findComponent(UHeader);
|
|
52
|
+
|
|
53
|
+
expect(header.exists()).toBe(true);
|
|
54
|
+
expect(header.props("label")).toBe(title);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it("Description – renders with description prop", () => {
|
|
58
|
+
const title = "Drawer Title";
|
|
59
|
+
const description = "Drawer Description";
|
|
60
|
+
|
|
61
|
+
const component = mount(UDrawer, {
|
|
62
|
+
props: {
|
|
63
|
+
modelValue,
|
|
64
|
+
title,
|
|
65
|
+
description,
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
expect(component.text()).toContain(description);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it("Position – applies correct position classes", () => {
|
|
73
|
+
const positions = {
|
|
74
|
+
top: ["top-0", "w-full", "h-auto"],
|
|
75
|
+
bottom: ["bottom-0", "w-full", "h-auto"],
|
|
76
|
+
left: ["left-0", "w-max", "h-full"],
|
|
77
|
+
right: ["right-0", "w-max", "h-full"],
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
Object.entries(positions).forEach(([position, expectedClasses]) => {
|
|
81
|
+
const component = mount(UDrawer, {
|
|
82
|
+
props: {
|
|
83
|
+
modelValue,
|
|
84
|
+
position: position as Props["position"],
|
|
85
|
+
},
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
const drawerClasses = component.find("[vl-key='drawerWrapper']").attributes("class");
|
|
89
|
+
|
|
90
|
+
expectedClasses.forEach((expectedClass) => {
|
|
91
|
+
expect(drawerClasses).toContain(expectedClass);
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it("Variant – applies correct variant classes", () => {
|
|
97
|
+
const variants = {
|
|
98
|
+
solid: "bg-default",
|
|
99
|
+
outlined: "bg-default",
|
|
100
|
+
subtle: "bg-muted",
|
|
101
|
+
soft: "bg-muted",
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
Object.entries(variants).forEach(([variant, expectedClasses]) => {
|
|
105
|
+
const component = mount(UDrawer, {
|
|
106
|
+
props: {
|
|
107
|
+
modelValue,
|
|
108
|
+
variant: variant as Props["variant"],
|
|
109
|
+
},
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
expect(component.find("[vl-key='drawerWrapper']").attributes("class")).toContain(
|
|
113
|
+
expectedClasses,
|
|
114
|
+
);
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
it("Handle – renders handle when prop is true", () => {
|
|
119
|
+
const handle = [true, false];
|
|
120
|
+
|
|
121
|
+
handle.forEach((value) => {
|
|
122
|
+
const component = mount(UDrawer, {
|
|
123
|
+
props: {
|
|
124
|
+
modelValue,
|
|
125
|
+
handle: value,
|
|
126
|
+
},
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
const handleWrapper = component.find("[vl-key='handleWrapper']");
|
|
130
|
+
const handleElement = component.find("[vl-key='handle']");
|
|
131
|
+
|
|
132
|
+
expect(handleWrapper.exists()).toBe(value);
|
|
133
|
+
expect(handleElement.exists()).toBe(value);
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
it("Inset – applies inset class when prop is true", () => {
|
|
138
|
+
const inset = true;
|
|
139
|
+
const expectedClass = "m-4";
|
|
140
|
+
|
|
141
|
+
const component = mount(UDrawer, {
|
|
142
|
+
props: {
|
|
143
|
+
modelValue,
|
|
144
|
+
inset,
|
|
145
|
+
},
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
const innerWrapper = component.find("[vl-key='innerWrapper']");
|
|
149
|
+
|
|
150
|
+
expect(innerWrapper.attributes("class")).toContain(expectedClass);
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
it("CloseOnOverlay – closes drawer when overlay is clicked", () => {
|
|
154
|
+
const closeOnOverlay = [true, false];
|
|
155
|
+
|
|
156
|
+
closeOnOverlay.forEach(async (value) => {
|
|
157
|
+
const component = mount(UDrawer, {
|
|
158
|
+
props: {
|
|
159
|
+
modelValue,
|
|
160
|
+
closeOnOverlay: value,
|
|
161
|
+
},
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
const innerWrapper = component.find('[vl-key="innerWrapper"]');
|
|
165
|
+
|
|
166
|
+
expect(innerWrapper.exists()).toBe(true);
|
|
167
|
+
|
|
168
|
+
await innerWrapper.trigger("click");
|
|
169
|
+
await sleep(500);
|
|
170
|
+
|
|
171
|
+
const drawer = component.find('[vl-key="drawer"]');
|
|
172
|
+
|
|
173
|
+
expect(drawer.exists()).toBe(!value);
|
|
174
|
+
});
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
it("CloseOnEsc – closes drawer when escape key is pressed", () => {
|
|
178
|
+
const closeOnEsc = [true, false];
|
|
179
|
+
|
|
180
|
+
closeOnEsc.forEach(async (value) => {
|
|
181
|
+
const component = mount(UDrawer, {
|
|
182
|
+
props: {
|
|
183
|
+
modelValue,
|
|
184
|
+
closeOnEsc: value,
|
|
185
|
+
},
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
const wrapper = component.find("[vl-key='wrapper']");
|
|
189
|
+
|
|
190
|
+
await wrapper.trigger("keydown", { key: "Escape" });
|
|
191
|
+
await sleep(500);
|
|
192
|
+
|
|
193
|
+
const drawer = component.find('[vl-key="drawer"]');
|
|
194
|
+
|
|
195
|
+
expect(drawer.exists()).toBe(!value);
|
|
196
|
+
});
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
it("DataTest – applies the correct data-test attribute", () => {
|
|
200
|
+
const dataTest = "drawer-test";
|
|
201
|
+
|
|
202
|
+
const component = mount(UDrawer, {
|
|
203
|
+
props: {
|
|
204
|
+
modelValue,
|
|
205
|
+
dataTest,
|
|
206
|
+
},
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
const drawerWrapper = component.find("[vl-key='wrapper']");
|
|
210
|
+
|
|
211
|
+
expect(drawerWrapper.attributes("data-test")).toBe(dataTest);
|
|
212
|
+
});
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
// Slots tests
|
|
216
|
+
describe("Slots", () => {
|
|
217
|
+
it("Default – renders content in default slot", () => {
|
|
218
|
+
const slotClass = "default-content";
|
|
219
|
+
const slotContent = "Default Content";
|
|
220
|
+
|
|
221
|
+
const component = mount(UDrawer, {
|
|
222
|
+
props: { modelValue: true },
|
|
223
|
+
slots: {
|
|
224
|
+
default: `<div class="${slotClass}">${slotContent}</div>`,
|
|
225
|
+
},
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
expect(component.find(`.${slotClass}`).exists()).toBe(true);
|
|
229
|
+
expect(component.text()).toContain(slotContent);
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
it("Before Title – renders content in slot and shows header", () => {
|
|
233
|
+
const slotClass = "before-title";
|
|
234
|
+
const slotContent = "Before Title";
|
|
235
|
+
|
|
236
|
+
const component = mount(UDrawer, {
|
|
237
|
+
props: {
|
|
238
|
+
modelValue: true,
|
|
239
|
+
title: "Drawer Title",
|
|
240
|
+
},
|
|
241
|
+
slots: {
|
|
242
|
+
"before-title": `<div class="${slotClass}">${slotContent}</div>`,
|
|
243
|
+
},
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
expect(component.find(`.${slotClass}`).exists()).toBe(true);
|
|
247
|
+
expect(component.text()).toContain(slotContent);
|
|
248
|
+
|
|
249
|
+
// Check that header is shown when before-title slot is provided
|
|
250
|
+
const header = component.find("[vl-key='header']");
|
|
251
|
+
|
|
252
|
+
expect(header.exists()).toBe(true);
|
|
253
|
+
expect(header.text()).toContain(slotContent);
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
it("Title – renders custom content in slot and shows header", () => {
|
|
257
|
+
const slotClass = "custom-title";
|
|
258
|
+
const slotContent = "Custom Title";
|
|
259
|
+
|
|
260
|
+
const component = mount(UDrawer, {
|
|
261
|
+
props: {
|
|
262
|
+
modelValue: true,
|
|
263
|
+
title: "Drawer Title",
|
|
264
|
+
},
|
|
265
|
+
slots: {
|
|
266
|
+
title: `<div class="${slotClass}">${slotContent}</div>`,
|
|
267
|
+
},
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
expect(component.find(`.${slotClass}`).exists()).toBe(true);
|
|
271
|
+
expect(component.text()).toContain(slotContent);
|
|
272
|
+
expect(component.findComponent(UHeader).exists()).toBe(false);
|
|
273
|
+
|
|
274
|
+
// Check that header is shown when title slot is provided
|
|
275
|
+
const header = component.find("[vl-key='header']");
|
|
276
|
+
|
|
277
|
+
expect(header.exists()).toBe(true);
|
|
278
|
+
expect(header.text()).toContain(slotContent);
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
it("After Title – renders content in slot and shows header", () => {
|
|
282
|
+
const slotClass = "after-title";
|
|
283
|
+
const slotContent = "After Title";
|
|
284
|
+
|
|
285
|
+
const component = mount(UDrawer, {
|
|
286
|
+
props: {
|
|
287
|
+
modelValue: true,
|
|
288
|
+
title: "Drawer Title",
|
|
289
|
+
},
|
|
290
|
+
slots: {
|
|
291
|
+
"after-title": `<div class="${slotClass}">${slotContent}</div>`,
|
|
292
|
+
},
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
expect(component.find(`.${slotClass}`).exists()).toBe(true);
|
|
296
|
+
expect(component.text()).toContain(slotContent);
|
|
297
|
+
|
|
298
|
+
// Check that header is shown when after-title slot is provided
|
|
299
|
+
const header = component.find("[vl-key='header']");
|
|
300
|
+
|
|
301
|
+
expect(header.exists()).toBe(true);
|
|
302
|
+
expect(header.text()).toContain(slotContent);
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
it("Actions – renders custom content in slot and shows header", () => {
|
|
306
|
+
const slotClass = "actions";
|
|
307
|
+
const slotContent = "Actions";
|
|
308
|
+
|
|
309
|
+
const component = mount(UDrawer, {
|
|
310
|
+
props: {
|
|
311
|
+
modelValue: true,
|
|
312
|
+
title: "Drawer Title",
|
|
313
|
+
},
|
|
314
|
+
slots: {
|
|
315
|
+
actions: `<div class="${slotClass}">${slotContent}</div>`,
|
|
316
|
+
},
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
expect(component.find(`.${slotClass}`).exists()).toBe(true);
|
|
320
|
+
expect(component.text()).toContain(slotContent);
|
|
321
|
+
|
|
322
|
+
// Check that header is shown when actions slot is provided
|
|
323
|
+
const header = component.find("[vl-key='header']");
|
|
324
|
+
|
|
325
|
+
expect(header.exists()).toBe(true);
|
|
326
|
+
expect(header.text()).toContain(slotContent);
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
it("Header – does not show when no title or slots are provided", () => {
|
|
330
|
+
const component = mount(UDrawer, {
|
|
331
|
+
props: { modelValue },
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
const header = component.find("[vl-key='header']");
|
|
335
|
+
|
|
336
|
+
expect(header.exists()).toBe(false);
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
it("Actions – provides close binding to slot", () => {
|
|
340
|
+
const component = mount(UDrawer, {
|
|
341
|
+
props: {
|
|
342
|
+
modelValue: true,
|
|
343
|
+
title: "Drawer Title",
|
|
344
|
+
},
|
|
345
|
+
slots: {
|
|
346
|
+
actions: `
|
|
347
|
+
<template #default="{ close }">
|
|
348
|
+
<button class="custom-close" @click="close">Close</button>
|
|
349
|
+
</template>
|
|
350
|
+
`,
|
|
351
|
+
},
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
const closeButton = component.find(".custom-close");
|
|
355
|
+
|
|
356
|
+
expect(closeButton.exists()).toBe(true);
|
|
357
|
+
|
|
358
|
+
// Click the close button
|
|
359
|
+
closeButton.trigger("click");
|
|
360
|
+
|
|
361
|
+
// Check if the drawer emitted the update:modelValue event with false
|
|
362
|
+
expect(component.emitted("update:modelValue")).toBeTruthy();
|
|
363
|
+
expect(component.emitted("update:modelValue")?.[0]).toEqual([false]);
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
it("Handle – renders custom content in slot", () => {
|
|
367
|
+
const slotClass = "custom-handle";
|
|
368
|
+
const slotContent = "Custom Handle";
|
|
369
|
+
|
|
370
|
+
const component = mount(UDrawer, {
|
|
371
|
+
props: {
|
|
372
|
+
modelValue: true,
|
|
373
|
+
handle: true,
|
|
374
|
+
},
|
|
375
|
+
slots: {
|
|
376
|
+
handle: `<div class="${slotClass}">${slotContent}</div>`,
|
|
377
|
+
},
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
expect(component.find(`.${slotClass}`).exists()).toBe(true);
|
|
381
|
+
expect(component.text()).toContain(slotContent);
|
|
382
|
+
|
|
383
|
+
// Check that default handle element is not rendered when slot is used
|
|
384
|
+
const defaultHandle = component.find("[vl-key='handle']");
|
|
385
|
+
|
|
386
|
+
expect(defaultHandle.exists()).toBe(false);
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
it("Footer Left – renders content in slot and shows footer", () => {
|
|
390
|
+
const slotClass = "footer-left";
|
|
391
|
+
const slotContent = "Footer Left";
|
|
392
|
+
|
|
393
|
+
const component = mount(UDrawer, {
|
|
394
|
+
props: { modelValue: true },
|
|
395
|
+
slots: {
|
|
396
|
+
"footer-left": `<div class="${slotClass}">${slotContent}</div>`,
|
|
397
|
+
},
|
|
398
|
+
});
|
|
399
|
+
|
|
400
|
+
expect(component.find(`.${slotClass}`).exists()).toBe(true);
|
|
401
|
+
expect(component.text()).toContain(slotContent);
|
|
402
|
+
|
|
403
|
+
// Check that footer is shown when footer-left slot is provided
|
|
404
|
+
const footer = component.find("[vl-key='footer']");
|
|
405
|
+
|
|
406
|
+
expect(footer.exists()).toBe(true);
|
|
407
|
+
expect(footer.text()).toContain(slotContent);
|
|
408
|
+
});
|
|
409
|
+
|
|
410
|
+
it("Footer Right – renders content in slot and shows footer", () => {
|
|
411
|
+
const slotClass = "footer-right";
|
|
412
|
+
const slotContent = "Footer Right";
|
|
413
|
+
|
|
414
|
+
const component = mount(UDrawer, {
|
|
415
|
+
props: { modelValue: true },
|
|
416
|
+
slots: {
|
|
417
|
+
"footer-right": `<div class="${slotClass}">${slotContent}</div>`,
|
|
418
|
+
},
|
|
419
|
+
});
|
|
420
|
+
|
|
421
|
+
expect(component.find(`.${slotClass}`).exists()).toBe(true);
|
|
422
|
+
expect(component.text()).toContain(slotContent);
|
|
423
|
+
|
|
424
|
+
// Check that footer is shown when footer-right slot is provided
|
|
425
|
+
const footer = component.find("[vl-key='footer']");
|
|
426
|
+
|
|
427
|
+
expect(footer.exists()).toBe(true);
|
|
428
|
+
expect(footer.text()).toContain(slotContent);
|
|
429
|
+
});
|
|
430
|
+
|
|
431
|
+
it("Footer – does not show when no footer slots are provided", () => {
|
|
432
|
+
const component = mount(UDrawer, {
|
|
433
|
+
props: { modelValue },
|
|
434
|
+
});
|
|
435
|
+
|
|
436
|
+
const footer = component.find("[vl-key='footer']");
|
|
437
|
+
|
|
438
|
+
expect(footer.exists()).toBe(false);
|
|
439
|
+
});
|
|
440
|
+
});
|
|
441
|
+
|
|
442
|
+
// Events tests
|
|
443
|
+
describe("Events", () => {
|
|
444
|
+
it("Update:modelValue – emits event when drawer is closed", async () => {
|
|
445
|
+
const title = "Drawer Title";
|
|
446
|
+
|
|
447
|
+
const component = mount(UDrawer, {
|
|
448
|
+
props: {
|
|
449
|
+
modelValue,
|
|
450
|
+
title,
|
|
451
|
+
},
|
|
452
|
+
slots: {
|
|
453
|
+
actions: `
|
|
454
|
+
<template #default="{ close }">
|
|
455
|
+
<button class="close-btn" @click="close">Close</button>
|
|
456
|
+
</template>
|
|
457
|
+
`,
|
|
458
|
+
},
|
|
459
|
+
});
|
|
460
|
+
|
|
461
|
+
const closeButton = component.find(".close-btn");
|
|
462
|
+
|
|
463
|
+
await closeButton.trigger("click");
|
|
464
|
+
|
|
465
|
+
expect(component.emitted("update:modelValue")).toBeTruthy();
|
|
466
|
+
expect(component.emitted("update:modelValue")?.[0]).toEqual([false]);
|
|
467
|
+
});
|
|
468
|
+
|
|
469
|
+
it("Close – emits event when drawer is closed", async () => {
|
|
470
|
+
const title = "Drawer Title";
|
|
471
|
+
|
|
472
|
+
const component = mount(UDrawer, {
|
|
473
|
+
props: {
|
|
474
|
+
modelValue,
|
|
475
|
+
title,
|
|
476
|
+
},
|
|
477
|
+
slots: {
|
|
478
|
+
actions: `
|
|
479
|
+
<template #default="{ close }">
|
|
480
|
+
<button class="close-btn" @click="close">Close</button>
|
|
481
|
+
</template>
|
|
482
|
+
`,
|
|
483
|
+
},
|
|
484
|
+
});
|
|
485
|
+
|
|
486
|
+
const closeButton = component.find(".close-btn");
|
|
487
|
+
|
|
488
|
+
await closeButton.trigger("click");
|
|
489
|
+
|
|
490
|
+
expect(component.emitted("close")).toBeTruthy();
|
|
491
|
+
});
|
|
492
|
+
|
|
493
|
+
it("CloseOnOverlay – emits events when overlay is clicked based on prop", () => {
|
|
494
|
+
const closeOnOverlay = [true, false];
|
|
495
|
+
|
|
496
|
+
closeOnOverlay.forEach(async (value) => {
|
|
497
|
+
const component = mount(UDrawer, {
|
|
498
|
+
props: {
|
|
499
|
+
modelValue,
|
|
500
|
+
closeOnOverlay: value,
|
|
501
|
+
},
|
|
502
|
+
});
|
|
503
|
+
|
|
504
|
+
const innerWrapper = component.find("[vl-key='innerWrapper']");
|
|
505
|
+
|
|
506
|
+
await innerWrapper.trigger("click");
|
|
507
|
+
|
|
508
|
+
if (value) {
|
|
509
|
+
expect(component.emitted("update:modelValue")).toBeTruthy();
|
|
510
|
+
expect(component.emitted("update:modelValue")?.[0]).toEqual([false]);
|
|
511
|
+
expect(component.emitted("close")).toBeTruthy();
|
|
512
|
+
} else {
|
|
513
|
+
expect(component.emitted("update:modelValue")).toBeFalsy();
|
|
514
|
+
expect(component.emitted("close")).toBeFalsy();
|
|
515
|
+
}
|
|
516
|
+
});
|
|
517
|
+
});
|
|
518
|
+
|
|
519
|
+
it("CloseOnEsc – emits events when escape key is pressed based on prop", () => {
|
|
520
|
+
const closeOnEsc = [true, false];
|
|
521
|
+
|
|
522
|
+
closeOnEsc.forEach(async (value) => {
|
|
523
|
+
const component = mount(UDrawer, {
|
|
524
|
+
props: {
|
|
525
|
+
modelValue,
|
|
526
|
+
closeOnEsc: value,
|
|
527
|
+
},
|
|
528
|
+
});
|
|
529
|
+
|
|
530
|
+
const wrapper = component.find("[vl-key='wrapper']");
|
|
531
|
+
|
|
532
|
+
await wrapper.trigger("keydown", { key: "Escape" });
|
|
533
|
+
|
|
534
|
+
if (value) {
|
|
535
|
+
expect(component.emitted("update:modelValue")).toBeTruthy();
|
|
536
|
+
expect(component.emitted("update:modelValue")?.[0]).toEqual([false]);
|
|
537
|
+
expect(component.emitted("close")).toBeTruthy();
|
|
538
|
+
} else {
|
|
539
|
+
expect(component.emitted("update:modelValue")).toBeFalsy();
|
|
540
|
+
expect(component.emitted("close")).toBeFalsy();
|
|
541
|
+
}
|
|
542
|
+
});
|
|
543
|
+
});
|
|
544
|
+
});
|
|
545
|
+
|
|
546
|
+
// Drag functionality tests
|
|
547
|
+
describe("Drag Functionality", () => {
|
|
548
|
+
it("Cursor – applies drag cursor classes when drawer is draggable", () => {
|
|
549
|
+
const component = mount(UDrawer, {
|
|
550
|
+
props: {
|
|
551
|
+
modelValue: true,
|
|
552
|
+
},
|
|
553
|
+
});
|
|
554
|
+
|
|
555
|
+
const drawer = component.find("[vl-key='drawerWrapper']");
|
|
556
|
+
|
|
557
|
+
expect(drawer.attributes("class")).toContain("cursor-grab");
|
|
558
|
+
});
|
|
559
|
+
|
|
560
|
+
it("Mouse Drag – handles drag start", async () => {
|
|
561
|
+
const component = mount(UDrawer, {
|
|
562
|
+
props: {
|
|
563
|
+
modelValue: true,
|
|
564
|
+
},
|
|
565
|
+
});
|
|
566
|
+
|
|
567
|
+
const drawer = component.find("[vl-key='drawerWrapper']");
|
|
568
|
+
|
|
569
|
+
// Mock getBoundingClientRect
|
|
570
|
+
const mockRect = {
|
|
571
|
+
width: 300,
|
|
572
|
+
height: 400,
|
|
573
|
+
top: 0,
|
|
574
|
+
left: 0,
|
|
575
|
+
right: 300,
|
|
576
|
+
bottom: 400,
|
|
577
|
+
};
|
|
578
|
+
|
|
579
|
+
vi.spyOn(drawer.element, "getBoundingClientRect").mockReturnValue(mockRect as DOMRect);
|
|
580
|
+
|
|
581
|
+
await drawer.trigger("mousedown", {
|
|
582
|
+
clientX: 100,
|
|
583
|
+
clientY: 100,
|
|
584
|
+
});
|
|
585
|
+
|
|
586
|
+
// Check if drag state is initialized (drag should not start until minimum distance)
|
|
587
|
+
expect(drawer.attributes("class")).toContain("cursor-grab");
|
|
588
|
+
});
|
|
589
|
+
|
|
590
|
+
it("Touch Drag – handles drag start", async () => {
|
|
591
|
+
const component = mount(UDrawer, {
|
|
592
|
+
props: {
|
|
593
|
+
modelValue: true,
|
|
594
|
+
},
|
|
595
|
+
});
|
|
596
|
+
|
|
597
|
+
const drawer = component.find("[vl-key='drawerWrapper']");
|
|
598
|
+
|
|
599
|
+
// Mock getBoundingClientRect
|
|
600
|
+
const mockRect = {
|
|
601
|
+
width: 300,
|
|
602
|
+
height: 400,
|
|
603
|
+
top: 0,
|
|
604
|
+
left: 0,
|
|
605
|
+
right: 300,
|
|
606
|
+
bottom: 400,
|
|
607
|
+
};
|
|
608
|
+
|
|
609
|
+
vi.spyOn(drawer.element, "getBoundingClientRect").mockReturnValue(mockRect as DOMRect);
|
|
610
|
+
|
|
611
|
+
await drawer.trigger("touchstart", {
|
|
612
|
+
touches: [{ clientX: 100, clientY: 100 }],
|
|
613
|
+
});
|
|
614
|
+
|
|
615
|
+
// Check if drag state is initialized (drag should not start until minimum distance)
|
|
616
|
+
expect(drawer.attributes("class")).toContain("cursor-grab");
|
|
617
|
+
});
|
|
618
|
+
|
|
619
|
+
it("Transform – applies drag transform styles during drag", async () => {
|
|
620
|
+
const component = mount(UDrawer, {
|
|
621
|
+
props: {
|
|
622
|
+
modelValue: true,
|
|
623
|
+
position: "left",
|
|
624
|
+
},
|
|
625
|
+
});
|
|
626
|
+
|
|
627
|
+
const drawer = component.find("[vl-key='drawerWrapper']");
|
|
628
|
+
|
|
629
|
+
// Mock getBoundingClientRect
|
|
630
|
+
const mockRect = {
|
|
631
|
+
width: 300,
|
|
632
|
+
height: 400,
|
|
633
|
+
top: 0,
|
|
634
|
+
left: 0,
|
|
635
|
+
right: 300,
|
|
636
|
+
bottom: 400,
|
|
637
|
+
};
|
|
638
|
+
|
|
639
|
+
vi.spyOn(drawer.element, "getBoundingClientRect").mockReturnValue(mockRect as DOMRect);
|
|
640
|
+
|
|
641
|
+
// Start drag
|
|
642
|
+
await drawer.trigger("mousedown", {
|
|
643
|
+
clientX: 100,
|
|
644
|
+
clientY: 100,
|
|
645
|
+
});
|
|
646
|
+
|
|
647
|
+
// Simulate drag movement
|
|
648
|
+
const mouseMoveEvent = new MouseEvent("mousemove", {
|
|
649
|
+
clientX: 150, // 50px movement
|
|
650
|
+
clientY: 100,
|
|
651
|
+
});
|
|
652
|
+
|
|
653
|
+
document.dispatchEvent(mouseMoveEvent);
|
|
654
|
+
|
|
655
|
+
// Check if transform is applied
|
|
656
|
+
const drawerElement = component.find("[vl-key='drawerWrapper']");
|
|
657
|
+
const style = drawerElement.attributes("style");
|
|
658
|
+
|
|
659
|
+
// Should contain transform when dragging (if style exists)
|
|
660
|
+
if (style) {
|
|
661
|
+
expect(style).toContain("transform");
|
|
662
|
+
} else {
|
|
663
|
+
// If no style attribute, that's also valid (transform might be applied via CSS classes)
|
|
664
|
+
expect(drawerElement.exists()).toBe(true);
|
|
665
|
+
}
|
|
666
|
+
});
|
|
667
|
+
});
|
|
668
|
+
|
|
669
|
+
// Exposed refs tests
|
|
670
|
+
describe("Exposed refs", () => {
|
|
671
|
+
it("WrapperRef – exposes wrapper element ref", () => {
|
|
672
|
+
const component = mount(UDrawer, {
|
|
673
|
+
props: { modelValue },
|
|
674
|
+
});
|
|
675
|
+
|
|
676
|
+
expect(component.vm.wrapperRef).toBeDefined();
|
|
677
|
+
expect(component.vm.wrapperRef instanceof HTMLDivElement).toBe(true);
|
|
678
|
+
});
|
|
679
|
+
});
|
|
680
|
+
});
|