@fiscozen/checkbox 0.2.0 → 1.0.0

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.
Files changed (42) hide show
  1. package/dist/checkbox.js +2376 -0
  2. package/dist/checkbox.umd.cjs +13 -0
  3. package/dist/index.d.ts +1 -0
  4. package/dist/src/FzCheckbox.vue.d.ts +102 -0
  5. package/dist/src/FzCheckboxGroup.vue.d.ts +72 -0
  6. package/dist/src/__tests__/FzCheckbox.spec.d.ts +1 -0
  7. package/dist/src/__tests__/FzCheckboxGroup.spec.d.ts +1 -0
  8. package/dist/src/common.d.ts +23 -0
  9. package/dist/src/components/ErrorAlert.vue.d.ts +34 -0
  10. package/dist/src/components/FzCheckboxGroupOption.vue.d.ts +86 -0
  11. package/dist/src/index.d.ts +4 -0
  12. package/dist/src/types.d.ts +192 -0
  13. package/dist/src/utils.d.ts +24 -0
  14. package/dist/style.css +1 -0
  15. package/package.json +9 -13
  16. package/src/__tests__/FzCheckbox.spec.ts +748 -0
  17. package/src/__tests__/FzCheckboxGroup.spec.ts +764 -0
  18. package/src/__tests__/__snapshots__/FzCheckbox.spec.ts.snap +427 -0
  19. package/src/__tests__/__snapshots__/FzCheckboxGroup.spec.ts.snap +805 -0
  20. package/src/components/ErrorAlert.vue +1 -1
  21. package/tsconfig.tsbuildinfo +1 -0
  22. package/vitest.config.ts +9 -1
  23. package/coverage/base.css +0 -224
  24. package/coverage/block-navigation.js +0 -87
  25. package/coverage/clover.xml +0 -1031
  26. package/coverage/coverage-final.json +0 -7
  27. package/coverage/favicon.png +0 -0
  28. package/coverage/index.html +0 -131
  29. package/coverage/prettify.css +0 -1
  30. package/coverage/prettify.js +0 -2
  31. package/coverage/sort-arrow-sprite.png +0 -0
  32. package/coverage/sorter.js +0 -196
  33. package/coverage/src/FzCheckbox.vue.html +0 -1489
  34. package/coverage/src/FzCheckboxGroup.vue.html +0 -682
  35. package/coverage/src/common.ts.html +0 -157
  36. package/coverage/src/components/ErrorAlert.vue.html +0 -268
  37. package/coverage/src/components/FzCheckboxGroupOption.vue.html +0 -652
  38. package/coverage/src/components/index.html +0 -131
  39. package/coverage/src/index.html +0 -161
  40. package/coverage/src/utils.ts.html +0 -265
  41. package/src/__test__/FzCheckbox.test.ts +0 -206
  42. package/src/__test__/FzCheckboxGroup.test.ts +0 -263
