@weni/unnnic-system 3.28.2-alpha.3 → 3.30.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.
- package/dist/index.d.ts +4 -0
- package/dist/style.css +1 -1
- package/dist/unnnic.mjs +2454 -2445
- package/dist/unnnic.umd.js +18 -18
- package/package.json +2 -2
- package/src/components/Button/__tests__/Button.spec.js +81 -0
- package/src/components/Button/__tests__/ButtonIcon.spec.js +56 -0
- package/src/components/Carousel/TagCarousel.vue +8 -2
- package/src/components/Carousel/__tests__/TagCarousel.spec.js +258 -0
- package/src/components/ChartLine/__tests__/ChartLine.spec.js +170 -0
- package/src/components/Checkbox/__tests__/Checkbox.spec.js +14 -0
- package/src/components/CheckboxGroup/__tests__/CheckboxGroup.spec.js +62 -0
- package/src/components/DatePicker/DatePicker.vue +1 -0
- package/src/components/DatePicker/__tests__/DatePicker.spec.js +364 -0
- package/src/components/Disclaimer/__tests__/Disclaimer.spec.js +16 -0
- package/src/components/DropArea/DropArea.vue +1 -2
- package/src/components/DropArea/__tests__/DropArea.spec.js +333 -0
- package/src/components/MultiSelect/__tests__/MultiSelect.spec.js +109 -2
- package/src/components/MultiSelect/index.vue +1 -1
- package/src/components/PageHeader/__tests__/PageHeader.spec.js +97 -0
- package/src/components/Pagination/__tests__/Pagination.spec.js +99 -0
- package/src/components/Radio/__test__/Radio.spec.js +67 -0
- package/src/components/RadioGroup/__tests__/RadioGroup.spec.js +100 -0
- package/src/components/Slider/__tests__/Slider.spec.js +321 -0
- package/src/components/Tag/DefaultTag.vue +4 -3
- package/src/components/Tag/__tests__/DefaultTag.spec.js +51 -0
- package/src/components/Tag/__tests__/Tag.spec.js +82 -0
- package/src/components/TextArea/__test__/TextArea.spec.js +19 -0
- package/src/components/ToolTip/__tests__/ToolTip.spec.js +82 -1
- package/src/components/ui/table/TableRow.vue +4 -0
|
@@ -24,6 +24,11 @@ const findFirstSelectableDay = (wrapper) =>
|
|
|
24
24
|
.findAll('[data-testid="date-picker-day"]')
|
|
25
25
|
.find((day) => day.classes().includes('selectable'));
|
|
26
26
|
|
|
27
|
+
const findSelectableDays = (wrapper) =>
|
|
28
|
+
wrapper
|
|
29
|
+
.findAll('[data-testid="date-picker-day"]')
|
|
30
|
+
.filter((day) => day.classes().includes('selectable'));
|
|
31
|
+
|
|
27
32
|
describe('DatePicker.vue', () => {
|
|
28
33
|
let wrapper;
|
|
29
34
|
|
|
@@ -224,4 +229,363 @@ describe('DatePicker.vue', () => {
|
|
|
224
229
|
|
|
225
230
|
expect(hasOutOfRange).toBe(true);
|
|
226
231
|
});
|
|
232
|
+
|
|
233
|
+
it('selects range when start and end differ and a new date is clicked', async () => {
|
|
234
|
+
const first = findFirstSelectableDay(wrapper);
|
|
235
|
+
const days = wrapper
|
|
236
|
+
.findAll('[data-testid="date-picker-day"]')
|
|
237
|
+
.filter((day) => day.classes().includes('selectable'));
|
|
238
|
+
|
|
239
|
+
await first.trigger('click');
|
|
240
|
+
await days[5].trigger('click');
|
|
241
|
+
await days[10].trigger('click');
|
|
242
|
+
|
|
243
|
+
expect(wrapper.vm.startDate).toBeTruthy();
|
|
244
|
+
expect(wrapper.vm.endDate).toBe(wrapper.vm.startDate);
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
it('extends end date when selecting a later day from a single-day range', async () => {
|
|
248
|
+
const days = wrapper
|
|
249
|
+
.findAll('[data-testid="date-picker-day"]')
|
|
250
|
+
.filter((day) => day.classes().includes('selectable'));
|
|
251
|
+
|
|
252
|
+
await days[0].trigger('click');
|
|
253
|
+
await days[4].trigger('click');
|
|
254
|
+
|
|
255
|
+
expect(wrapper.vm.endDate).not.toBe(wrapper.vm.startDate);
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
it('moves start date when selecting an earlier day from a single-day range', async () => {
|
|
259
|
+
const days = wrapper
|
|
260
|
+
.findAll('[data-testid="date-picker-day"]')
|
|
261
|
+
.filter((day) => day.classes().includes('selectable'));
|
|
262
|
+
|
|
263
|
+
await days[10].trigger('click');
|
|
264
|
+
const earlierDay = days[2];
|
|
265
|
+
await earlierDay.trigger('click');
|
|
266
|
+
|
|
267
|
+
expect(wrapper.vm.startDate).toBeTruthy();
|
|
268
|
+
expect(wrapper.vm.startDate).toContain(String(earlierDay.text()));
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
it('resets range when clicking the same selected day twice', async () => {
|
|
272
|
+
const day = findFirstSelectableDay(wrapper);
|
|
273
|
+
const dayText = day.text();
|
|
274
|
+
|
|
275
|
+
await day.trigger('click');
|
|
276
|
+
await day.trigger('click');
|
|
277
|
+
|
|
278
|
+
expect(wrapper.vm.startDate).toContain(dayText);
|
|
279
|
+
expect(wrapper.vm.endDate).toBe(wrapper.vm.startDate);
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
it('computes last-N-months period correctly', () => {
|
|
283
|
+
wrapper = factory({
|
|
284
|
+
periodBaseDate: '2025-06-15',
|
|
285
|
+
options: [{ name: 'Last 3 months', id: 'last-3-months' }],
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
const { startDate, endDate } =
|
|
289
|
+
wrapper.vm.getStartAndEndDateByPeriod('last-3-months');
|
|
290
|
+
|
|
291
|
+
expect(startDate).toBeTruthy();
|
|
292
|
+
expect(endDate).toBeTruthy();
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
it('computes current-month period correctly', () => {
|
|
296
|
+
wrapper = factory({
|
|
297
|
+
periodBaseDate: '2025-06-15',
|
|
298
|
+
options: [{ name: 'Current month', id: 'current-month' }],
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
const { startDate, endDate } =
|
|
302
|
+
wrapper.vm.getStartAndEndDateByPeriod('current-month');
|
|
303
|
+
|
|
304
|
+
expect(startDate).toContain('1 2025');
|
|
305
|
+
expect(endDate).toContain('15 2025');
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
it('parses non-ISO periodBaseDate format', () => {
|
|
309
|
+
wrapper = factory({
|
|
310
|
+
periodBaseDate: 'June 15, 2025',
|
|
311
|
+
options: [{ name: 'Last 7 days', id: 'last-7-days' }],
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
const { startDate, endDate } =
|
|
315
|
+
wrapper.vm.getStartAndEndDateByPeriod('last-7-days');
|
|
316
|
+
|
|
317
|
+
expect(startDate).toBeTruthy();
|
|
318
|
+
expect(endDate).toBeTruthy();
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
it('falls back to current date for invalid periodBaseDate', () => {
|
|
322
|
+
wrapper = factory({
|
|
323
|
+
periodBaseDate: 'invalid-date',
|
|
324
|
+
options: [{ name: 'Last 7 days', id: 'last-7-days' }],
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
const { startDate, endDate } =
|
|
328
|
+
wrapper.vm.getStartAndEndDateByPeriod('last-7-days');
|
|
329
|
+
|
|
330
|
+
expect(startDate).toBeTruthy();
|
|
331
|
+
expect(endDate).toBeTruthy();
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
it('uses i18n pluralization with three forms', () => {
|
|
335
|
+
wrapper = factory({
|
|
336
|
+
translations: {
|
|
337
|
+
items: {
|
|
338
|
+
en: 'one|few|many',
|
|
339
|
+
},
|
|
340
|
+
},
|
|
341
|
+
});
|
|
342
|
+
|
|
343
|
+
expect(wrapper.vm.i18n('items', 0)).toBe('one');
|
|
344
|
+
expect(wrapper.vm.i18n('items', 1)).toBe('few');
|
|
345
|
+
expect(wrapper.vm.i18n('items', 2)).toBe('many');
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
it('uses i18n pluralization with two forms', () => {
|
|
349
|
+
wrapper = factory({
|
|
350
|
+
translations: {
|
|
351
|
+
items: {
|
|
352
|
+
en: 'singular|plural',
|
|
353
|
+
},
|
|
354
|
+
},
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
expect(wrapper.vm.i18n('items', 1)).toBe('singular');
|
|
358
|
+
expect(wrapper.vm.i18n('items', 2)).toBe('plural');
|
|
359
|
+
});
|
|
360
|
+
|
|
361
|
+
it('replaces variables in i18n text', () => {
|
|
362
|
+
wrapper = factory({
|
|
363
|
+
translations: {
|
|
364
|
+
greeting: {
|
|
365
|
+
en: 'Hello {name}',
|
|
366
|
+
},
|
|
367
|
+
},
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
expect(wrapper.vm.i18n('greeting', { name: 'Weni' })).toBe('Hello Weni');
|
|
371
|
+
});
|
|
372
|
+
|
|
373
|
+
it('renders popover variant class', () => {
|
|
374
|
+
wrapper = factory({ variant: 'popover' });
|
|
375
|
+
expect(wrapper.classes()).toContain('unnnic-date-picker--popover');
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
it('hides preset options when hideOptions is true', () => {
|
|
379
|
+
wrapper = factory({
|
|
380
|
+
hideOptions: true,
|
|
381
|
+
options: [{ name: 'Last 7 days', id: 'last-7-days' }],
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
expect(wrapper.find('[data-testid="date-picker-option"]').exists()).toBe(
|
|
385
|
+
false,
|
|
386
|
+
);
|
|
387
|
+
expect(wrapper.find('[data-testid="date-picker-options"]').exists()).toBe(
|
|
388
|
+
true,
|
|
389
|
+
);
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
it('navigates month view with navigation buttons', async () => {
|
|
393
|
+
wrapper = factory({
|
|
394
|
+
type: 'month',
|
|
395
|
+
options: [{ name: 'Last 12 months', id: 'last-12-months' }],
|
|
396
|
+
});
|
|
397
|
+
|
|
398
|
+
const initialReference = wrapper.vm.referenceDate;
|
|
399
|
+
await wrapper
|
|
400
|
+
.find('[data-testid="date-picker-month-nav-right"]')
|
|
401
|
+
.trigger('click');
|
|
402
|
+
|
|
403
|
+
expect(wrapper.vm.referenceDate).not.toBe(initialReference);
|
|
404
|
+
});
|
|
405
|
+
|
|
406
|
+
it('navigates year view with navigation buttons', async () => {
|
|
407
|
+
wrapper = factory({
|
|
408
|
+
type: 'year',
|
|
409
|
+
options: [{ name: 'Previous year', id: 'previous-year' }],
|
|
410
|
+
});
|
|
411
|
+
|
|
412
|
+
const initialReference = wrapper.vm.referenceDate;
|
|
413
|
+
await wrapper
|
|
414
|
+
.find('[data-testid="date-picker-year-nav-left"]')
|
|
415
|
+
.trigger('click');
|
|
416
|
+
|
|
417
|
+
expect(wrapper.vm.referenceDate).not.toBe(initialReference);
|
|
418
|
+
});
|
|
419
|
+
|
|
420
|
+
it('updates equivalent option name on submit for matched period', async () => {
|
|
421
|
+
await wrapper.vm.autoSelect('last-7-days');
|
|
422
|
+
await wrapper.find('[data-testid="date-picker-submit"]').trigger('click');
|
|
423
|
+
|
|
424
|
+
expect(wrapper.emitted('update:equivalentOption')[0][0]).toBe(
|
|
425
|
+
'Last 7 days',
|
|
426
|
+
);
|
|
427
|
+
});
|
|
428
|
+
|
|
429
|
+
it('marks custom selection when dates do not match a preset', async () => {
|
|
430
|
+
const day = findFirstSelectableDay(wrapper);
|
|
431
|
+
await day.trigger('click');
|
|
432
|
+
|
|
433
|
+
expect(wrapper.vm.optionSelected).toBe('custom');
|
|
434
|
+
});
|
|
435
|
+
|
|
436
|
+
it('does nothing when clicking a custom preset option', async () => {
|
|
437
|
+
wrapper = factory({
|
|
438
|
+
options: [
|
|
439
|
+
{ name: 'Last 7 days', id: 'last-7-days' },
|
|
440
|
+
{ name: 'Custom', id: 'custom' },
|
|
441
|
+
],
|
|
442
|
+
});
|
|
443
|
+
|
|
444
|
+
const customOption = wrapper
|
|
445
|
+
.findAll('[data-testid="date-picker-option"]')
|
|
446
|
+
.find((option) => option.text() === 'Custom');
|
|
447
|
+
|
|
448
|
+
await customOption.trigger('click');
|
|
449
|
+
expect(wrapper.vm.optionSelected).not.toBe('last-7-days');
|
|
450
|
+
});
|
|
451
|
+
|
|
452
|
+
it('highlights dates when only start date is set', async () => {
|
|
453
|
+
wrapper = factory();
|
|
454
|
+
wrapper.vm.startDate = wrapper.vm.referenceDate;
|
|
455
|
+
wrapper.vm.endDate = '';
|
|
456
|
+
await wrapper.vm.$nextTick();
|
|
457
|
+
|
|
458
|
+
const dates = wrapper.vm.getDatesOfTheMonth(wrapper.vm.referenceDate);
|
|
459
|
+
expect(dates.some((date) => date.properties.includes('highlighted'))).toBe(
|
|
460
|
+
true,
|
|
461
|
+
);
|
|
462
|
+
});
|
|
463
|
+
|
|
464
|
+
it('highlights dates when only end date is set', async () => {
|
|
465
|
+
wrapper = factory();
|
|
466
|
+
wrapper.vm.startDate = '';
|
|
467
|
+
wrapper.vm.endDate = wrapper.vm.referenceDate;
|
|
468
|
+
await wrapper.vm.$nextTick();
|
|
469
|
+
|
|
470
|
+
const dates = wrapper.vm.getDatesOfTheMonth(wrapper.vm.referenceDate);
|
|
471
|
+
expect(dates.some((date) => date.properties.includes('highlighted'))).toBe(
|
|
472
|
+
true,
|
|
473
|
+
);
|
|
474
|
+
});
|
|
475
|
+
|
|
476
|
+
it('applies column-reverse layout when hideOptions is true', () => {
|
|
477
|
+
wrapper = factory({
|
|
478
|
+
hideOptions: true,
|
|
479
|
+
size: 'large',
|
|
480
|
+
options: [{ name: 'Last 7 days', id: 'last-7-days' }],
|
|
481
|
+
});
|
|
482
|
+
|
|
483
|
+
expect(wrapper.find('[data-testid="date-picker-options"]').exists()).toBe(
|
|
484
|
+
true,
|
|
485
|
+
);
|
|
486
|
+
});
|
|
487
|
+
|
|
488
|
+
it('highlights year range with only start year selected', async () => {
|
|
489
|
+
wrapper = factory({ type: 'year' });
|
|
490
|
+
wrapper.vm.startDate = wrapper.vm.referenceDate;
|
|
491
|
+
wrapper.vm.endDate = '';
|
|
492
|
+
await wrapper.vm.$nextTick();
|
|
493
|
+
|
|
494
|
+
const highlighted = wrapper
|
|
495
|
+
.findAll('[data-testid="date-picker-year-cell"]')
|
|
496
|
+
.filter((cell) => cell.classes().includes('highlighted'));
|
|
497
|
+
|
|
498
|
+
expect(highlighted.length).toBeGreaterThan(0);
|
|
499
|
+
});
|
|
500
|
+
|
|
501
|
+
it('highlights year range with only end year selected', async () => {
|
|
502
|
+
wrapper = factory({ type: 'year' });
|
|
503
|
+
wrapper.vm.startDate = '';
|
|
504
|
+
wrapper.vm.endDate = wrapper.vm.referenceDate;
|
|
505
|
+
await wrapper.vm.$nextTick();
|
|
506
|
+
|
|
507
|
+
const highlighted = wrapper
|
|
508
|
+
.findAll('[data-testid="date-picker-year-cell"]')
|
|
509
|
+
.filter((cell) => cell.classes().includes('highlighted'));
|
|
510
|
+
|
|
511
|
+
expect(highlighted.length).toBeGreaterThan(0);
|
|
512
|
+
});
|
|
513
|
+
|
|
514
|
+
it('moves range start when selecting an interior day closer to start', async () => {
|
|
515
|
+
const days = findSelectableDays(wrapper);
|
|
516
|
+
|
|
517
|
+
await days[2].trigger('click');
|
|
518
|
+
await days[10].trigger('click');
|
|
519
|
+
await days[4].trigger('click');
|
|
520
|
+
|
|
521
|
+
expect(wrapper.vm.startDate).toBeTruthy();
|
|
522
|
+
expect(wrapper.vm.endDate).toBeTruthy();
|
|
523
|
+
expect(wrapper.emitted('change')).toBeTruthy();
|
|
524
|
+
});
|
|
525
|
+
|
|
526
|
+
it('moves range end when selecting an interior day closer to end', async () => {
|
|
527
|
+
const days = findSelectableDays(wrapper);
|
|
528
|
+
|
|
529
|
+
await days[2].trigger('click');
|
|
530
|
+
await days[10].trigger('click');
|
|
531
|
+
await days[9].trigger('click');
|
|
532
|
+
|
|
533
|
+
expect(wrapper.vm.startDate).toBeTruthy();
|
|
534
|
+
expect(wrapper.vm.endDate).toBeTruthy();
|
|
535
|
+
expect(wrapper.emitted('change')).toBeTruthy();
|
|
536
|
+
});
|
|
537
|
+
|
|
538
|
+
it('highlights month range with only start month selected', async () => {
|
|
539
|
+
wrapper = factory({ type: 'month' });
|
|
540
|
+
wrapper.vm.startDate = '3 1 2026';
|
|
541
|
+
wrapper.vm.endDate = '';
|
|
542
|
+
await wrapper.vm.$nextTick();
|
|
543
|
+
|
|
544
|
+
const highlighted = wrapper
|
|
545
|
+
.findAll('[data-testid="date-picker-month-cell"]')
|
|
546
|
+
.filter((cell) => cell.classes().includes('highlighted'));
|
|
547
|
+
|
|
548
|
+
expect(highlighted.length).toBeGreaterThan(0);
|
|
549
|
+
});
|
|
550
|
+
|
|
551
|
+
it('highlights month range with only end month selected', async () => {
|
|
552
|
+
wrapper = factory({ type: 'month' });
|
|
553
|
+
wrapper.vm.startDate = '';
|
|
554
|
+
wrapper.vm.endDate = '6 1 2026';
|
|
555
|
+
await wrapper.vm.$nextTick();
|
|
556
|
+
|
|
557
|
+
const highlighted = wrapper
|
|
558
|
+
.findAll('[data-testid="date-picker-month-cell"]')
|
|
559
|
+
.filter((cell) => cell.classes().includes('highlighted'));
|
|
560
|
+
|
|
561
|
+
expect(highlighted.length).toBeGreaterThan(0);
|
|
562
|
+
});
|
|
563
|
+
|
|
564
|
+
it('navigates month view to previous year', async () => {
|
|
565
|
+
wrapper = factory({
|
|
566
|
+
type: 'month',
|
|
567
|
+
options: [{ name: 'Last 12 months', id: 'last-12-months' }],
|
|
568
|
+
});
|
|
569
|
+
|
|
570
|
+
const initialReference = wrapper.vm.referenceDate;
|
|
571
|
+
await wrapper
|
|
572
|
+
.find('[data-testid="date-picker-month-nav-left"]')
|
|
573
|
+
.trigger('click');
|
|
574
|
+
|
|
575
|
+
expect(wrapper.vm.referenceDate).not.toBe(initialReference);
|
|
576
|
+
});
|
|
577
|
+
|
|
578
|
+
it('navigates year view to next range', async () => {
|
|
579
|
+
wrapper = factory({
|
|
580
|
+
type: 'year',
|
|
581
|
+
options: [{ name: 'Previous year', id: 'previous-year' }],
|
|
582
|
+
});
|
|
583
|
+
|
|
584
|
+
const initialReference = wrapper.vm.referenceDate;
|
|
585
|
+
await wrapper
|
|
586
|
+
.find('[data-testid="date-picker-year-nav-right"]')
|
|
587
|
+
.trigger('click');
|
|
588
|
+
|
|
589
|
+
expect(wrapper.vm.referenceDate).not.toBe(initialReference);
|
|
590
|
+
});
|
|
227
591
|
});
|
|
@@ -14,6 +14,22 @@ const mountComponent = (props = {}, slots = {}) =>
|
|
|
14
14
|
});
|
|
15
15
|
|
|
16
16
|
describe('Disclaimer', () => {
|
|
17
|
+
it('renders title when provided', () => {
|
|
18
|
+
const wrapper = mountComponent({ title: 'Disclaimer title' });
|
|
19
|
+
|
|
20
|
+
expect(wrapper.find('[data-testid="disclaimer-title"]').text()).toBe(
|
|
21
|
+
'Disclaimer title',
|
|
22
|
+
);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('uses explicit type when legacy icon props are absent', () => {
|
|
26
|
+
const wrapper = mountComponent({ type: 'success', title: 'Success' });
|
|
27
|
+
|
|
28
|
+
expect(
|
|
29
|
+
wrapper.findComponent('[data-testid="disclaimer-icon"]').props('icon'),
|
|
30
|
+
).toBe('check_circle');
|
|
31
|
+
});
|
|
32
|
+
|
|
17
33
|
it('hides title when no title is provided', () => {
|
|
18
34
|
const wrapper = mountComponent({ title: '' });
|
|
19
35
|
|
|
@@ -72,7 +72,6 @@ import UnnnicIcon from '../Icon.vue';
|
|
|
72
72
|
const isDragging = ref(false);
|
|
73
73
|
const hasError = ref(false);
|
|
74
74
|
const dragEnterCounter = ref(0);
|
|
75
|
-
const file = ref();
|
|
76
75
|
const fileRef = useTemplateRef('file');
|
|
77
76
|
|
|
78
77
|
const props = defineProps({
|
|
@@ -195,7 +194,7 @@ function handleFileChange(event) {
|
|
|
195
194
|
addFiles(files);
|
|
196
195
|
}
|
|
197
196
|
|
|
198
|
-
|
|
197
|
+
fileRef.value.value = '';
|
|
199
198
|
}
|
|
200
199
|
|
|
201
200
|
function setErrorState() {
|