ConfirmModal.test.tsx 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. /**
  2. * Tests for the ConfirmModal component.
  3. */
  4. import { describe, it, expect, vi, afterEach } from 'vitest';
  5. import { screen, fireEvent, cleanup } from '@testing-library/react';
  6. import userEvent from '@testing-library/user-event';
  7. import { render } from '../utils';
  8. import { ConfirmModal } from '../../components/ConfirmModal';
  9. describe('ConfirmModal', () => {
  10. const defaultProps = {
  11. title: 'Confirm Action',
  12. message: 'Are you sure you want to proceed?',
  13. onConfirm: vi.fn(),
  14. onCancel: vi.fn(),
  15. };
  16. afterEach(() => {
  17. cleanup();
  18. vi.clearAllMocks();
  19. });
  20. describe('rendering', () => {
  21. it('renders title', () => {
  22. render(<ConfirmModal {...defaultProps} />);
  23. expect(screen.getByText('Confirm Action')).toBeInTheDocument();
  24. });
  25. it('renders message', () => {
  26. render(<ConfirmModal {...defaultProps} />);
  27. expect(
  28. screen.getByText('Are you sure you want to proceed?')
  29. ).toBeInTheDocument();
  30. });
  31. it('renders default button text', () => {
  32. render(<ConfirmModal {...defaultProps} />);
  33. expect(screen.getByText('Confirm')).toBeInTheDocument();
  34. expect(screen.getByText('Cancel')).toBeInTheDocument();
  35. });
  36. it('renders custom button text', () => {
  37. render(
  38. <ConfirmModal
  39. {...defaultProps}
  40. confirmText="Delete"
  41. cancelText="Go Back"
  42. />
  43. );
  44. expect(screen.getByText('Delete')).toBeInTheDocument();
  45. expect(screen.getByText('Go Back')).toBeInTheDocument();
  46. });
  47. });
  48. describe('interactions', () => {
  49. it('calls onConfirm when confirm button is clicked', async () => {
  50. const user = userEvent.setup();
  51. const onConfirm = vi.fn();
  52. render(<ConfirmModal {...defaultProps} onConfirm={onConfirm} />);
  53. await user.click(screen.getByText('Confirm'));
  54. expect(onConfirm).toHaveBeenCalledTimes(1);
  55. });
  56. it('calls onCancel when cancel button is clicked', async () => {
  57. const user = userEvent.setup();
  58. const onCancel = vi.fn();
  59. render(<ConfirmModal {...defaultProps} onCancel={onCancel} />);
  60. await user.click(screen.getByText('Cancel'));
  61. expect(onCancel).toHaveBeenCalledTimes(1);
  62. });
  63. it('calls onCancel when clicking backdrop', async () => {
  64. const user = userEvent.setup();
  65. const onCancel = vi.fn();
  66. const { container } = render(
  67. <ConfirmModal {...defaultProps} onCancel={onCancel} />
  68. );
  69. // Click on the backdrop (first div with fixed class)
  70. const backdrop = container.querySelector('.fixed');
  71. if (backdrop) {
  72. await user.click(backdrop);
  73. expect(onCancel).toHaveBeenCalledTimes(1);
  74. }
  75. });
  76. it('does not call onCancel when clicking modal content', async () => {
  77. const user = userEvent.setup();
  78. const onCancel = vi.fn();
  79. render(<ConfirmModal {...defaultProps} onCancel={onCancel} />);
  80. // Click on the title inside the modal
  81. await user.click(screen.getByText('Confirm Action'));
  82. expect(onCancel).not.toHaveBeenCalled();
  83. });
  84. it('calls onCancel when Escape key is pressed', () => {
  85. const onCancel = vi.fn();
  86. render(<ConfirmModal {...defaultProps} onCancel={onCancel} />);
  87. fireEvent.keyDown(window, { key: 'Escape' });
  88. expect(onCancel).toHaveBeenCalledTimes(1);
  89. });
  90. });
  91. describe('variants', () => {
  92. it('renders default variant', () => {
  93. render(<ConfirmModal {...defaultProps} variant="default" />);
  94. expect(screen.getByText('Confirm Action')).toBeInTheDocument();
  95. });
  96. it('renders danger variant', () => {
  97. render(<ConfirmModal {...defaultProps} variant="danger" />);
  98. expect(screen.getByText('Confirm Action')).toBeInTheDocument();
  99. });
  100. it('renders warning variant', () => {
  101. render(<ConfirmModal {...defaultProps} variant="warning" />);
  102. expect(screen.getByText('Confirm Action')).toBeInTheDocument();
  103. });
  104. });
  105. describe('loading state', () => {
  106. it('shows loading text when isLoading is true', () => {
  107. render(<ConfirmModal {...defaultProps} isLoading={true} loadingText="Deleting..." />);
  108. expect(screen.getByText('Deleting...')).toBeInTheDocument();
  109. });
  110. it('shows default loading text when loadingText not provided', () => {
  111. render(<ConfirmModal {...defaultProps} isLoading={true} />);
  112. expect(screen.getByText('Loading...')).toBeInTheDocument();
  113. });
  114. it('disables buttons when loading', () => {
  115. render(<ConfirmModal {...defaultProps} isLoading={true} />);
  116. const buttons = screen.getAllByRole('button');
  117. buttons.forEach(button => {
  118. expect(button).toBeDisabled();
  119. });
  120. });
  121. it('does not call onCancel when clicking backdrop while loading', async () => {
  122. const user = userEvent.setup();
  123. const onCancel = vi.fn();
  124. const { container } = render(
  125. <ConfirmModal {...defaultProps} onCancel={onCancel} isLoading={true} />
  126. );
  127. const backdrop = container.querySelector('.fixed');
  128. if (backdrop) {
  129. await user.click(backdrop);
  130. expect(onCancel).not.toHaveBeenCalled();
  131. }
  132. });
  133. it('does not call onCancel on Escape key while loading', () => {
  134. const onCancel = vi.fn();
  135. render(<ConfirmModal {...defaultProps} onCancel={onCancel} isLoading={true} />);
  136. fireEvent.keyDown(window, { key: 'Escape' });
  137. expect(onCancel).not.toHaveBeenCalled();
  138. });
  139. });
  140. });