@@ -0,0 +1,764 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { mount } from "@vue/test-utils";
3
+ import FzCheckboxGroup from "../FzCheckboxGroup.vue";
4
+ import FzCheckbox from "../FzCheckbox.vue";
5
+
6
+ describe("FzCheckboxGroup", () => {
7
+ // ============================================
8
+ // RENDERING TESTS
9
+ // ============================================
10
+ describe("Rendering", () => {
11
+ it("should render with default props", async () => {
12
+ const wrapper = mount(FzCheckboxGroup, {
13
+ props: {
14
+ label: "Test Checkbox Group",
15
+ modelValue: [],
16
+ options: [
17
+ { label: "Option 1", value: "option1" },
18
+ { label: "Option 2", value: "option2" },
19
+ ],
20
+ },
21
+ });
22
+
23
+ await wrapper.vm.$nextTick();
24
+ expect(wrapper.exists()).toBe(true);
25
+ expect(wrapper.html()).toContain("Test Checkbox Group");
26
+ expect(wrapper.findAllComponents(FzCheckbox).length).toBe(2);
27
+ });
28
+
29
+ it("should render label", async () => {
30
+ const wrapper = mount(FzCheckboxGroup, {
31
+ props: {
32
+ label: "Custom Label",
33
+ modelValue: [],
34
+ options: [
35
+ { label: "Option 1", value: "option1" },
36
+ ],
37
+ },
38
+ });
39
+
40
+ await wrapper.vm.$nextTick();
41
+ expect(wrapper.text()).toContain("Custom Label");
42
+ });
43
+
44
+ it("should render all checkbox options", async () => {
45
+ const wrapper = mount(FzCheckboxGroup, {
46
+ props: {
47
+ label: "Test Checkbox Group",
48
+ modelValue: [],
49
+ options: [
50
+ { label: "Option 1", value: "option1" },
51
+ { label: "Option 2", value: "option2" },
52
+ { label: "Option 3", value: "option3" },
53
+ ],
54
+ },
55
+ });
56
+
57
+ await wrapper.vm.$nextTick();
58
+ expect(wrapper.findAllComponents(FzCheckbox).length).toBe(3);
59
+ });
60
+
61
+ it("should render hierarchical checkboxes", async () => {
62
+ const wrapper = mount(FzCheckboxGroup, {
63
+ props: {
64
+ label: "Test Checkbox Group",
65
+ modelValue: [],
66
+ options: [
67
+ {
68
+ label: "Parent Option",
69
+ value: "parent",
70
+ children: [
71
+ { label: "Child 1", value: "child1" },
72
+ { label: "Child 2", value: "child2" },
73
+ ],
74
+ },
75
+ ],
76
+ },
77
+ });
78
+
79
+ await wrapper.vm.$nextTick();
80
+ const allCheckboxes = wrapper.findAllComponents(FzCheckbox);
81
+ // Should have parent + 2 children = 3 checkboxes
82
+ expect(allCheckboxes.length).toBe(3);
83
+ });
84
+ });
85
+
86
+ // ============================================
87
+ // PROPS TESTS
88
+ // ============================================
89
+ describe("Props", () => {
90
+ describe("label prop", () => {
91
+ it("should display label text", async () => {
92
+ const wrapper = mount(FzCheckboxGroup, {
93
+ props: {
94
+ label: "Custom Label",
95
+ modelValue: [],
96
+ options: [
97
+ { label: "Option 1", value: "option1" },
98
+ ],
99
+ },
100
+ });
101
+
102
+ await wrapper.vm.$nextTick();
103
+ expect(wrapper.text()).toContain("Custom Label");
104
+ });
105
+ });
106
+
107
+ describe("options prop", () => {
108
+ it("should render checkboxes from options array", async () => {
109
+ const wrapper = mount(FzCheckboxGroup, {
110
+ props: {
111
+ label: "Test Checkbox Group",
112
+ modelValue: [],
113
+ options: [
114
+ { label: "Option 1", value: "option1" },
115
+ { label: "Option 2", value: "option2" },
116
+ ],
117
+ },
118
+ });
119
+
120
+ await wrapper.vm.$nextTick();
121
+ expect(wrapper.findAllComponents(FzCheckbox).length).toBe(2);
122
+ });
123
+
124
+ it("should handle empty options array", async () => {
125
+ const wrapper = mount(FzCheckboxGroup, {
126
+ props: {
127
+ label: "Test Checkbox Group",
128
+ modelValue: [],
129
+ options: [],
130
+ },
131
+ });
132
+
133
+ await wrapper.vm.$nextTick();
134
+ expect(wrapper.findAllComponents(FzCheckbox).length).toBe(0);
135
+ });
136
+ });
137
+
138
+ describe("disabled prop", () => {
139
+ it("should propagate disabled to all checkboxes", async () => {
140
+ const wrapper = mount(FzCheckboxGroup, {
141
+ props: {
142
+ label: "Test Checkbox Group",
143
+ modelValue: [],
144
+ options: [
145
+ { label: "Option 1", value: "option1" },
146
+ { label: "Option 2", value: "option2" },
147
+ ],
148
+ disabled: true,
149
+ },
150
+ });
151
+
152
+ await wrapper.vm.$nextTick();
153
+ const checkboxes = wrapper.findAllComponents(FzCheckbox);
154
+ checkboxes.forEach((checkbox) => {
155
+ expect(checkbox.props("disabled")).toBe(true);
156
+ });
157
+ });
158
+ });
159
+
160
+ describe("error prop", () => {
161
+ it("should propagate error to all checkboxes", async () => {
162
+ const wrapper = mount(FzCheckboxGroup, {
163
+ props: {
164
+ label: "Test Checkbox Group",
165
+ modelValue: [],
166
+ options: [
167
+ { label: "Option 1", value: "option1" },
168
+ { label: "Option 2", value: "option2" },
169
+ ],
170
+ error: true,
171
+ },
172
+ });
173
+
174
+ await wrapper.vm.$nextTick();
175
+ const checkboxes = wrapper.findAllComponents(FzCheckbox);
176
+ checkboxes.forEach((checkbox) => {
177
+ expect(checkbox.props("error")).toBe(true);
178
+ });
179
+ });
180
+ });
181
+
182
+ describe("emphasis prop", () => {
183
+ it("should propagate emphasis to all checkboxes", async () => {
184
+ const wrapper = mount(FzCheckboxGroup, {
185
+ props: {
186
+ label: "Test Checkbox Group",
187
+ modelValue: [],
188
+ options: [
189
+ { label: "Option 1", value: "option1" },
190
+ { label: "Option 2", value: "option2" },
191
+ ],
192
+ emphasis: true,
193
+ },
194
+ });
195
+
196
+ await wrapper.vm.$nextTick();
197
+ const checkboxes = wrapper.findAllComponents(FzCheckbox);
198
+ checkboxes.forEach((checkbox) => {
199
+ expect(checkbox.props("emphasis")).toBe(true);
200
+ });
201
+ });
202
+ });
203
+
204
+ describe("required prop", () => {
205
+ it("should display required indicator when true", async () => {
206
+ const wrapper = mount(FzCheckboxGroup, {
207
+ props: {
208
+ label: "Test Checkbox Group",
209
+ modelValue: [],
210
+ options: [
211
+ { label: "Option 1", value: "option1" },
212
+ ],
213
+ required: true,
214
+ },
215
+ });
216
+
217
+ await wrapper.vm.$nextTick();
218
+ expect(wrapper.text()).toContain("*");
219
+ });
220
+ });
221
+
222
+ describe("horizontal prop", () => {
223
+ it("should apply horizontal layout classes when true", async () => {
224
+ const wrapper = mount(FzCheckboxGroup, {
225
+ props: {
226
+ label: "Test Checkbox Group",
227
+ modelValue: [],
228
+ options: [
229
+ { label: "Option 1", value: "option1" },
230
+ ],
231
+ horizontal: true,
232
+ },
233
+ });
234
+
235
+ await wrapper.vm.$nextTick();
236
+ const container = wrapper.find("[role='group']");
237
+ expect(container.classes()).toContain("flex-row");
238
+ expect(container.classes()).toContain("gap-16");
239
+ });
240
+
241
+ it("should apply vertical layout classes when false", async () => {
242
+ const wrapper = mount(FzCheckboxGroup, {
243
+ props: {
244
+ label: "Test Checkbox Group",
245
+ modelValue: [],
246
+ options: [
247
+ { label: "Option 1", value: "option1" },
248
+ ],
249
+ horizontal: false,
250
+ },
251
+ });
252
+
253
+ await wrapper.vm.$nextTick();
254
+ const container = wrapper.find("[role='group']");
255
+ expect(container.classes()).toContain("flex-col");
256
+ expect(container.classes()).toContain("gap-8");
257
+ });
258
+ });
259
+ });
260
+
261
+ // ============================================
262
+ // EVENTS TESTS
263
+ // ============================================
264
+ describe("Events", () => {
265
+ it("should update modelValue when checkbox is selected", async () => {
266
+ const wrapper = mount(FzCheckboxGroup, {
267
+ props: {
268
+ label: "Test Checkbox Group",
269
+ modelValue: [],
270
+ options: [
271
+ { label: "Option 1", value: "option1" },
272
+ { label: "Option 2", value: "option2" },
273
+ ],
274
+ },
275
+ });
276
+
277
+ await wrapper.vm.$nextTick();
278
+ const checkboxes = wrapper.findAllComponents(FzCheckbox);
279
+ await checkboxes[0].find("input").setValue(true);
280
+
281
+ expect(wrapper.emitted("update:modelValue")).toBeDefined();
282
+ });
283
+
284
+ it("should handle multiple selections", async () => {
285
+ const wrapper = mount(FzCheckboxGroup, {
286
+ props: {
287
+ label: "Test Checkbox Group",
288
+ modelValue: [],
289
+ options: [
290
+ { label: "Option 1", value: "option1" },
291
+ { label: "Option 2", value: "option2" },
292
+ ],
293
+ },
294
+ });
295
+
296
+ await wrapper.vm.$nextTick();
297
+ const checkboxes = wrapper.findAllComponents(FzCheckbox);
298
+ await checkboxes[0].find("input").setValue(true);
299
+ await checkboxes[1].find("input").setValue(true);
300
+
301
+ // Should emit multiple update:modelValue events
302
+ const updateEvents = wrapper.emitted("update:modelValue");
303
+ expect(updateEvents).toBeDefined();
304
+ expect(updateEvents!.length).toBeGreaterThan(0);
305
+ });
306
+ });
307
+
308
+ // ============================================
309
+ // ACCESSIBILITY TESTS
310
+ // ============================================
311
+ describe("Accessibility", () => {
312
+ describe("ARIA attributes", () => {
313
+ it("should have role='group' on container", async () => {
314
+ const wrapper = mount(FzCheckboxGroup, {
315
+ props: {
316
+ label: "Test Checkbox Group",
317
+ modelValue: [],
318
+ options: [
319
+ { label: "Option 1", value: "option1" },
320
+ { label: "Option 2", value: "option2" },
321
+ ],
322
+ },
323
+ });
324
+ await wrapper.vm.$nextTick();
325
+ expect(wrapper.find("[role='group']").exists()).toBe(true);
326
+ });
327
+
328
+ it("should have aria-labelledby linking to label", async () => {
329
+ const wrapper = mount(FzCheckboxGroup, {
330
+ props: {
331
+ label: "Test Checkbox Group",
332
+ modelValue: [],
333
+ options: [
334
+ { label: "Option 1", value: "option1" },
335
+ ],
336
+ },
337
+ });
338
+ await wrapper.vm.$nextTick();
339
+ const groupId = wrapper.find("[role='group']").attributes("id");
340
+ const labelId = groupId + "-label";
341
+ expect(wrapper.find("[role='group']").attributes("aria-labelledby")).toBe(
342
+ labelId,
343
+ );
344
+ expect(wrapper.find(`#${labelId}`).exists()).toBe(true);
345
+ });
346
+
347
+ it("should have aria-describedby when help text is present", async () => {
348
+ const wrapper = mount(FzCheckboxGroup, {
349
+ props: {
350
+ label: "Test Checkbox Group",
351
+ modelValue: [],
352
+ options: [
353
+ { label: "Option 1", value: "option1" },
354
+ ],
355
+ },
356
+ slots: {
357
+ help: "This is help text",
358
+ },
359
+ });
360
+ await wrapper.vm.$nextTick();
361
+ const groupId = wrapper.find("[role='group']").attributes("id");
362
+ const helpId = groupId + "-help";
363
+ expect(wrapper.find("[role='group']").attributes("aria-describedby")).toBe(
364
+ helpId,
365
+ );
366
+ expect(wrapper.find(`#${helpId}`).exists()).toBe(true);
367
+ expect(wrapper.find(`#${helpId}`).text()).toBe("This is help text");
368
+ });
369
+
370
+ it("should have aria-describedby when error is present", async () => {
371
+ const wrapper = mount(FzCheckboxGroup, {
372
+ props: {
373
+ label: "Test Checkbox Group",
374
+ modelValue: [],
375
+ options: [
376
+ { label: "Option 1", value: "option1" },
377
+ ],
378
+ error: true,
379
+ },
380
+ slots: {
381
+ error: "Test error message",
382
+ },
383
+ });
384
+ await wrapper.vm.$nextTick();
385
+ const groupId = wrapper.find("[role='group']").attributes("id");
386
+ const errorId = groupId + "-error";
387
+ expect(wrapper.find("[role='group']").attributes("aria-describedby")).toBe(
388
+ errorId,
389
+ );
390
+ expect(wrapper.find(`#${errorId}`).exists()).toBe(true);
391
+ });
392
+
393
+ it("should have aria-describedby with both help and error", async () => {
394
+ const wrapper = mount(FzCheckboxGroup, {
395
+ props: {
396
+ label: "Test Checkbox Group",
397
+ modelValue: [],
398
+ options: [
399
+ { label: "Option 1", value: "option1" },
400
+ ],
401
+ error: true,
402
+ },
403
+ slots: {
404
+ help: "This is help text",
405
+ error: "This is an error",
406
+ },
407
+ });
408
+ await wrapper.vm.$nextTick();
409
+ const groupId = wrapper.find("[role='group']").attributes("id");
410
+ const helpId = groupId + "-help";
411
+ const errorId = groupId + "-error";
412
+ const describedby = wrapper
413
+ .find("[role='group']")
414
+ .attributes("aria-describedby");
415
+
416
+ // Should contain both IDs separated by space
417
+ expect(describedby).toContain(helpId);
418
+ expect(describedby).toContain(errorId);
419
+ expect(describedby).toBe(`${helpId} ${errorId}`);
420
+ });
421
+
422
+ it("should have aria-invalid when error is present", async () => {
423
+ const wrapper = mount(FzCheckboxGroup, {
424
+ props: {
425
+ label: "Test Checkbox Group",
426
+ modelValue: [],
427
+ options: [
428
+ { label: "Option 1", value: "option1" },
429
+ ],
430
+ error: true,
431
+ },
432
+ });
433
+ await wrapper.vm.$nextTick();
434
+ const group = wrapper.find("[role='group']");
435
+ expect(group.attributes("aria-invalid")).toBe("true");
436
+ });
437
+
438
+ it("should have aria-required when required", async () => {
439
+ const wrapper = mount(FzCheckboxGroup, {
440
+ props: {
441
+ label: "Test Checkbox Group",
442
+ modelValue: [],
443
+ options: [
444
+ { label: "Option 1", value: "option1" },
445
+ ],
446
+ required: true,
447
+ },
448
+ });
449
+ await wrapper.vm.$nextTick();
450
+ const group = wrapper.find("[role='group']");
451
+ expect(group.attributes("aria-required")).toBe("true");
452
+ });
453
+
454
+ it("should not have aria-describedby when no error slot provided", async () => {
455
+ const wrapper = mount(FzCheckboxGroup, {
456
+ props: {
457
+ label: "Test Checkbox Group",
458
+ modelValue: [],
459
+ options: [
460
+ { label: "Option 1", value: "option1" },
461
+ ],
462
+ error: true,
463
+ },
464
+ });
465
+ await wrapper.vm.$nextTick();
466
+ const group = wrapper.find("[role='group']");
467
+ expect(group.attributes("aria-invalid")).toBe("true");
468
+ expect(group.attributes("aria-describedby")).toBeUndefined();
469
+ expect(wrapper.find("[role='alert']").exists()).toBe(false);
470
+ });
471
+ });
472
+
473
+ describe("Semantic HTML structure", () => {
474
+ it("should have proper label structure", async () => {
475
+ const wrapper = mount(FzCheckboxGroup, {
476
+ props: {
477
+ label: "Test Checkbox Group",
478
+ modelValue: [],
479
+ options: [
480
+ { label: "Option 1", value: "option1" },
481
+ ],
482
+ },
483
+ });
484
+ await wrapper.vm.$nextTick();
485
+ const label = wrapper.find("label");
486
+ expect(label.exists()).toBe(true);
487
+ expect(label.text()).toContain("Test Checkbox Group");
488
+ });
489
+
490
+ it("should have role='alert' on error message", async () => {
491
+ const wrapper = mount(FzCheckboxGroup, {
492
+ props: {
493
+ label: "Test Checkbox Group",
494
+ modelValue: [],
495
+ options: [
496
+ { label: "Option 1", value: "option1" },
497
+ ],
498
+ error: true,
499
+ },
500
+ slots: {
501
+ error: "Test error message",
502
+ },
503
+ });
504
+ await wrapper.vm.$nextTick();
505
+ expect(wrapper.find("[role='alert']").exists()).toBe(true);
506
+ });
507
+ });
508
+ });
509
+
510
+ // ============================================
511
+ // CSS CLASSES TESTS
512
+ // ============================================
513
+ describe("CSS Classes", () => {
514
+ it("should apply static base classes to container", async () => {
515
+ const wrapper = mount(FzCheckboxGroup, {
516
+ props: {
517
+ label: "Test Checkbox Group",
518
+ modelValue: [],
519
+ options: [
520
+ { label: "Option 1", value: "option1" },
521
+ ],
522
+ },
523
+ });
524
+ await wrapper.vm.$nextTick();
525
+ const container = wrapper.find("[role='group']");
526
+ expect(container.classes()).toContain("flex");
527
+ expect(container.classes()).toContain("items-start");
528
+ });
529
+
530
+ it("should apply horizontal layout classes when horizontal is true", async () => {
531
+ const wrapper = mount(FzCheckboxGroup, {
532
+ props: {
533
+ label: "Test Checkbox Group",
534
+ modelValue: [],
535
+ options: [
536
+ { label: "Option 1", value: "option1" },
537
+ ],
538
+ horizontal: true,
539
+ },
540
+ });
541
+ await wrapper.vm.$nextTick();
542
+ const container = wrapper.find("[role='group']");
543
+ expect(container.classes()).toContain("flex-row");
544
+ expect(container.classes()).toContain("gap-16");
545
+ });
546
+
547
+ it("should apply vertical layout classes when horizontal is false", async () => {
548
+ const wrapper = mount(FzCheckboxGroup, {
549
+ props: {
550
+ label: "Test Checkbox Group",
551
+ modelValue: [],
552
+ options: [
553
+ { label: "Option 1", value: "option1" },
554
+ ],
555
+ horizontal: false,
556
+ },
557
+ });
558
+ await wrapper.vm.$nextTick();
559
+ const container = wrapper.find("[role='group']");
560
+ expect(container.classes()).toContain("flex-col");
561
+ expect(container.classes()).toContain("gap-8");
562
+ });
563
+
564
+ it("should apply disabled classes to label when disabled", async () => {
565
+ const wrapper = mount(FzCheckboxGroup, {
566
+ props: {
567
+ label: "Test Checkbox Group",
568
+ modelValue: [],
569
+ options: [
570
+ { label: "Option 1", value: "option1" },
571
+ ],
572
+ disabled: true,
573
+ },
574
+ });
575
+ await wrapper.vm.$nextTick();
576
+ const label = wrapper.find("label");
577
+ expect(label.classes()).toContain("text-grey-400");
578
+ });
579
+ });
580
+
581
+ // ============================================
582
+ // EDGE CASES
583
+ // ============================================
584
+ describe("Edge Cases", () => {
585
+ it("should handle empty options array", async () => {
586
+ const wrapper = mount(FzCheckboxGroup, {
587
+ props: {
588
+ label: "Test Checkbox Group",
589
+ modelValue: [],
590
+ options: [],
591
+ },
592
+ });
593
+
594
+ await wrapper.vm.$nextTick();
595
+ expect(wrapper.findAllComponents(FzCheckbox).length).toBe(0);
596
+ });
597
+
598
+ it("should propagate error prop to child checkboxes in hierarchical structure", async () => {
599
+ const wrapper = mount(FzCheckboxGroup, {
600
+ props: {
601
+ label: "Test Checkbox Group",
602
+ modelValue: [],
603
+ options: [
604
+ {
605
+ label: "Parent Option",
606
+ value: "parent",
607
+ children: [
608
+ { label: "Child 1", value: "child1" },
609
+ { label: "Child 2", value: "child2" },
610
+ ],
611
+ },
612
+ ],
613
+ error: true,
614
+ },
615
+ slots: {
616
+ error: "Test error message",
617
+ },
618
+ });
619
+
620
+ await wrapper.vm.$nextTick();
621
+ const allCheckboxes = wrapper.findAllComponents(FzCheckbox);
622
+
623
+ // Should have parent + 2 children = 3 checkboxes
624
+ expect(allCheckboxes.length).toBe(3);
625
+
626
+ // All checkboxes should have error prop set to true
627
+ allCheckboxes.forEach((checkbox) => {
628
+ expect(checkbox.props("error")).toBe(true);
629
+ });
630
+ });
631
+
632
+ it("should handle options without value prop", async () => {
633
+ const wrapper = mount(FzCheckboxGroup, {
634
+ props: {
635
+ label: "Test Checkbox Group",
636
+ modelValue: [],
637
+ options: [
638
+ { label: "Option 1" },
639
+ { label: "Option 2" },
640
+ ],
641
+ },
642
+ });
643
+
644
+ await wrapper.vm.$nextTick();
645
+ expect(wrapper.findAllComponents(FzCheckbox).length).toBe(2);
646
+ });
647
+ });
648
+
649
+ // ============================================
650
+ // SNAPSHOTS
651
+ // ============================================
652
+ describe("Snapshots", () => {
653
+ it("should match snapshot - default state", () => {
654
+ const wrapper = mount(FzCheckboxGroup, {
655
+ props: {
656
+ label: "Test Checkbox Group",
657
+ modelValue: [],
658
+ options: [
659
+ { label: "Option 1", value: "option1" },
660
+ { label: "Option 2", value: "option2" },
661
+ ],
662
+ },
663
+ });
664
+ expect(wrapper.html()).toMatchSnapshot();
665
+ });
666
+
667
+ it("should match snapshot - with error", () => {
668
+ const wrapper = mount(FzCheckboxGroup, {
669
+ props: {
670
+ label: "Test Checkbox Group",
671
+ modelValue: [],
672
+ options: [
673
+ { label: "Option 1", value: "option1" },
674
+ ],
675
+ error: true,
676
+ },
677
+ slots: {
678
+ error: "Test error message",
679
+ },
680
+ });
681
+ expect(wrapper.html()).toMatchSnapshot();
682
+ });
683
+
684
+ it("should match snapshot - disabled", () => {
685
+ const wrapper = mount(FzCheckboxGroup, {
686
+ props: {
687
+ label: "Test Checkbox Group",
688
+ modelValue: [],
689
+ options: [
690
+ { label: "Option 1", value: "option1" },
691
+ ],
692
+ disabled: true,
693
+ },
694
+ });
695
+ expect(wrapper.html()).toMatchSnapshot();
696
+ });
697
+
698
+ it("should match snapshot - horizontal layout", () => {
699
+ const wrapper = mount(FzCheckboxGroup, {
700
+ props: {
701
+ label: "Test Checkbox Group",
702
+ modelValue: [],
703
+ options: [
704
+ { label: "Option 1", value: "option1" },
705
+ { label: "Option 2", value: "option2" },
706
+ ],
707
+ horizontal: true,
708
+ },
709
+ });
710
+ expect(wrapper.html()).toMatchSnapshot();
711
+ });
712
+
713
+ it("should match snapshot - with help text", () => {
714
+ const wrapper = mount(FzCheckboxGroup, {
715
+ props: {
716
+ label: "Test Checkbox Group",
717
+ modelValue: [],
718
+ options: [
719
+ { label: "Option 1", value: "option1" },
720
+ ],
721
+ },
722
+ slots: {
723
+ help: "This is help text",
724
+ },
725
+ });
726
+ expect(wrapper.html()).toMatchSnapshot();
727
+ });
728
+
729
+ it("should match snapshot - required", () => {
730
+ const wrapper = mount(FzCheckboxGroup, {
731
+ props: {
732
+ label: "Test Checkbox Group",
733
+ modelValue: [],
734
+ options: [
735
+ { label: "Option 1", value: "option1" },
736
+ ],
737
+ required: true,
738
+ },
739
+ });
740
+ expect(wrapper.html()).toMatchSnapshot();
741
+ });
742
+
743
+ it("should match snapshot - hierarchical structure", () => {
744
+ const wrapper = mount(FzCheckboxGroup, {
745
+ props: {
746
+ label: "Test Checkbox Group",
747
+ modelValue: [],
748
+ options: [
749
+ {
750
+ label: "Parent Option",
751
+ value: "parent",
752
+ children: [
753
+ { label: "Child 1", value: "child1" },
754
+ { label: "Child 2", value: "child2" },
755
+ ],
756
+ },
757
+ ],
758
+ },
759
+ });
760
+ expect(wrapper.html()).toMatchSnapshot();
761
+ });
762
+ });
763
+ });
764
+