diff --git a/src/components/AgendaItems/AgendaItemsUpdateModal.test.tsx b/src/components/AgendaItems/AgendaItemsUpdateModal.test.tsx new file mode 100644 index 0000000000..afaae49520 --- /dev/null +++ b/src/components/AgendaItems/AgendaItemsUpdateModal.test.tsx @@ -0,0 +1,295 @@ +import React from 'react'; +import { render, screen, fireEvent, waitFor } from '@testing-library/react'; +import { MockedProvider } from '@apollo/react-testing'; +import { I18nextProvider } from 'react-i18next'; +import { Provider } from 'react-redux'; +import { BrowserRouter } from 'react-router-dom'; +import { store } from 'state/store'; +import i18nForTest from 'utils/i18nForTest'; + +import { LocalizationProvider } from '@mui/x-date-pickers'; +import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; + +import AgendaItemsUpdateModal from './AgendaItemsUpdateModal'; +import { toast } from 'react-toastify'; +import convertToBase64 from 'utils/convertToBase64'; + +const mockFormState = { + title: 'Test Title', + description: 'Test Description', + duration: '20', + attachments: ['Test Attachment'], + urls: ['https://example.com'], + agendaItemCategoryIds: ['category'], + agendaItemCategoryNames: ['category'], + createdBy: { + firstName: 'Test', + lastName: 'User', + }, +}; + +const mockHideUpdateModal = jest.fn(); +const mockSetFormState = jest.fn(); +const mockUpdateAgendaItemHandler = jest.fn(); +const mockT = (key: string): string => key; + +jest.mock('react-toastify', () => ({ + toast: { + success: jest.fn(), + error: jest.fn(), + }, +})); +jest.mock('utils/convertToBase64'); +const mockedConvertToBase64 = convertToBase64 as jest.MockedFunction< + typeof convertToBase64 +>; + +describe('AgendaItemsUpdateModal', () => { + test('renders modal correctly', () => { + render( + + + + + + + + + + + , + ); + + expect(screen.getByText('updateAgendaItem')).toBeInTheDocument(); + expect(screen.getByTestId('updateAgendaItemBtn')).toBeInTheDocument(); + expect( + screen.getByTestId('updateAgendaItemModalCloseBtn'), + ).toBeInTheDocument(); + }); + + test('tests the condition for formState.title and formState.description', async () => { + render( + + + + + + + + + + + , + ); + + fireEvent.change(screen.getByLabelText('title'), { + target: { value: 'New title' }, + }); + + fireEvent.change(screen.getByLabelText('description'), { + target: { value: 'New description' }, + }); + + fireEvent.change(screen.getByLabelText('duration'), { + target: { value: '30' }, + }); + + fireEvent.click(screen.getByTestId('deleteUrl')); + fireEvent.click(screen.getByTestId('deleteAttachment')); + + expect(mockSetFormState).toHaveBeenCalledWith({ + ...mockFormState, + title: 'New title', + }); + expect(mockSetFormState).toHaveBeenCalledWith({ + ...mockFormState, + description: 'New description', + }); + + expect(mockSetFormState).toHaveBeenCalledWith({ + ...mockFormState, + duration: '30', + }); + + await waitFor(() => { + expect(mockSetFormState).toHaveBeenCalledWith({ + ...mockFormState, + urls: [], + }); + }); + + await waitFor(() => { + expect(mockSetFormState).toHaveBeenCalledWith({ + ...mockFormState, + attachments: [], + }); + }); + }); + + test('handleAddUrl correctly adds valid URL', async () => { + render( + + + + + + + + + , + ); + + const urlInput = screen.getByTestId('urlInput'); + const linkBtn = screen.getByTestId('linkBtn'); + + fireEvent.change(urlInput, { target: { value: 'https://example.com' } }); + fireEvent.click(linkBtn); + + await waitFor(() => { + expect(mockSetFormState).toHaveBeenCalledWith({ + ...mockFormState, + urls: [...mockFormState.urls, 'https://example.com'], + }); + }); + }); + + test('shows error toast for invalid URL', async () => { + render( + + + + + + + + + + + , + ); + + const urlInput = screen.getByTestId('urlInput'); + const linkBtn = screen.getByTestId('linkBtn'); + + fireEvent.change(urlInput, { target: { value: 'invalid-url' } }); + fireEvent.click(linkBtn); + + await waitFor(() => { + expect(toast.error).toHaveBeenCalledWith('invalidUrl'); + }); + }); + + test('shows error toast for file size exceeding limit', async () => { + render( + + + + + + + + + + + , + ); + + const fileInput = screen.getByTestId('attachment'); + const largeFile = new File( + ['a'.repeat(11 * 1024 * 1024)], + 'large-file.jpg', + ); // 11 MB file + + Object.defineProperty(fileInput, 'files', { + value: [largeFile], + }); + + fireEvent.change(fileInput); + + await waitFor(() => { + expect(toast.error).toHaveBeenCalledWith('fileSizeExceedsLimit'); + }); + }); + + test('adds files correctly when within size limit', async () => { + mockedConvertToBase64.mockResolvedValue('base64-file'); + + render( + + + + + + + + + + + , + ); + + const fileInput = screen.getByTestId('attachment'); + const smallFile = new File(['small-file-content'], 'small-file.jpg'); // Small file + + Object.defineProperty(fileInput, 'files', { + value: [smallFile], + }); + + fireEvent.change(fileInput); + + await waitFor(() => { + expect(mockSetFormState).toHaveBeenCalledWith({ + ...mockFormState, + attachments: [...mockFormState.attachments, 'base64-file'], + }); + }); + }); +}); diff --git a/src/components/AgendaItems/AgendaItemsUpdateModal.tsx b/src/components/AgendaItems/AgendaItemsUpdateModal.tsx index e3f43e5602..693234b314 100644 --- a/src/components/AgendaItems/AgendaItemsUpdateModal.tsx +++ b/src/components/AgendaItems/AgendaItemsUpdateModal.tsx @@ -209,10 +209,13 @@ const AgendaItemsUpdateModal: React.FC< type="text" placeholder={t('enterUrl')} id="basic-url" + data-testid="urlInput" value={newUrl} onChange={(e) => setNewUrl(e.target.value)} /> - + {formState.urls.map((url, index) => ( @@ -224,6 +227,7 @@ const AgendaItemsUpdateModal: React.FC<