the-tip-top-frontend/__tests__/components/ui/Modal.test.tsx
soufiane 43a2dadd0e test: add unit tests for UI components to improve coverage
Add comprehensive tests for:
- Pagination: navigation, page numbers, disabled states
- EmptyState: message, icon, title, action button
- LoadingState: different types (page, card, table, list)
- Modal: open/close, backdrop click, escape key, sizes

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-01 22:24:19 +01:00

201 lines
5.4 KiB
TypeScript

/**
* Tests for the Modal component
* @jest-environment jsdom
*/
import React from 'react';
import { render, screen, fireEvent } from '@testing-library/react';
import { Modal } from '@/components/ui/Modal';
describe('Modal', () => {
const mockOnClose = jest.fn();
beforeEach(() => {
jest.clearAllMocks();
});
it('should not render when isOpen is false', () => {
const { container } = render(
<Modal isOpen={false} onClose={mockOnClose}>
<div>Modal content</div>
</Modal>
);
expect(container.firstChild).toBeNull();
});
it('should render when isOpen is true', () => {
render(
<Modal isOpen={true} onClose={mockOnClose}>
<div>Modal content</div>
</Modal>
);
expect(screen.getByText('Modal content')).toBeInTheDocument();
});
it('should render title when provided', () => {
render(
<Modal isOpen={true} onClose={mockOnClose} title="Test Title">
<div>Content</div>
</Modal>
);
expect(screen.getByText('Test Title')).toBeInTheDocument();
});
it('should render close button by default', () => {
render(
<Modal isOpen={true} onClose={mockOnClose} title="Test">
<div>Content</div>
</Modal>
);
expect(screen.getByLabelText('Fermer')).toBeInTheDocument();
});
it('should not render close button when showCloseButton is false', () => {
render(
<Modal isOpen={true} onClose={mockOnClose} showCloseButton={false}>
<div>Content</div>
</Modal>
);
expect(screen.queryByLabelText('Fermer')).not.toBeInTheDocument();
});
it('should call onClose when close button is clicked', () => {
render(
<Modal isOpen={true} onClose={mockOnClose} title="Test">
<div>Content</div>
</Modal>
);
fireEvent.click(screen.getByLabelText('Fermer'));
expect(mockOnClose).toHaveBeenCalledTimes(1);
});
it('should call onClose when backdrop is clicked', () => {
render(
<Modal isOpen={true} onClose={mockOnClose}>
<div>Content</div>
</Modal>
);
// The dialog role is on the backdrop element itself
const backdrop = screen.getByRole('dialog');
fireEvent.click(backdrop);
expect(mockOnClose).toHaveBeenCalledTimes(1);
});
it('should not call onClose when modal content is clicked', () => {
render(
<Modal isOpen={true} onClose={mockOnClose}>
<div>Content</div>
</Modal>
);
fireEvent.click(screen.getByText('Content'));
expect(mockOnClose).not.toHaveBeenCalled();
});
it('should call onClose when Escape key is pressed', () => {
render(
<Modal isOpen={true} onClose={mockOnClose}>
<div>Content</div>
</Modal>
);
fireEvent.keyDown(document, { key: 'Escape' });
expect(mockOnClose).toHaveBeenCalledTimes(1);
});
it('should have dialog role', () => {
render(
<Modal isOpen={true} onClose={mockOnClose}>
<div>Content</div>
</Modal>
);
expect(screen.getByRole('dialog')).toBeInTheDocument();
});
it('should have aria-modal attribute', () => {
render(
<Modal isOpen={true} onClose={mockOnClose}>
<div>Content</div>
</Modal>
);
expect(screen.getByRole('dialog')).toHaveAttribute('aria-modal', 'true');
});
it('should apply sm size class', () => {
const { container } = render(
<Modal isOpen={true} onClose={mockOnClose} size="sm">
<div>Content</div>
</Modal>
);
expect(container.querySelector('.max-w-md')).toBeInTheDocument();
});
it('should apply md size class by default', () => {
const { container } = render(
<Modal isOpen={true} onClose={mockOnClose}>
<div>Content</div>
</Modal>
);
expect(container.querySelector('.max-w-lg')).toBeInTheDocument();
});
it('should apply lg size class', () => {
const { container } = render(
<Modal isOpen={true} onClose={mockOnClose} size="lg">
<div>Content</div>
</Modal>
);
expect(container.querySelector('.max-w-2xl')).toBeInTheDocument();
});
it('should apply xl size class', () => {
const { container } = render(
<Modal isOpen={true} onClose={mockOnClose} size="xl">
<div>Content</div>
</Modal>
);
expect(container.querySelector('.max-w-4xl')).toBeInTheDocument();
});
it('should set body overflow to hidden when open', () => {
render(
<Modal isOpen={true} onClose={mockOnClose}>
<div>Content</div>
</Modal>
);
expect(document.body.style.overflow).toBe('hidden');
});
it('should reset body overflow when closed', () => {
const { rerender } = render(
<Modal isOpen={true} onClose={mockOnClose}>
<div>Content</div>
</Modal>
);
rerender(
<Modal isOpen={false} onClose={mockOnClose}>
<div>Content</div>
</Modal>
);
expect(document.body.style.overflow).toBe('unset');
});
it('should have aria-labelledby when title is provided', () => {
render(
<Modal isOpen={true} onClose={mockOnClose} title="My Modal">
<div>Content</div>
</Modal>
);
const dialog = screen.getByRole('dialog');
expect(dialog).toHaveAttribute('aria-labelledby', 'modal-title');
});
it('should not have aria-labelledby when title is not provided', () => {
render(
<Modal isOpen={true} onClose={mockOnClose}>
<div>Content</div>
</Modal>
);
const dialog = screen.getByRole('dialog');
expect(dialog).not.toHaveAttribute('aria-labelledby');
});
});