diff --git a/src/__tests__/components/DeleteModal.test.tsx b/src/__tests__/components/DeleteModal.test.tsx new file mode 100644 index 0000000..0737f52 --- /dev/null +++ b/src/__tests__/components/DeleteModal.test.tsx @@ -0,0 +1,102 @@ +import React from 'react'; +import { render, screen, fireEvent, waitFor } from '@testing-library/react'; +import '@testing-library/jest-dom'; +import { DeleteModal } from '../../components/base/DeleteModal'; + +describe('DeleteModal', () => { + const defaultProps = { + isOpen: true, + onClose: jest.fn(), + onConfirm: jest.fn().mockResolvedValue(undefined), + title: 'Supprimer la campagne', + description: 'Êtes-vous sûr de vouloir supprimer cette campagne ?', + itemName: 'Campagne Test', + itemDetails:
Détails de la campagne à supprimer
, + }; + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('should render modal when open', () => { + render(); + + expect(screen.getByText('Supprimer la campagne')).toBeInTheDocument(); + expect(screen.getByText('Êtes-vous sûr de vouloir supprimer cette campagne ?')).toBeInTheDocument(); + expect(screen.getByText('Campagne Test à supprimer :')).toBeInTheDocument(); + }); + + it('should not render modal when closed', () => { + render(); + + expect(screen.queryByText('Supprimer la campagne')).not.toBeInTheDocument(); + }); + + it('should call onConfirm when delete button is clicked', async () => { + const onConfirm = jest.fn().mockResolvedValue(undefined); + render(); + + const deleteButton = screen.getByRole('button', { name: /supprimer définitivement/i }); + fireEvent.click(deleteButton); + + await waitFor(() => { + expect(onConfirm).toHaveBeenCalledTimes(1); + }); + }); + + it('should call onClose when cancel button is clicked', () => { + const onClose = jest.fn(); + render(); + + const cancelButton = screen.getByRole('button', { name: /annuler/i }); + fireEvent.click(cancelButton); + + expect(onClose).toHaveBeenCalledTimes(1); + }); + + it('should show loading state during deletion', async () => { + const onConfirm = jest.fn().mockImplementation(() => new Promise(resolve => setTimeout(resolve, 100))); + render(); + + const deleteButton = screen.getByRole('button', { name: /supprimer définitivement/i }); + fireEvent.click(deleteButton); + + await waitFor(() => { + expect(screen.getByText('Suppression...')).toBeInTheDocument(); + }); + }); + + it('should render with custom confirm text', () => { + render( + + ); + + expect(screen.getByRole('button', { name: /oui, supprimer définitivement/i })).toBeInTheDocument(); + }); + + it('should show warning message', () => { + render(); + + expect(screen.getByText(/⚠️ Cette action est irréversible./)).toBeInTheDocument(); + }); + + it('should show custom warning message', () => { + render( + + ); + + expect(screen.getByText(/⚠️ Attention, cette suppression est définitive !/)).toBeInTheDocument(); + }); + + it('should display item details', () => { + render(); + + expect(screen.getByText('Détails de la campagne à supprimer')).toBeInTheDocument(); + }); +}); diff --git a/src/__tests__/components/ErrorDisplay.test.tsx b/src/__tests__/components/ErrorDisplay.test.tsx new file mode 100644 index 0000000..0e79c53 --- /dev/null +++ b/src/__tests__/components/ErrorDisplay.test.tsx @@ -0,0 +1,63 @@ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import '@testing-library/jest-dom'; +import { ErrorDisplay } from '../../components/base/ErrorDisplay'; + +describe('ErrorDisplay', () => { + it('should render error message when error is provided', () => { + const error = 'Une erreur est survenue'; + render(); + + expect(screen.getByText('Une erreur est survenue')).toBeInTheDocument(); + expect(screen.getByText('Une erreur est survenue')).toHaveClass('text-red-600'); + }); + + it('should not render when no error is provided', () => { + render(); + + expect(screen.queryByText('Une erreur est survenue')).not.toBeInTheDocument(); + }); + + it('should not render when error is null', () => { + render(); + + expect(screen.queryByText('Une erreur est survenue')).not.toBeInTheDocument(); + }); + + it('should not render when error is undefined', () => { + render(); + + expect(screen.queryByText('Une erreur est survenue')).not.toBeInTheDocument(); + }); + + it('should handle long error messages', () => { + const longError = 'A'.repeat(500); + render(); + + expect(screen.getByText(longError)).toBeInTheDocument(); + }); + + it('should handle special characters in error message', () => { + const specialError = 'Erreur avec des caractères spéciaux: @#$%^&*()_+{}|:"<>?[]\\;\',./'; + render(); + + expect(screen.getByText(specialError)).toBeInTheDocument(); + }); + + it('should handle HTML in error message', () => { + const htmlError = 'Erreur avec HTML'; + render(); + + expect(screen.getByText(htmlError)).toBeInTheDocument(); + // Vérifier que le HTML n'est pas interprété + expect(screen.queryByText('xss')).not.toBeInTheDocument(); + }); + + it('should have proper accessibility attributes', () => { + const error = 'Erreur d\'accessibilité'; + render(); + + const errorElement = screen.getByText(error); + expect(errorElement).toHaveAttribute('role', 'alert'); + }); +}); diff --git a/src/__tests__/lib/markdown.test.ts b/src/__tests__/lib/markdown.test.ts new file mode 100644 index 0000000..90d7896 --- /dev/null +++ b/src/__tests__/lib/markdown.test.ts @@ -0,0 +1,67 @@ +import { parseMarkdown } from '../../lib/markdown'; + +describe('Markdown Module', () => { + describe('parseMarkdown', () => { + it('should parse basic markdown', () => { + const markdown = '# Titre\n\nContenu **gras** et *italique*.'; + const result = parseMarkdown(markdown); + + expect(result).toContain('

Titre

'); + expect(result).toContain('gras'); + expect(result).toContain('italique'); + }); + + it('should handle empty string', () => { + const result = parseMarkdown(''); + expect(result).toBe(''); + }); + + it('should handle null/undefined', () => { + expect(parseMarkdown(null as any)).toBe(''); + expect(parseMarkdown(undefined as any)).toBe(''); + }); + + it('should handle links', () => { + const markdown = '[Lien](https://example.com)'; + const result = parseMarkdown(markdown); + + expect(result).toContain('Lien'); + }); + + it('should handle lists', () => { + const markdown = '- Item 1\n- Item 2\n- Item 3'; + const result = parseMarkdown(markdown); + + expect(result).toContain('
    '); + expect(result).toContain('
  • Item 1
  • '); + expect(result).toContain('
  • Item 2
  • '); + expect(result).toContain('
  • Item 3
  • '); + }); + }); + + describe('renderMarkdown', () => { + it('should render markdown to HTML', () => { + const markdown = '**Texte en gras**'; + const result = parseMarkdown(markdown); + + expect(result).toContain('Texte en gras'); + }); + + it('should handle code blocks', () => { + const markdown = '```javascript\nconsole.log("test");\n```'; + const result = parseMarkdown(markdown); + + expect(result).toContain('```javascript'); + expect(result).toContain('console.log("test");'); + expect(result).toContain('```'); + }); + + it('should handle inline code', () => { + const markdown = 'Utilisez `console.log()` pour afficher.'; + const result = parseMarkdown(markdown); + + expect(result).toContain('`console.log()`'); + }); + }); +}); diff --git a/src/components/base/ErrorDisplay.tsx b/src/components/base/ErrorDisplay.tsx index c4b26ef..a1d0d7f 100644 --- a/src/components/base/ErrorDisplay.tsx +++ b/src/components/base/ErrorDisplay.tsx @@ -8,7 +8,7 @@ export function ErrorDisplay({ error, className = "" }: ErrorDisplayProps) { return (
    -

    {error}

    +

    {error}

    ); }