@api-client/ui 0.5.18 → 0.5.20

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.
@@ -441,5 +441,319 @@ describe('md', () => {
441
441
  })
442
442
  })
443
443
  })
444
+
445
+ describe('closing event', () => {
446
+ it('dispatches the closing event before close event when dismissing', async () => {
447
+ const element = await buttonFixture()
448
+ const closingSpy = sinon.spy()
449
+ const closeSpy = sinon.spy()
450
+ element.addEventListener('closing', closingSpy)
451
+ element.addEventListener('close', closeSpy)
452
+
453
+ const button = element.querySelector('ui-button[value="dismiss"]') as UiButton
454
+ button.click()
455
+
456
+ assert.isTrue(closingSpy.calledOnce, 'closing event was dispatched')
457
+ assert.isTrue(closeSpy.calledOnce, 'close event was dispatched')
458
+ assert.isTrue(closingSpy.calledBefore(closeSpy), 'closing event was dispatched before close event')
459
+ })
460
+
461
+ it('dispatches the closing event before close event when confirming', async () => {
462
+ const element = await buttonFixture()
463
+ const closingSpy = sinon.spy()
464
+ const closeSpy = sinon.spy()
465
+ element.addEventListener('closing', closingSpy)
466
+ element.addEventListener('close', closeSpy)
467
+
468
+ const button = element.querySelector('ui-button[value="confirm"]') as UiButton
469
+ button.click()
470
+
471
+ assert.isTrue(closingSpy.calledOnce, 'closing event was dispatched')
472
+ assert.isTrue(closeSpy.calledOnce, 'close event was dispatched')
473
+ assert.isTrue(closingSpy.calledBefore(closeSpy), 'closing event was dispatched before close event')
474
+ })
475
+
476
+ it('dispatches the closing event when pressing Escape', async () => {
477
+ const element = await buttonFixture()
478
+ const closingSpy = sinon.spy()
479
+ const closeSpy = sinon.spy()
480
+ element.addEventListener('closing', closingSpy)
481
+ element.addEventListener('close', closeSpy)
482
+
483
+ element.open = true
484
+ await element.updateComplete
485
+ const button = element.querySelector('ui-button')!
486
+ button.focus()
487
+ await UiMock.keyPress(element, 'Escape', { key: 'Escape' })
488
+
489
+ assert.isTrue(closingSpy.calledOnce, 'closing event was dispatched')
490
+ assert.isTrue(closeSpy.calledOnce, 'close event was dispatched')
491
+ assert.isTrue(closingSpy.calledBefore(closeSpy), 'closing event was dispatched before close event')
492
+ })
493
+
494
+ it('dispatches the closing event with correct detail for dismiss action', async () => {
495
+ const element = await buttonFixture()
496
+ const closingSpy = sinon.spy()
497
+ element.addEventListener('closing', closingSpy)
498
+
499
+ const button = element.querySelector('ui-button[value="dismiss"]') as UiButton
500
+ button.click()
501
+
502
+ assert.isTrue(closingSpy.calledOnce, 'closing event was dispatched')
503
+ const event = closingSpy.args[0][0] as CustomEvent<UiDialogClosingReason>
504
+ assert.isTrue(event.detail.cancelled, 'cancelled flag is true for dismiss action')
505
+ assert.isUndefined(event.detail.value, 'value is undefined when no dialogValue is set')
506
+ })
507
+
508
+ it('dispatches the closing event with correct detail for confirm action', async () => {
509
+ const element = await buttonFixture()
510
+ const closingSpy = sinon.spy()
511
+ element.addEventListener('closing', closingSpy)
512
+
513
+ const button = element.querySelector('ui-button[value="confirm"]') as UiButton
514
+ button.click()
515
+
516
+ assert.isTrue(closingSpy.calledOnce, 'closing event was dispatched')
517
+ const event = closingSpy.args[0][0] as CustomEvent<UiDialogClosingReason>
518
+ assert.isFalse(event.detail.cancelled, 'cancelled flag is false for confirm action')
519
+ assert.isUndefined(event.detail.value, 'value is undefined when no dialogValue is set')
520
+ })
521
+
522
+ it('includes dialogValue in closing event detail', async () => {
523
+ const element = await buttonFixture()
524
+ element.dialogValue = 'test-value'
525
+ const closingSpy = sinon.spy()
526
+ element.addEventListener('closing', closingSpy)
527
+
528
+ const button = element.querySelector('ui-button[value="confirm"]') as UiButton
529
+ button.click()
530
+
531
+ assert.isTrue(closingSpy.calledOnce, 'closing event was dispatched')
532
+ const event = closingSpy.args[0][0] as CustomEvent<UiDialogClosingReason>
533
+ assert.equal(event.detail.value, 'test-value', 'dialogValue is included in event detail')
534
+ })
535
+
536
+ it('prevents dialog closing when closing event is cancelled', async () => {
537
+ const element = await buttonFixture()
538
+ const closingSpy = sinon.spy()
539
+ const closeSpy = sinon.spy()
540
+
541
+ element.addEventListener('closing', (event) => {
542
+ closingSpy()
543
+ event.preventDefault() // Cancel the closing
544
+ })
545
+ element.addEventListener('close', closeSpy)
546
+
547
+ element.open = true
548
+ await element.updateComplete
549
+ assert.isTrue(element.open, 'dialog is initially open')
550
+
551
+ const button = element.querySelector('ui-button[value="dismiss"]') as UiButton
552
+ button.click()
553
+
554
+ assert.isTrue(closingSpy.calledOnce, 'closing event was dispatched')
555
+ assert.isFalse(closeSpy.called, 'close event was not dispatched')
556
+ assert.isTrue(element.open, 'dialog remains open when closing is prevented')
557
+ })
558
+
559
+ it('prevents dialog closing when confirming and closing event is cancelled', async () => {
560
+ const element = await buttonFixture()
561
+ const closingSpy = sinon.spy()
562
+ const closeSpy = sinon.spy()
563
+
564
+ element.addEventListener('closing', (event) => {
565
+ closingSpy()
566
+ event.preventDefault() // Cancel the closing
567
+ })
568
+ element.addEventListener('close', closeSpy)
569
+
570
+ element.open = true
571
+ await element.updateComplete
572
+ assert.isTrue(element.open, 'dialog is initially open')
573
+
574
+ const button = element.querySelector('ui-button[value="confirm"]') as UiButton
575
+ button.click()
576
+
577
+ assert.isTrue(closingSpy.calledOnce, 'closing event was dispatched')
578
+ assert.isFalse(closeSpy.called, 'close event was not dispatched')
579
+ assert.isTrue(element.open, 'dialog remains open when closing is prevented')
580
+ })
581
+
582
+ it('prevents dialog closing when pressing Escape and closing event is cancelled', async () => {
583
+ const element = await buttonFixture()
584
+ const closingSpy = sinon.spy()
585
+ const closeSpy = sinon.spy()
586
+
587
+ element.addEventListener('closing', (event) => {
588
+ closingSpy()
589
+ event.preventDefault() // Cancel the closing
590
+ })
591
+ element.addEventListener('close', closeSpy)
592
+
593
+ element.open = true
594
+ await element.updateComplete
595
+ assert.isTrue(element.open, 'dialog is initially open')
596
+
597
+ const button = element.querySelector('ui-button')!
598
+ button.focus()
599
+ await UiMock.keyPress(element, 'Escape', { key: 'Escape' })
600
+
601
+ assert.isTrue(closingSpy.calledOnce, 'closing event was dispatched')
602
+ assert.isFalse(closeSpy.called, 'close event was not dispatched')
603
+ assert.isTrue(element.open, 'dialog remains open when closing is prevented')
604
+ })
605
+
606
+ it('prevents native dialog close and reopens when closing event is cancelled', async () => {
607
+ const element = await modalFixture()
608
+ const closingSpy = sinon.spy()
609
+ const showModalSpy = sinon.spy(element.dialog, 'showModal')
610
+
611
+ element.addEventListener('closing', (event) => {
612
+ closingSpy()
613
+ event.preventDefault() // Cancel the closing
614
+ })
615
+
616
+ element.open = true
617
+ await element.updateComplete
618
+ assert.isTrue(element.open, 'dialog is initially open')
619
+ assert.isTrue(element.dialog.open, 'native dialog is open')
620
+
621
+ // Reset the spy count after initial open
622
+ showModalSpy.resetHistory()
623
+
624
+ // Simulate native dialog close event (e.g., clicking backdrop)
625
+ element.dialog.dispatchEvent(new Event('close'))
626
+
627
+ assert.isTrue(closingSpy.calledOnce, 'closing event was dispatched')
628
+ assert.isTrue(element.open, 'dialog remains open when closing is prevented')
629
+ assert.isTrue(showModalSpy.calledOnce, 'showModal was called to reopen the dialog')
630
+ })
631
+
632
+ it('verifies closing event properties', async () => {
633
+ const element = await buttonFixture()
634
+ let closingEvent: CustomEvent<UiDialogClosingReason>
635
+
636
+ element.addEventListener('closing', (event) => {
637
+ closingEvent = event as CustomEvent<UiDialogClosingReason>
638
+ })
639
+
640
+ const button = element.querySelector('ui-button[value="dismiss"]') as UiButton
641
+ button.click()
642
+
643
+ assert.isDefined(closingEvent!, 'closing event was dispatched')
644
+ assert.isTrue(closingEvent!.cancelable, 'closing event is cancelable')
645
+ assert.isFalse(closingEvent!.bubbles, 'closing event does not bubble')
646
+ assert.isFalse(closingEvent!.composed, 'closing event is not composed')
647
+ assert.equal(closingEvent!.type, 'closing', 'event type is "closing"')
648
+ })
649
+
650
+ it('works with imperative dismiss and confirm buttons', async () => {
651
+ const element = await basicFixture()
652
+ element.dismissLabel = 'Cancel'
653
+ element.confirmLabel = 'OK'
654
+ await element.updateComplete
655
+
656
+ const closingSpy = sinon.spy()
657
+ const closeSpy = sinon.spy()
658
+ element.addEventListener('closing', closingSpy)
659
+ element.addEventListener('close', closeSpy)
660
+
661
+ // Test dismiss button
662
+ const dismissButton = element.shadowRoot!.querySelector('.internal-button[value="dismiss"]') as UiButton
663
+ dismissButton.click()
664
+
665
+ assert.isTrue(closingSpy.calledOnce, 'closing event was dispatched for dismiss')
666
+ assert.isTrue(closeSpy.calledOnce, 'close event was dispatched for dismiss')
667
+
668
+ // Reset spies and test confirm button
669
+ closingSpy.resetHistory()
670
+ closeSpy.resetHistory()
671
+ element.open = true
672
+ await element.updateComplete
673
+
674
+ const confirmButton = element.shadowRoot!.querySelector('.internal-button[value="confirm"]') as UiButton
675
+ confirmButton.click()
676
+
677
+ assert.isTrue(closingSpy.calledOnce, 'closing event was dispatched for confirm')
678
+ assert.isTrue(closeSpy.calledOnce, 'close event was dispatched for confirm')
679
+ })
680
+
681
+ it('can prevent closing with imperative buttons', async () => {
682
+ const element = await basicFixture()
683
+ element.dismissLabel = 'Cancel'
684
+ await element.updateComplete
685
+
686
+ const closingSpy = sinon.spy()
687
+ const closeSpy = sinon.spy()
688
+
689
+ element.addEventListener('closing', (event) => {
690
+ closingSpy()
691
+ event.preventDefault()
692
+ })
693
+ element.addEventListener('close', closeSpy)
694
+
695
+ element.open = true
696
+ await element.updateComplete
697
+
698
+ const dismissButton = element.shadowRoot!.querySelector('.internal-button[value="dismiss"]') as UiButton
699
+ dismissButton.click()
700
+
701
+ assert.isTrue(closingSpy.calledOnce, 'closing event was dispatched')
702
+ assert.isFalse(closeSpy.called, 'close event was not dispatched')
703
+ assert.isTrue(element.open, 'dialog remains open')
704
+ })
705
+ })
706
+
707
+ describe('accessibility', () => {
708
+ it('meets accessibility standards in closed state', async () => {
709
+ const element = await basicFixture()
710
+ await assert.isAccessible(element)
711
+ })
712
+
713
+ it('meets accessibility standards when open', async () => {
714
+ const element = await basicFixture()
715
+ element.open = true
716
+ await element.updateComplete
717
+ await assert.isAccessible(element)
718
+ })
719
+
720
+ it('meets accessibility standards with modal dialog', async () => {
721
+ const element = await modalFixture()
722
+ element.open = true
723
+ await element.updateComplete
724
+ await assert.isAccessible(element)
725
+ })
726
+
727
+ it('meets accessibility standards with full content', async () => {
728
+ const element: UiDialog = await fixture(html`
729
+ <ui-dialog modal open>
730
+ <ui-icon slot="icon" icon="deleteOutline"></ui-icon>
731
+ <span slot="title">Delete confirmation</span>
732
+ <p>Are you sure you want to delete this item?</p>
733
+ <ui-button color="text" slot="button" value="dismiss">Cancel</ui-button>
734
+ <ui-button color="text" slot="button" value="confirm">Delete</ui-button>
735
+ </ui-dialog>
736
+ `)
737
+ await element.updateComplete
738
+ await assert.isAccessible(element)
739
+ })
740
+
741
+ it('maintains accessibility when closing is prevented', async () => {
742
+ const element = await buttonFixture()
743
+ element.addEventListener('closing', (event) => {
744
+ event.preventDefault()
745
+ })
746
+
747
+ element.open = true
748
+ await element.updateComplete
749
+
750
+ const button = element.querySelector('ui-button[value="dismiss"]') as UiButton
751
+ button.click()
752
+
753
+ // Dialog should remain open and accessible
754
+ assert.isTrue(element.open, 'dialog remains open')
755
+ await assert.isAccessible(element)
756
+ })
757
+ })
444
758
  })
445
759
  })