From 895beaddd5d12a6c3d7ba0dd08f2a433eb297d21 Mon Sep 17 00:00:00 2001 From: MANDEEP N H <146331633+mandeepnh5@users.noreply.github.com> Date: Thu, 26 Dec 2024 17:34:19 +0530 Subject: [PATCH 01/13] Update EventRegistryModal jest to vitest (#2910) --- ...ee.test.tsx => AddOnSpotAttendee.spec.tsx} | 24 +++++++++++-------- ...est.tsx => EventRegistrantsModal.spec.tsx} | 3 ++- ...t.tsx => EventRegistrantsWrapper.spec.tsx} | 1 + 3 files changed, 17 insertions(+), 11 deletions(-) rename src/components/EventRegistrantsModal/{AddOnSpotAttendee.test.tsx => AddOnSpotAttendee.spec.tsx} (92%) rename src/components/EventRegistrantsModal/{EventRegistrantsModal.test.tsx => EventRegistrantsModal.spec.tsx} (99%) rename src/components/EventRegistrantsModal/{EventRegistrantsWrapper.test.tsx => EventRegistrantsWrapper.spec.tsx} (98%) diff --git a/src/components/EventRegistrantsModal/AddOnSpotAttendee.test.tsx b/src/components/EventRegistrantsModal/AddOnSpotAttendee.spec.tsx similarity index 92% rename from src/components/EventRegistrantsModal/AddOnSpotAttendee.test.tsx rename to src/components/EventRegistrantsModal/AddOnSpotAttendee.spec.tsx index c0dc20d200..66f0dda38b 100644 --- a/src/components/EventRegistrantsModal/AddOnSpotAttendee.test.tsx +++ b/src/components/EventRegistrantsModal/AddOnSpotAttendee.spec.tsx @@ -11,23 +11,27 @@ import { Provider } from 'react-redux'; import { I18nextProvider } from 'react-i18next'; import { store } from 'state/store'; import i18nForTest from '../../utils/i18nForTest'; +import { describe, expect, vi } from 'vitest'; -jest.mock('react-toastify', () => ({ +vi.mock('react-toastify', () => ({ toast: { - success: jest.fn(), - error: jest.fn(), + success: vi.fn(), + error: vi.fn(), }, })); const mockProps = { show: true, - handleClose: jest.fn(), - reloadMembers: jest.fn(), + handleClose: vi.fn(), + reloadMembers: vi.fn(), }; -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useParams: () => ({ eventId: '123', orgId: '123' }), -})); +vi.mock('react-router-dom', async () => { + const actual = await vi.importActual('react-router-dom'); + return { + ...actual, + useParams: () => ({ eventId: '123', orgId: '123' }), + }; +}); const MOCKS = [ { @@ -80,7 +84,7 @@ const renderAddOnSpotAttendee = (): RenderResult => { describe('AddOnSpotAttendee Component', () => { beforeEach(() => { - jest.clearAllMocks(); + vi.clearAllMocks(); }); it('renders the component with all form fields', async () => { diff --git a/src/components/EventRegistrantsModal/EventRegistrantsModal.test.tsx b/src/components/EventRegistrantsModal/EventRegistrantsModal.spec.tsx similarity index 99% rename from src/components/EventRegistrantsModal/EventRegistrantsModal.test.tsx rename to src/components/EventRegistrantsModal/EventRegistrantsModal.spec.tsx index 8ca76393cd..4f422ceb7f 100644 --- a/src/components/EventRegistrantsModal/EventRegistrantsModal.test.tsx +++ b/src/components/EventRegistrantsModal/EventRegistrantsModal.spec.tsx @@ -15,6 +15,7 @@ import i18nForTest from 'utils/i18nForTest'; import { ToastContainer } from 'react-toastify'; import { LocalizationProvider } from '@mui/x-date-pickers'; import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; +import { describe, test, expect, vi } from 'vitest'; const queryMockWithoutRegistrant = [ { @@ -160,7 +161,7 @@ describe('Testing Event Registrants Modal', () => { show: true, eventId: 'event123', orgId: 'org123', - handleClose: jest.fn(), + handleClose: vi.fn(), }; test('The modal should be rendered, correct text must be displayed when there are no attendees and add attendee mutation must function properly', async () => { diff --git a/src/components/EventRegistrantsModal/EventRegistrantsWrapper.test.tsx b/src/components/EventRegistrantsModal/EventRegistrantsWrapper.spec.tsx similarity index 98% rename from src/components/EventRegistrantsModal/EventRegistrantsWrapper.test.tsx rename to src/components/EventRegistrantsModal/EventRegistrantsWrapper.spec.tsx index 95ac347bc4..97a0d1f00f 100644 --- a/src/components/EventRegistrantsModal/EventRegistrantsWrapper.test.tsx +++ b/src/components/EventRegistrantsModal/EventRegistrantsWrapper.spec.tsx @@ -11,6 +11,7 @@ import i18nForTest from 'utils/i18nForTest'; import { ToastContainer } from 'react-toastify'; import { LocalizationProvider } from '@mui/x-date-pickers'; import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; +import { describe, test, expect } from 'vitest'; const queryMock = [ { From 431a76ad2d85c370d16b7f6b114008bd9bbcf8e2 Mon Sep 17 00:00:00 2001 From: Dhiren-Mhatre <130587526+Dhiren-Mhatre@users.noreply.github.com> Date: Thu, 26 Dec 2024 17:38:24 +0530 Subject: [PATCH 02/13] Refactor: src/utils/getRefreshToken.test.ts from Jest to Vitest (#2913) --- .../OrganizationDashboard.spec.tsx | 14 ++- src/utils/getRefreshToken.spec.ts | 87 +++++++++++++++++++ src/utils/getRefreshToken.test.ts | 54 ------------ 3 files changed, 98 insertions(+), 57 deletions(-) create mode 100644 src/utils/getRefreshToken.spec.ts delete mode 100644 src/utils/getRefreshToken.test.ts diff --git a/src/screens/OrganizationDashboard/OrganizationDashboard.spec.tsx b/src/screens/OrganizationDashboard/OrganizationDashboard.spec.tsx index b7b4e05a37..92404f767b 100644 --- a/src/screens/OrganizationDashboard/OrganizationDashboard.spec.tsx +++ b/src/screens/OrganizationDashboard/OrganizationDashboard.spec.tsx @@ -147,6 +147,11 @@ describe('Testing Organization Dashboard Screen', () => { vi.mocked(useParams).mockReturnValue({ orgId: 'orgId' }); renderOrganizationDashboard(link1); + // Wait for initial load + await waitFor(() => { + expect(screen.getByText(t.upcomingEvents)).toBeInTheDocument(); + }); + // Dashboard cards const membersBtn = await screen.findByText(t.members); expect(membersBtn).toBeInTheDocument(); @@ -155,9 +160,12 @@ describe('Testing Organization Dashboard Screen', () => { expect(screen.getByText(t.events)).toBeInTheDocument(); expect(screen.getByText(t.blockedUsers)).toBeInTheDocument(); - // Upcoming events - expect(screen.getByText(t.upcomingEvents)).toBeInTheDocument(); - expect(screen.getByText('Event 1')).toBeInTheDocument(); + // Upcoming events - Using more flexible matcher + await waitFor(() => { + expect( + screen.getByText(/Event 1/i, { exact: false }), + ).toBeInTheDocument(); + }); // Latest posts expect(screen.getByText(t.latestPosts)).toBeInTheDocument(); diff --git a/src/utils/getRefreshToken.spec.ts b/src/utils/getRefreshToken.spec.ts new file mode 100644 index 0000000000..54ed1b57e8 --- /dev/null +++ b/src/utils/getRefreshToken.spec.ts @@ -0,0 +1,87 @@ +// SKIP_LOCALSTORAGE_CHECK +import { describe, it, expect, beforeEach, vi } from 'vitest'; +import { refreshToken } from './getRefreshToken'; + +const mockApolloClient = { + mutate: vi.fn(() => + Promise.resolve({ + data: { + refreshToken: { + accessToken: 'newAccessToken', + refreshToken: 'newRefreshToken', + }, + }, + }), + ), +}; + +vi.mock('@apollo/client', async () => { + const actual = await vi.importActual('@apollo/client'); + return { + ...actual, + ApolloClient: vi.fn(() => mockApolloClient), + }; +}); + +describe('refreshToken', () => { + const { location } = window; + + interface TestInterfacePartialWindow { + location?: Partial; + } + + delete (window as TestInterfacePartialWindow).location; + global.window.location = { ...location, reload: vi.fn() }; + + // Create storage mock + const localStorageMock = { + getItem: vi.fn(), + setItem: vi.fn(), + clear: vi.fn(), + removeItem: vi.fn(), + length: 0, + key: vi.fn(), + }; + + beforeEach(() => { + vi.clearAllMocks(); + Object.defineProperty(window, 'localStorage', { + value: localStorageMock, + writable: true, + }); + }); + + it('returns true when the token is refreshed successfully', async () => { + const result = await refreshToken(); + + expect(localStorage.setItem).toHaveBeenCalledWith( + 'Talawa-admin_token', + JSON.stringify('newAccessToken'), + ); + expect(localStorage.setItem).toHaveBeenCalledWith( + 'Talawa-admin_refreshToken', + JSON.stringify('newRefreshToken'), + ); + expect(result).toBe(true); + expect(window.location.reload).toHaveBeenCalled(); + }); + + it('returns false and logs error when token refresh fails', async () => { + const consoleErrorSpy = vi + .spyOn(console, 'error') + .mockImplementation(() => {}); + + const errorMock = new Error('Failed to refresh token'); + mockApolloClient.mutate.mockRejectedValueOnce(errorMock); + + const result = await refreshToken(); + + expect(result).toBe(false); + expect(consoleErrorSpy).toHaveBeenCalledWith( + 'Failed to refresh token', + errorMock, + ); + + consoleErrorSpy.mockRestore(); + }); +}); diff --git a/src/utils/getRefreshToken.test.ts b/src/utils/getRefreshToken.test.ts deleted file mode 100644 index 58de898a66..0000000000 --- a/src/utils/getRefreshToken.test.ts +++ /dev/null @@ -1,54 +0,0 @@ -// SKIP_LOCALSTORAGE_CHECK -import { refreshToken } from './getRefreshToken'; - -jest.mock('@apollo/client', () => { - const originalModule = jest.requireActual('@apollo/client'); - - return { - __esModule: true, - ...originalModule, - ApolloClient: jest.fn(() => ({ - mutate: jest.fn(() => - Promise.resolve({ - data: { - refreshToken: { - accessToken: 'newAccessToken', - refreshToken: 'newRefreshToken', - }, - }, - }), - ), - })), - }; -}); - -describe('refreshToken', () => { - // Mock window.location.reload() - const { location } = window; - delete (global.window as any).location; - global.window.location = { ...location, reload: jest.fn() }; - - // Mock localStorage.setItem() and localStorage.clear() - - Storage.prototype.setItem = jest.fn(); - Storage.prototype.clear = jest.fn(); - - beforeEach(() => { - jest.clearAllMocks(); - }); - - it('returns true when the token is refreshed successfully', async () => { - const result = await refreshToken(); - - expect(localStorage.setItem).toHaveBeenCalledWith( - 'Talawa-admin_token', - JSON.stringify('newAccessToken'), - ); - expect(localStorage.setItem).toHaveBeenCalledWith( - 'Talawa-admin_refreshToken', - JSON.stringify('newRefreshToken'), - ); - expect(result).toBe(true); - expect(window.location.reload).toHaveBeenCalled(); - }); -}); From d99fc8b23ecb0598d2ebfc340bcbb2236f0f56fb Mon Sep 17 00:00:00 2001 From: MANDEEP N H <146331633+mandeepnh5@users.noreply.github.com> Date: Thu, 26 Dec 2024 17:39:45 +0530 Subject: [PATCH 03/13] Migrated src/components/RecurrenceOptions/* from Jest to Vitest. (#2911) * Update Recurrence options jest to vitest * Fix linting issues --- ...nce.test.tsx => CustomRecurrence.spec.tsx} | 19 ++++++++++--------- ...ns.test.tsx => RecurrenceOptions.spec.tsx} | 19 ++++++++++--------- 2 files changed, 20 insertions(+), 18 deletions(-) rename src/components/RecurrenceOptions/{CustomRecurrence.test.tsx => CustomRecurrence.spec.tsx} (98%) rename src/components/RecurrenceOptions/{RecurrenceOptions.test.tsx => RecurrenceOptions.spec.tsx} (97%) diff --git a/src/components/RecurrenceOptions/CustomRecurrence.test.tsx b/src/components/RecurrenceOptions/CustomRecurrence.spec.tsx similarity index 98% rename from src/components/RecurrenceOptions/CustomRecurrence.test.tsx rename to src/components/RecurrenceOptions/CustomRecurrence.spec.tsx index fc0cacf5c4..236e34e855 100644 --- a/src/components/RecurrenceOptions/CustomRecurrence.test.tsx +++ b/src/components/RecurrenceOptions/CustomRecurrence.spec.tsx @@ -9,7 +9,6 @@ import { } from '@testing-library/react'; import { Provider } from 'react-redux'; import { BrowserRouter } from 'react-router-dom'; -import 'jest-location-mock'; import { I18nextProvider } from 'react-i18next'; import OrganizationEvents from '../../screens/OrganizationEvents/OrganizationEvents'; @@ -23,6 +22,7 @@ import { ThemeProvider } from 'react-bootstrap'; import { LocalizationProvider } from '@mui/x-date-pickers'; import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; import { MOCKS } from '../../screens/OrganizationEvents/OrganizationEventsMocks'; +import { describe, test, expect, vi } from 'vitest'; const theme = createTheme({ palette: { @@ -48,19 +48,20 @@ const translations = JSON.parse( ), ); -jest.mock('@mui/x-date-pickers/DateTimePicker', () => { +vi.mock('@mui/x-date-pickers/DateTimePicker', async () => { + const actual = await vi.importActual( + '@mui/x-date-pickers/DesktopDateTimePicker', + ); return { - DateTimePicker: jest.requireActual( - '@mui/x-date-pickers/DesktopDateTimePicker', - ).DesktopDateTimePicker, + DateTimePicker: actual.DesktopDateTimePicker, }; }); -jest.mock('react-toastify', () => ({ +vi.mock('react-toastify', () => ({ toast: { - success: jest.fn(), - warning: jest.fn(), - error: jest.fn(), + success: vi.fn(), + warning: vi.fn(), + error: vi.fn(), }, })); diff --git a/src/components/RecurrenceOptions/RecurrenceOptions.test.tsx b/src/components/RecurrenceOptions/RecurrenceOptions.spec.tsx similarity index 97% rename from src/components/RecurrenceOptions/RecurrenceOptions.test.tsx rename to src/components/RecurrenceOptions/RecurrenceOptions.spec.tsx index 2d283460da..07adf7bd16 100644 --- a/src/components/RecurrenceOptions/RecurrenceOptions.test.tsx +++ b/src/components/RecurrenceOptions/RecurrenceOptions.spec.tsx @@ -9,7 +9,6 @@ import { } from '@testing-library/react'; import { Provider } from 'react-redux'; import { BrowserRouter } from 'react-router-dom'; -import 'jest-location-mock'; import { I18nextProvider } from 'react-i18next'; import OrganizationEvents from '../../screens/OrganizationEvents/OrganizationEvents'; @@ -23,6 +22,7 @@ import { ThemeProvider } from 'react-bootstrap'; import { LocalizationProvider } from '@mui/x-date-pickers'; import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; import { MOCKS } from '../../screens/OrganizationEvents/OrganizationEventsMocks'; +import { describe, test, expect, vi } from 'vitest'; const theme = createTheme({ palette: { @@ -52,19 +52,20 @@ const translations = { ...JSON.parse(JSON.stringify(i18n.getDataByLanguage('en')?.errors ?? {})), }; -jest.mock('@mui/x-date-pickers/DateTimePicker', () => { +vi.mock('@mui/x-date-pickers/DateTimePicker', async () => { + const actual = await vi.importActual( + '@mui/x-date-pickers/DesktopDateTimePicker', + ); return { - DateTimePicker: jest.requireActual( - '@mui/x-date-pickers/DesktopDateTimePicker', - ).DesktopDateTimePicker, + DateTimePicker: actual.DesktopDateTimePicker, }; }); -jest.mock('react-toastify', () => ({ +vi.mock('react-toastify', () => ({ toast: { - success: jest.fn(), - warning: jest.fn(), - error: jest.fn(), + success: vi.fn(), + warning: vi.fn(), + error: vi.fn(), }, })); From 47f57a91e6f98e7fb05875403a528fd2852748ed Mon Sep 17 00:00:00 2001 From: Devender singh shekhawat <50149675+devender18@users.noreply.github.com> Date: Thu, 26 Dec 2024 17:40:59 +0530 Subject: [PATCH 04/13] Refactor CSS files in src/screens/ForgotPassword (fixes #2506) (#2914) --- .../ForgotPassword/ForgotPassword.module.css | 71 ------------------ src/screens/ForgotPassword/ForgotPassword.tsx | 4 +- src/style/app.module.css | 72 +++++++++++++++++++ 3 files changed, 74 insertions(+), 73 deletions(-) delete mode 100644 src/screens/ForgotPassword/ForgotPassword.module.css diff --git a/src/screens/ForgotPassword/ForgotPassword.module.css b/src/screens/ForgotPassword/ForgotPassword.module.css deleted file mode 100644 index 74e09aecc6..0000000000 --- a/src/screens/ForgotPassword/ForgotPassword.module.css +++ /dev/null @@ -1,71 +0,0 @@ -.pageWrapper { - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - height: 100vh; -} - -.cardBody { - padding: 2rem; - background-color: #fff; - border-radius: 0.8rem; - border: 1px solid var(--bs-gray-200); -} - -.keyWrapper { - height: 72px; - width: 72px; - transform: rotate(180deg); - position: relative; - overflow: hidden; - display: block; - display: flex; - justify-content: center; - align-items: center; - border-radius: 50%; - margin: 1rem auto; -} - -.keyWrapper .themeOverlay { - position: absolute; - background-color: var(--bs-primary); - height: 100%; - width: 100%; - opacity: 0.15; -} - -.keyWrapper .keyLogo { - height: 42px; - width: 42px; - -webkit-animation: zoomIn 0.3s ease-in-out; - animation: zoomIn 0.3s ease-in-out; -} - -@-webkit-keyframes zoomIn { - 0% { - opacity: 0; - -webkit-transform: scale(0.5); - transform: scale(0.5); - } - - 100% { - opacity: 1; - -webkit-transform: scale(1); - transform: scale(1); - } -} - -@keyframes zoomIn { - 0% { - opacity: 0; - -webkit-transform: scale(0.5); - transform: scale(0.5); - } - - 100% { - opacity: 1; - -webkit-transform: scale(1); - transform: scale(1); - } -} diff --git a/src/screens/ForgotPassword/ForgotPassword.tsx b/src/screens/ForgotPassword/ForgotPassword.tsx index 663960572b..83f20b4375 100644 --- a/src/screens/ForgotPassword/ForgotPassword.tsx +++ b/src/screens/ForgotPassword/ForgotPassword.tsx @@ -16,7 +16,7 @@ import { Form } from 'react-bootstrap'; import Button from 'react-bootstrap/Button'; import { useTranslation } from 'react-i18next'; import { errorHandler } from 'utils/errorHandler'; -import styles from './ForgotPassword.module.css'; +import styles from 'style/app.module.css'; import useLocalStorage from 'utils/useLocalstorage'; /** @@ -162,7 +162,7 @@ const ForgotPassword = (): JSX.Element => {
-
+
diff --git a/src/style/app.module.css b/src/style/app.module.css index 5bfdef1e66..db6b79477c 100644 --- a/src/style/app.module.css +++ b/src/style/app.module.css @@ -1823,6 +1823,50 @@ form > input { margin-bottom: 20px; } +.pageWrapper { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + height: 100vh; +} + +.cardTemplate { + padding: 2rem; + background-color: #fff; + border-radius: 0.8rem; + border: 1px solid var(--bs-gray-200); +} + +.keyWrapper { + height: 72px; + width: 72px; + transform: rotate(180deg); + transform-origin: center; + position: relative; + overflow: hidden; + display: flex; + justify-content: center; + align-items: center; + border-radius: 50%; + margin: 1rem auto; +} + +.keyWrapper .themeOverlay { + position: absolute; + background-color: var(--bs-primary); + height: 100%; + width: 100%; + opacity: var(--theme-overlay-opacity, 0.15); +} + +.keyWrapper .keyLogo { + height: 42px; + width: 42px; + -webkit-animation: zoomIn 0.3s ease-in-out; + animation: zoomIn 0.3s ease-in-out; +} + @media (max-width: 1020px) { .btnsContainerOrgPost { flex-direction: column; @@ -1952,3 +1996,31 @@ button[data-testid='createPostBtn'] { top: 45%; } } + +@-webkit-keyframes zoomIn { + 0% { + opacity: 0; + -webkit-transform: scale(0.5); + transform: scale(0.5); + } + + 100% { + opacity: 1; + -webkit-transform: scale(1); + transform: scale(1); + } +} + +@keyframes zoomIn { + 0% { + opacity: 0; + -webkit-transform: scale(0.5); + transform: scale(0.5); + } + + 100% { + opacity: 1; + -webkit-transform: scale(1); + transform: scale(1); + } +} From f0dadfd0784e6c960b547e88514d4edcf42c3925 Mon Sep 17 00:00:00 2001 From: Pratap Rathi Date: Thu, 26 Dec 2024 17:43:30 +0530 Subject: [PATCH 05/13] Refactor: Migrated src/components/EventManagement/* from Jest to Vitest (#2915) --- ...board.test.tsx => EventDashboard.spec.tsx} | 12 +++--- ...ems.test.tsx => EventAgendaItems.spec.tsx} | 41 ++++++++++--------- ...st.test.tsx => AttendedEventList.spec.tsx} | 7 ++-- ...ance.test.tsx => EventAttendance.spec.tsx} | 22 +++++----- ...tics.test.tsx => EventStatistics.spec.tsx} | 39 ++++++++++-------- 5 files changed, 65 insertions(+), 56 deletions(-) rename src/components/EventManagement/Dashboard/{EventDashboard.test.tsx => EventDashboard.spec.tsx} (88%) rename src/components/EventManagement/EventAgendaItems/{EventAgendaItems.test.tsx => EventAgendaItems.spec.tsx} (87%) rename src/components/EventManagement/EventAttendance/{AttendedEventList.test.tsx => AttendedEventList.spec.tsx} (92%) rename src/components/EventManagement/EventAttendance/{EventAttendance.test.tsx => EventAttendance.spec.tsx} (85%) rename src/components/EventManagement/EventAttendance/{EventStatistics.test.tsx => EventStatistics.spec.tsx} (88%) diff --git a/src/components/EventManagement/Dashboard/EventDashboard.test.tsx b/src/components/EventManagement/Dashboard/EventDashboard.spec.tsx similarity index 88% rename from src/components/EventManagement/Dashboard/EventDashboard.test.tsx rename to src/components/EventManagement/Dashboard/EventDashboard.spec.tsx index dc605a1604..672282ff4a 100644 --- a/src/components/EventManagement/Dashboard/EventDashboard.test.tsx +++ b/src/components/EventManagement/Dashboard/EventDashboard.spec.tsx @@ -13,6 +13,7 @@ import type { ApolloLink, DefaultOptions } from '@apollo/client'; import { MOCKS_WITHOUT_TIME, MOCKS_WITH_TIME } from './EventDashboard.mocks'; import { StaticMockLink } from 'utils/StaticMockLink'; +import { vi, expect, it, describe } from 'vitest'; const mockWithTime = new StaticMockLink(MOCKS_WITH_TIME, true); const mockWithoutTime = new StaticMockLink(MOCKS_WITHOUT_TIME, true); @@ -38,9 +39,8 @@ async function wait(ms = 500): Promise { } const mockID = 'event123'; -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useParams: () => ({ eventId: mockID }), +vi.mock('react-router-dom', async () => ({ + ...(await vi.importActual('react-router-dom')), })); const renderEventDashboard = (mockLink: ApolloLink): RenderResult => { @@ -63,7 +63,7 @@ const renderEventDashboard = (mockLink: ApolloLink): RenderResult => { }; describe('Testing Event Dashboard Screen', () => { - test('The page should display event details correctly and also show the time if provided', async () => { + it('The page should display event details correctly and also show the time if provided', async () => { const { getByTestId } = renderEventDashboard(mockWithTime); await wait(); @@ -84,7 +84,7 @@ describe('Testing Event Dashboard Screen', () => { fireEvent.click(closeButton); }); - test('The page should display event details correctly and should not show the time if it is null', async () => { + it('The page should display event details correctly and should not show the time if it is null', async () => { const { getByTestId } = renderEventDashboard(mockWithoutTime); await wait(); @@ -92,7 +92,7 @@ describe('Testing Event Dashboard Screen', () => { expect(getByTestId('event-time')).toBeInTheDocument(); }); - test('Should show loader while data is being fetched', async () => { + it('Should show loader while data is being fetched', async () => { const { getByTestId, queryByTestId } = renderEventDashboard(mockWithTime); expect(getByTestId('spinner')).toBeInTheDocument(); // Wait for loading to complete diff --git a/src/components/EventManagement/EventAgendaItems/EventAgendaItems.test.tsx b/src/components/EventManagement/EventAgendaItems/EventAgendaItems.spec.tsx similarity index 87% rename from src/components/EventManagement/EventAgendaItems/EventAgendaItems.test.tsx rename to src/components/EventManagement/EventAgendaItems/EventAgendaItems.spec.tsx index 3bce7ad11e..fabd3312dd 100644 --- a/src/components/EventManagement/EventAgendaItems/EventAgendaItems.test.tsx +++ b/src/components/EventManagement/EventAgendaItems/EventAgendaItems.spec.tsx @@ -7,9 +7,7 @@ import { waitForElementToBeRemoved, } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; -import 'jest-localstorage-mock'; import { MockedProvider } from '@apollo/client/testing'; -import 'jest-location-mock'; import { I18nextProvider } from 'react-i18next'; import { Provider } from 'react-redux'; import { BrowserRouter } from 'react-router-dom'; @@ -17,11 +15,10 @@ import i18n from 'utils/i18nForTest'; // import { toast } from 'react-toastify'; import { LocalizationProvider } from '@mui/x-date-pickers'; import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; - import { store } from 'state/store'; import { StaticMockLink } from 'utils/StaticMockLink'; - import EventAgendaItems from './EventAgendaItems'; +import { vi, describe, expect, it, beforeEach } from 'vitest'; import { MOCKS, @@ -29,21 +26,20 @@ import { // MOCKS_ERROR_MUTATION, } from './EventAgendaItemsMocks'; -jest.mock('react-toastify', () => ({ +vi.mock('react-toastify', () => ({ toast: { - success: jest.fn(), - error: jest.fn(), + success: vi.fn(), + error: vi.fn(), }, })); -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useParams: () => ({ eventId: '123' }), +vi.mock('react-router-dom', async () => ({ + ...(await vi.importActual('react-router-dom')), })); //temporarily fixes react-beautiful-dnd droppable method's depreciation error //needs to be fixed in React 19 -jest.spyOn(console, 'error').mockImplementation((message) => { +vi.spyOn(console, 'error').mockImplementation((message) => { if (message.includes('Support for defaultProps will be removed')) { return; } @@ -78,8 +74,18 @@ describe('Testing Agenda Items Components', () => { attachments: [], urls: [], }; - test('Component loads correctly', async () => { - window.location.assign('/event/111/123'); + + beforeEach(() => { + Object.defineProperty(window, 'location', { + configurable: true, + value: { + reload: vi.fn(), + href: 'https://localhost:4321/event/111/123', + }, + }); + }); + + it('Component loads correctly', async () => { const { getByText } = render( @@ -99,8 +105,7 @@ describe('Testing Agenda Items Components', () => { }); }); - test('render error component on unsuccessful agenda item query', async () => { - window.location.assign('/event/111/123'); + it('render error component on unsuccessful agenda item query', async () => { const { queryByText } = render( @@ -122,8 +127,7 @@ describe('Testing Agenda Items Components', () => { }); }); - test('opens and closes the create agenda item modal', async () => { - window.location.assign('/event/111/123'); + it('opens and closes the create agenda item modal', async () => { render( @@ -156,8 +160,7 @@ describe('Testing Agenda Items Components', () => { screen.queryByTestId('createAgendaItemModalCloseBtn'), ); }); - test('creates new agenda item', async () => { - window.location.assign('/event/111/123'); + it('creates new agenda item', async () => { render( diff --git a/src/components/EventManagement/EventAttendance/AttendedEventList.test.tsx b/src/components/EventManagement/EventAttendance/AttendedEventList.spec.tsx similarity index 92% rename from src/components/EventManagement/EventAttendance/AttendedEventList.test.tsx rename to src/components/EventManagement/EventAttendance/AttendedEventList.spec.tsx index 2d60081acf..b365ba89ff 100644 --- a/src/components/EventManagement/EventAttendance/AttendedEventList.test.tsx +++ b/src/components/EventManagement/EventAttendance/AttendedEventList.spec.tsx @@ -7,6 +7,7 @@ import { BrowserRouter } from 'react-router-dom'; import { I18nextProvider } from 'react-i18next'; import i18nForTest from 'utils/i18nForTest'; import { formatDate } from 'utils/dateFormatter'; +import { describe, expect, it } from 'vitest'; const mockEvent = { _id: 'event123', @@ -51,7 +52,7 @@ describe('Testing AttendedEventList', () => { eventId: 'event123', }; - test('Component renders and displays event details correctly', async () => { + it('Component renders and displays event details correctly', async () => { const { queryByText, queryByTitle } = render( @@ -71,7 +72,7 @@ describe('Testing AttendedEventList', () => { }); }); - test('Component handles error state gracefully', async () => { + it('Component handles error state gracefully', async () => { const errorMock = [ { request: { @@ -99,7 +100,7 @@ describe('Testing AttendedEventList', () => { }); }); - test('Component renders link with correct URL', async () => { + it('Component renders link with correct URL', async () => { const { container } = render( diff --git a/src/components/EventManagement/EventAttendance/EventAttendance.test.tsx b/src/components/EventManagement/EventAttendance/EventAttendance.spec.tsx similarity index 85% rename from src/components/EventManagement/EventAttendance/EventAttendance.test.tsx rename to src/components/EventManagement/EventAttendance/EventAttendance.spec.tsx index db44357d07..bff1553cc0 100644 --- a/src/components/EventManagement/EventAttendance/EventAttendance.test.tsx +++ b/src/components/EventManagement/EventAttendance/EventAttendance.spec.tsx @@ -17,6 +17,7 @@ import userEvent from '@testing-library/user-event'; import { StaticMockLink } from 'utils/StaticMockLink'; import i18n from 'utils/i18nForTest'; import { MOCKS } from './Attendance.mocks'; +import { vi, describe, beforeEach, afterEach, expect, it } from 'vitest'; const link = new StaticMockLink(MOCKS, true); @@ -25,7 +26,7 @@ async function wait(): Promise { return Promise.resolve(); }); } -jest.mock('react-chartjs-2', () => ({ +vi.mock('react-chartjs-2', () => ({ Line: () => null, Bar: () => null, Pie: () => null, @@ -47,18 +48,17 @@ const renderEventAttendance = (): RenderResult => { describe('Event Attendance Component', () => { beforeEach(() => { - jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useParams: () => ({ eventId: 'event123', orgId: 'org123' }), + vi.mock('react-router-dom', async () => ({ + ...(await vi.importActual('react-router-dom')), })); }); afterEach(() => { - jest.clearAllMocks(); + vi.clearAllMocks(); cleanup(); }); - test('Component loads correctly with table headers', async () => { + it('Component loads correctly with table headers', async () => { renderEventAttendance(); await wait(); @@ -70,7 +70,7 @@ describe('Event Attendance Component', () => { }); }); - test('Renders attendee data correctly', async () => { + it('Renders attendee data correctly', async () => { renderEventAttendance(); await wait(); @@ -83,7 +83,7 @@ describe('Event Attendance Component', () => { }); }); - test('Search filters attendees by name correctly', async () => { + it('Search filters attendees by name correctly', async () => { renderEventAttendance(); await wait(); @@ -97,7 +97,7 @@ describe('Event Attendance Component', () => { }); }); - test('Sort functionality changes attendee order', async () => { + it('Sort functionality changes attendee order', async () => { renderEventAttendance(); await wait(); @@ -112,7 +112,7 @@ describe('Event Attendance Component', () => { }); }); - test('Date filter shows correct number of attendees', async () => { + it('Date filter shows correct number of attendees', async () => { renderEventAttendance(); await wait(); @@ -124,7 +124,7 @@ describe('Event Attendance Component', () => { expect(screen.getByText('Attendees not Found')).toBeInTheDocument(); }); }); - test('Statistics modal opens and closes correctly', async () => { + it('Statistics modal opens and closes correctly', async () => { renderEventAttendance(); await wait(); diff --git a/src/components/EventManagement/EventAttendance/EventStatistics.test.tsx b/src/components/EventManagement/EventAttendance/EventStatistics.spec.tsx similarity index 88% rename from src/components/EventManagement/EventAttendance/EventStatistics.test.tsx rename to src/components/EventManagement/EventAttendance/EventStatistics.spec.tsx index 03f4671a5e..38379b54fb 100644 --- a/src/components/EventManagement/EventAttendance/EventStatistics.test.tsx +++ b/src/components/EventManagement/EventAttendance/EventStatistics.spec.tsx @@ -5,21 +5,26 @@ import { MockedProvider } from '@apollo/client/testing'; import { EVENT_DETAILS, RECURRING_EVENTS } from 'GraphQl/Queries/Queries'; import userEvent from '@testing-library/user-event'; import { exportToCSV } from 'utils/chartToPdf'; +import { vi, describe, expect, it } from 'vitest'; +import type { Mock } from 'vitest'; // Mock chart.js to avoid canvas errors -jest.mock('react-chartjs-2', () => ({ +vi.mock('react-chartjs-2', async () => ({ + ...(await vi.importActual('react-chartjs-2')), Line: () => null, Bar: () => null, })); // Mock react-router-dom -jest.mock('react-router-dom', () => ({ +vi.mock('react-router-dom', async () => ({ + ...(await vi.importActual('react-router-dom')), useParams: () => ({ orgId: 'org123', eventId: 'event123', }), })); -jest.mock('utils/chartToPdf', () => ({ - exportToCSV: jest.fn(), +vi.mock('utils/chartToPdf', async () => ({ + ...(await vi.importActual('utils/chartToPdf')), + exportToCSV: vi.fn(), })); const mocks = [ { @@ -139,7 +144,7 @@ const mockStatistics = { }; describe('AttendanceStatisticsModal', () => { - test('renders modal with correct initial state', async () => { + it('renders modal with correct initial state', async () => { render( { }); }); - test('switches between gender and age demographics', async () => { + it('switches between gender and age demographics', async () => { render( { }); }); - test('handles data demographics export functionality', async () => { - const mockExportToCSV = jest.fn(); - (exportToCSV as jest.Mock).mockImplementation(mockExportToCSV); + it('handles data demographics export functionality', async () => { + const mockExportToCSV = vi.fn(); + (exportToCSV as Mock).mockImplementation(mockExportToCSV); render( @@ -220,9 +225,9 @@ describe('AttendanceStatisticsModal', () => { expect(mockExportToCSV).toHaveBeenCalled(); }); - test('handles data trends export functionality', async () => { - const mockExportToCSV = jest.fn(); - (exportToCSV as jest.Mock).mockImplementation(mockExportToCSV); + it('handles data trends export functionality', async () => { + const mockExportToCSV = vi.fn(); + (exportToCSV as Mock).mockImplementation(mockExportToCSV); render( @@ -255,7 +260,7 @@ describe('AttendanceStatisticsModal', () => { expect(mockExportToCSV).toHaveBeenCalled(); }); - test('displays recurring event data correctly', async () => { + it('displays recurring event data correctly', async () => { render( { expect(screen.getByTestId('today-button')).toBeInTheDocument(); }); }); - test('handles pagination and today button correctly', async () => { + it('handles pagination and today button correctly', async () => { render( { expect(screen.getByTestId('today-button')).toBeInTheDocument(); }); - test('handles pagination in recurring events view', async () => { + it('handles pagination in recurring events view', async () => { render( { }); }); - test('closes modal correctly', async () => { - const handleClose = jest.fn(); + it('closes modal correctly', async () => { + const handleClose = vi.fn(); render( Date: Thu, 26 Dec 2024 17:46:04 +0530 Subject: [PATCH 06/13] Refactor src/components/OrgSettings/ActionItemCategories/* from Jest to Vitest (#2916) * categoryModal tests migrated from jest to vitest * orgActionItemCategories tests migrated from jest to vitest * agendaCategoryCreateModal tests migrated from jest to vitest * agendaCategoryUpdateModal tests migrated from jest to vitest * organizationAgendaCategory tests migrated from jest to vitest * DeleteOrg tests migarated from jest to vitest * OrgProfileFieldSettings tests migrated from jest to vitest * OrgUpdate tests migrated from jest to vitest * setting back to default vitest config file --- ...yModal.test.tsx => CategoryModal.spec.tsx} | 28 +++++++--- ...t.tsx => OrgActionItemCategories.spec.tsx} | 33 +++++++++--- ...tsx => AgendaCategoryCreateModal.spec.tsx} | 28 ++++++---- ...tsx => AgendaCategoryUpdateModal.spec.tsx} | 30 +++++++---- ...sx => OrganizationAgendaCategory.spec.tsx} | 51 +++++++++++-------- ...{DeleteOrg.test.tsx => DeleteOrg.spec.tsx} | 51 +++++++++++++------ ...t.tsx => OrgProfileFieldSettings.spec.tsx} | 28 +++++++--- ...{OrgUpdate.test.tsx => OrgUpdate.spec.tsx} | 22 ++++++-- 8 files changed, 188 insertions(+), 83 deletions(-) rename src/components/OrgSettings/ActionItemCategories/{CategoryModal.test.tsx => CategoryModal.spec.tsx} (85%) rename src/components/OrgSettings/ActionItemCategories/{OrgActionItemCategories.test.tsx => OrgActionItemCategories.spec.tsx} (83%) rename src/components/OrgSettings/AgendaItemCategories/{AgendaCategoryCreateModal.test.tsx => AgendaCategoryCreateModal.spec.tsx} (76%) rename src/components/OrgSettings/AgendaItemCategories/{AgendaCategoryUpdateModal.test.tsx => AgendaCategoryUpdateModal.spec.tsx} (82%) rename src/components/OrgSettings/AgendaItemCategories/{OrganizationAgendaCategory.test.tsx => OrganizationAgendaCategory.spec.tsx} (82%) rename src/components/OrgSettings/General/DeleteOrg/{DeleteOrg.test.tsx => DeleteOrg.spec.tsx} (80%) rename src/components/OrgSettings/General/OrgProfileFieldSettings/{OrgProfileFieldSettings.test.tsx => OrgProfileFieldSettings.spec.tsx} (86%) rename src/components/OrgSettings/General/OrgUpdate/{OrgUpdate.test.tsx => OrgUpdate.spec.tsx} (90%) diff --git a/src/components/OrgSettings/ActionItemCategories/CategoryModal.test.tsx b/src/components/OrgSettings/ActionItemCategories/CategoryModal.spec.tsx similarity index 85% rename from src/components/OrgSettings/ActionItemCategories/CategoryModal.test.tsx rename to src/components/OrgSettings/ActionItemCategories/CategoryModal.spec.tsx index 39d4884e8b..e4b5663788 100644 --- a/src/components/OrgSettings/ActionItemCategories/CategoryModal.test.tsx +++ b/src/components/OrgSettings/ActionItemCategories/CategoryModal.spec.tsx @@ -14,11 +14,23 @@ import { MOCKS, MOCKS_ERROR } from './OrgActionItemCategoryMocks'; import type { InterfaceActionItemCategoryModal } from './CategoryModal'; import CategoryModal from './CategoryModal'; import { toast } from 'react-toastify'; - -jest.mock('react-toastify', () => ({ +import { vi } from 'vitest'; +/** + * This file contains unit tests for the `CategoryModal` component. + * + * The tests cover: + * - Proper rendering of the component in various scenarios, including `create` and `edit` modes, mock data, and error states. + * - Handling user interactions with form fields, such as updating the category name and toggling the `isDisabled` switch. + * - Ensuring form submissions trigger appropriate callbacks (e.g., `refetchCategories` and `hide`) and display correct toast notifications. + * - Simulating GraphQL query and mutation operations with mocked data to validate behavior in success and error cases. + * - Testing edge cases, such as submitting without changes, invalid inputs, and handling API errors gracefully. + * - Verifying proper integration of internationalization, Redux state, routing, and toast notifications for success and error feedback. + */ + +vi.mock('react-toastify', () => ({ toast: { - success: jest.fn(), - error: jest.fn(), + success: vi.fn(), + error: vi.fn(), }, })); @@ -37,8 +49,8 @@ const translations = { const categoryProps: InterfaceActionItemCategoryModal[] = [ { isOpen: true, - hide: jest.fn(), - refetchCategories: jest.fn(), + hide: vi.fn(), + refetchCategories: vi.fn(), orgId: 'orgId', mode: 'create', category: { @@ -51,8 +63,8 @@ const categoryProps: InterfaceActionItemCategoryModal[] = [ }, { isOpen: true, - hide: jest.fn(), - refetchCategories: jest.fn(), + hide: vi.fn(), + refetchCategories: vi.fn(), orgId: 'orgId', mode: 'edit', category: { diff --git a/src/components/OrgSettings/ActionItemCategories/OrgActionItemCategories.test.tsx b/src/components/OrgSettings/ActionItemCategories/OrgActionItemCategories.spec.tsx similarity index 83% rename from src/components/OrgSettings/ActionItemCategories/OrgActionItemCategories.test.tsx rename to src/components/OrgSettings/ActionItemCategories/OrgActionItemCategories.spec.tsx index 784d69325f..27eec94851 100644 --- a/src/components/OrgSettings/ActionItemCategories/OrgActionItemCategories.test.tsx +++ b/src/components/OrgSettings/ActionItemCategories/OrgActionItemCategories.spec.tsx @@ -12,19 +12,36 @@ import i18n from 'utils/i18nForTest'; import type { ApolloLink } from '@apollo/client'; import { MOCKS, MOCKS_EMPTY, MOCKS_ERROR } from './OrgActionItemCategoryMocks'; import OrgActionItemCategories from './OrgActionItemCategories'; - -jest.mock('react-toastify', () => ({ +import { vi } from 'vitest'; + +/** + * This file contains unit tests for the `OrgActionItemCategories` component. + * + * The tests cover: + * - Proper rendering of the component under different conditions, including scenarios with populated categories, empty categories, and API errors. + * - User interactions such as searching, filtering, sorting categories, and opening/closing modals for creating or editing categories. + * - Verification of GraphQL query and mutation behaviors using mock data, ensuring correct functionality in both success and error cases. + * - Handling edge cases like no input, invalid input, and form resets. + * - Integration tests for Redux state, routing, internationalization, and toast notifications. + * - Ensuring sorting functionality reflects the `createdAt` property both in ascending and descending order. + * - Testing the modal interactions for creating and editing categories, ensuring proper lifecycle (open/close) and state updates. + * - Checking the rendering of error messages and placeholders when no data is available or an error occurs. + * - Validation of search functionality for categories by name, including clearing the search input and using keyboard shortcuts like `Enter`. + */ + +vi.mock('react-toastify', () => ({ toast: { - success: jest.fn(), - error: jest.fn(), + success: vi.fn(), + error: vi.fn(), }, })); -jest.mock('@mui/x-date-pickers/DateTimePicker', () => { +vi.mock('@mui/x-date-pickers/DateTimePicker', async () => { + const dateTimePickerModule = await vi.importActual( + '@mui/x-date-pickers/DesktopDateTimePicker', + ); return { - DateTimePicker: jest.requireActual( - '@mui/x-date-pickers/DesktopDateTimePicker', - ).DesktopDateTimePicker, + DateTimePicker: dateTimePickerModule.DesktopDateTimePicker, }; }); diff --git a/src/components/OrgSettings/AgendaItemCategories/AgendaCategoryCreateModal.test.tsx b/src/components/OrgSettings/AgendaItemCategories/AgendaCategoryCreateModal.spec.tsx similarity index 76% rename from src/components/OrgSettings/AgendaItemCategories/AgendaCategoryCreateModal.test.tsx rename to src/components/OrgSettings/AgendaItemCategories/AgendaCategoryCreateModal.spec.tsx index da92dfd201..9b69a0e331 100644 --- a/src/components/OrgSettings/AgendaItemCategories/AgendaCategoryCreateModal.test.tsx +++ b/src/components/OrgSettings/AgendaItemCategories/AgendaCategoryCreateModal.spec.tsx @@ -1,30 +1,40 @@ import React from 'react'; import { render, screen, fireEvent } from '@testing-library/react'; -import userEvent from '@testing-library/user-event'; 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 AgendaCategoryCreateModal from './AgendaCategoryCreateModal'; +import { vi } from 'vitest'; +/** + * This file contains unit tests for the `AgendaCategoryCreateModal` component. + * + * The tests cover: + * - Rendering of the modal, ensuring all elements such as form fields, buttons, and labels are displayed correctly. + * - Behavior of form inputs, including updating the `formState` when the `name` and `description` fields are changed. + * - Proper invocation of the `createAgendaCategoryHandler` when the form is submitted. + * - Integration of Redux state, routing, localization (i18n), and date-picker utilities to ensure compatibility and proper rendering. + * - Validations for form controls to check user interactions, including typing and submitting the form. + * - Mock function verifications for `setFormState`, `hideCreateModal`, and other handlers to ensure state changes and actions are triggered appropriately. + * - Handling edge cases, such as empty fields or invalid data, ensuring graceful degradation of functionality. + */ const mockFormState = { name: 'Test Name', description: 'Test Description', createdBy: 'Test User', }; -const mockHideCreateModal = jest.fn(); -const mockSetFormState = jest.fn(); -const mockCreateAgendaCategoryHandler = jest.fn(); +const mockHideCreateModal = vi.fn(); +const mockSetFormState = vi.fn(); +const mockCreateAgendaCategoryHandler = vi.fn(); const mockT = (key: string): string => key; describe('AgendaCategoryCreateModal', () => { - test('renders modal correctly', () => { + it('renders modal correctly', () => { render( @@ -54,7 +64,7 @@ describe('AgendaCategoryCreateModal', () => { screen.getByTestId('createAgendaCategoryModalCloseBtn'), ).toBeInTheDocument(); }); - test('tests the condition for formState.name and formState.description', () => { + it('tests the condition for formState.name and formState.description', () => { const mockFormState = { name: 'Test Name', description: 'Test Description', @@ -97,7 +107,7 @@ describe('AgendaCategoryCreateModal', () => { description: 'New description', }); }); - test('calls createAgendaCategoryHandler when form is submitted', () => { + it('calls createAgendaCategoryHandler when form is submitted', () => { render( diff --git a/src/components/OrgSettings/AgendaItemCategories/AgendaCategoryUpdateModal.test.tsx b/src/components/OrgSettings/AgendaItemCategories/AgendaCategoryUpdateModal.spec.tsx similarity index 82% rename from src/components/OrgSettings/AgendaItemCategories/AgendaCategoryUpdateModal.test.tsx rename to src/components/OrgSettings/AgendaItemCategories/AgendaCategoryUpdateModal.spec.tsx index 168b97abd3..8be982271c 100644 --- a/src/components/OrgSettings/AgendaItemCategories/AgendaCategoryUpdateModal.test.tsx +++ b/src/components/OrgSettings/AgendaItemCategories/AgendaCategoryUpdateModal.spec.tsx @@ -7,24 +7,36 @@ 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 AgendaCategoryUpdateModal from './AgendaCategoryUpdateModal'; +import { vi } from 'vitest'; + +/** + * Unit tests for `AgendaCategoryUpdateModal`: + * + * - **Rendering**: Verifies key elements (e.g., text, buttons) render correctly. + * - **Close Button**: Ensures `hideUpdateModal` is called on close. + * - **Form Inputs**: Confirms `setFormState` updates with new `name` and `description`. + * - **Submission**: Checks `updateAgendaCategoryHandler` triggers on submit. + * - **Integration**: Validates compatibility with Redux, routing, i18n, and MUI date-picker. + * - **Mocks**: Ensures handlers (`setFormState`, `hideUpdateModal`, `updateAgendaCategoryHandler`) are called with correct arguments. + * + * This suite ensures component reliability and behavior consistency. + */ const mockFormState = { name: 'Test Name', description: 'Test Description', createdBy: 'Test User', }; -const mockHideUpdateModal = jest.fn(); -const mockSetFormState = jest.fn(); -const mockUpdateAgendaCategoryHandler = jest.fn(); +const mockHideUpdateModal = vi.fn(); +const mockSetFormState = vi.fn(); +const mockUpdateAgendaCategoryHandler = vi.fn(); const mockT = (key: string): string => key; describe('AgendaCategoryUpdateModal', () => { - test('renders modal correctly', () => { + it('renders modal correctly', () => { render( @@ -53,7 +65,7 @@ describe('AgendaCategoryUpdateModal', () => { ).toBeInTheDocument(); }); - test('calls hideUpdateModal when close button is clicked', () => { + it('calls hideUpdateModal when close button is clicked', () => { render( @@ -79,7 +91,7 @@ describe('AgendaCategoryUpdateModal', () => { expect(mockHideUpdateModal).toHaveBeenCalledTimes(1); }); - test('tests the condition for formState.name and formState.description', () => { + it('tests the condition for formState.name and formState.description', () => { const mockFormState = { name: 'Test Name', description: 'Test Description', @@ -123,7 +135,7 @@ describe('AgendaCategoryUpdateModal', () => { }); }); - test('calls updateAgendaCategoryHandler when form is submitted', () => { + it('calls updateAgendaCategoryHandler when form is submitted', () => { render( diff --git a/src/components/OrgSettings/AgendaItemCategories/OrganizationAgendaCategory.test.tsx b/src/components/OrgSettings/AgendaItemCategories/OrganizationAgendaCategory.spec.tsx similarity index 82% rename from src/components/OrgSettings/AgendaItemCategories/OrganizationAgendaCategory.test.tsx rename to src/components/OrgSettings/AgendaItemCategories/OrganizationAgendaCategory.spec.tsx index 56cb450647..a2bd6d0130 100644 --- a/src/components/OrgSettings/AgendaItemCategories/OrganizationAgendaCategory.test.tsx +++ b/src/components/OrgSettings/AgendaItemCategories/OrganizationAgendaCategory.spec.tsx @@ -7,9 +7,7 @@ import { waitForElementToBeRemoved, } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; -import 'jest-localstorage-mock'; import { MockedProvider } from '@apollo/client/testing'; -import 'jest-location-mock'; import { I18nextProvider } from 'react-i18next'; import { Provider } from 'react-redux'; import { BrowserRouter } from 'react-router-dom'; @@ -22,23 +20,38 @@ import { store } from 'state/store'; import { StaticMockLink } from 'utils/StaticMockLink'; import OrganizationAgendaCategory from './OrganizationAgendaCategory'; -import { - MOCKS_ERROR_AGENDA_ITEM_CATEGORY_LIST_QUERY, - MOCKS_ERROR_MUTATION, -} from './OrganizationAgendaCategoryErrorMocks'; +import { MOCKS_ERROR_AGENDA_ITEM_CATEGORY_LIST_QUERY } from './OrganizationAgendaCategoryErrorMocks'; import { MOCKS } from './OrganizationAgendaCategoryMocks'; - -jest.mock('react-toastify', () => ({ +import { vi } from 'vitest'; + +/** + * Unit Tests for `OrganizationAgendaCategory` Component + * + * - **Load Component**: Verifies successful rendering of key elements like `createAgendaCategory`. + * - **Error Handling**: Confirms error view appears when agenda category list query fails. + * - **Modal Functionality**: + * - Opens and closes the create agenda category modal. + * - Ensures `createAgendaCategoryModalCloseBtn` disappears on close. + * - **Create Agenda Category**: + * - Simulates filling the form and submission. + * - Verifies success toast on successful creation (`agendaCategoryCreated`). + * - **Integration**: Validates compatibility with Redux, Apollo, i18n, and MUI date-picker. + */ + +vi.mock('react-toastify', () => ({ toast: { - success: jest.fn(), - error: jest.fn(), + success: vi.fn(), + error: vi.fn(), }, })); -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useParams: () => ({ orgId: '123' }), -})); +vi.mock('react-router-dom', async () => { + const actual = await vi.importActual('react-router-dom'); + return { + ...actual, + useParams: () => ({ orgId: '123' }), + }; +}); async function wait(ms = 100): Promise { await act(() => { @@ -53,8 +66,6 @@ const link2 = new StaticMockLink( MOCKS_ERROR_AGENDA_ITEM_CATEGORY_LIST_QUERY, true, ); -const link3 = new StaticMockLink(MOCKS_ERROR_MUTATION, true); - const translations = { ...JSON.parse( JSON.stringify( @@ -70,7 +81,7 @@ describe('Testing Agenda Categories Component', () => { description: 'Test Description', createdBy: 'Test User', }; - test('Component loads correctly', async () => { + it('Component loads correctly', async () => { const { getByText } = render( @@ -90,7 +101,7 @@ describe('Testing Agenda Categories Component', () => { }); }); - test('render error component on unsuccessful agenda category list query', async () => { + it('render error component on unsuccessful agenda category list query', async () => { const { queryByText } = render( @@ -112,7 +123,7 @@ describe('Testing Agenda Categories Component', () => { }); }); - test('opens and closes the create agenda category modal', async () => { + it('opens and closes the create agenda category modal', async () => { render( @@ -145,7 +156,7 @@ describe('Testing Agenda Categories Component', () => { screen.queryByTestId('createAgendaCategoryModalCloseBtn'), ); }); - test('creates new agenda cagtegory', async () => { + it('creates new agenda cagtegory', async () => { render( diff --git a/src/components/OrgSettings/General/DeleteOrg/DeleteOrg.test.tsx b/src/components/OrgSettings/General/DeleteOrg/DeleteOrg.spec.tsx similarity index 80% rename from src/components/OrgSettings/General/DeleteOrg/DeleteOrg.test.tsx rename to src/components/OrgSettings/General/DeleteOrg/DeleteOrg.spec.tsx index 77ffe65c08..e911d195dc 100644 --- a/src/components/OrgSettings/General/DeleteOrg/DeleteOrg.test.tsx +++ b/src/components/OrgSettings/General/DeleteOrg/DeleteOrg.spec.tsx @@ -1,11 +1,9 @@ import React, { act } from 'react'; import { MockedProvider } from '@apollo/react-testing'; import { render, screen, waitFor } from '@testing-library/react'; -import 'jest-location-mock'; import { I18nextProvider } from 'react-i18next'; import { Provider } from 'react-redux'; import { BrowserRouter } from 'react-router-dom'; - import { DELETE_ORGANIZATION_MUTATION, REMOVE_SAMPLE_ORGANIZATION_MUTATION, @@ -17,6 +15,24 @@ import DeleteOrg from './DeleteOrg'; import { ToastContainer, toast } from 'react-toastify'; import { IS_SAMPLE_ORGANIZATION_QUERY } from 'GraphQl/Queries/Queries'; import useLocalStorage from 'utils/useLocalstorage'; +import { vi } from 'vitest'; + +/** + * Unit Tests for `DeleteOrg` Component + * + * - **Toggle Modal**: Verifies the ability to open and close the delete organization modal for both sample and non-sample organizations. + * - **Delete Organization**: + * - Simulates deleting a non-sample organization and ensures the correct GraphQL mutation is triggered. + * - Confirms navigation occurs after a sample organization is deleted. + * - **Error Handling**: + * - Handles errors from `DELETE_ORGANIZATION_MUTATION` and `IS_SAMPLE_ORGANIZATION_QUERY`. + * - Verifies `toast.error` is called with appropriate error messages when mutations fail. + * - **Mocks**: + * - Mocks GraphQL queries and mutations using `StaticMockLink` for different success and error scenarios. + * - Uses `useParams` to simulate URL parameters (`orgId`). + * - Mocks `useNavigate` to check navigation after successful deletion. + * - **Toast Notifications**: Ensures `toast.success` or `toast.error` is triggered based on success or failure of actions. + */ const { setItem } = useLocalStorage(); @@ -98,13 +114,16 @@ const MOCKS_WITH_ERROR = [ }, ]; -const mockNavgatePush = jest.fn(); +const mockNavgatePush = vi.fn(); let mockURL = '123'; -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useParams: () => ({ orgId: mockURL }), - useNavigate: () => mockNavgatePush, -})); +vi.mock('react-router-dom', async () => { + const actual = await vi.importActual('react-router-dom'); + return { + ...actual, + useParams: () => ({ orgId: mockURL }), + useNavigate: () => mockNavgatePush, + }; +}); const link = new StaticMockLink(MOCKS, true); const link2 = new StaticMockLink(MOCKS_WITH_ERROR, true); @@ -114,7 +133,7 @@ afterEach(() => { }); describe('Delete Organization Component', () => { - test('should be able to Toggle Delete Organization Modal', async () => { + it('should be able to Toggle Delete Organization Modal', async () => { mockURL = '456'; setItem('SuperAdmin', true); await act(async () => { @@ -143,7 +162,7 @@ describe('Delete Organization Component', () => { }); }); - test('should be able to Toggle Delete Organization Modal When Organization is Sample Organization', async () => { + it('should be able to Toggle Delete Organization Modal When Organization is Sample Organization', async () => { mockURL = '123'; setItem('SuperAdmin', true); await act(async () => { @@ -173,7 +192,7 @@ describe('Delete Organization Component', () => { }); }); - test('Delete organization functionality should work properly', async () => { + it('Delete organization functionality should work properly', async () => { mockURL = '456'; setItem('SuperAdmin', true); await act(async () => { @@ -201,7 +220,7 @@ describe('Delete Organization Component', () => { }); }); - test('Delete organization functionality should work properly for sample org', async () => { + it('Delete organization functionality should work properly for sample org', async () => { mockURL = '123'; setItem('SuperAdmin', true); await act(async () => { @@ -234,10 +253,10 @@ describe('Delete Organization Component', () => { expect(mockNavgatePush).toHaveBeenCalledWith('/orglist'); }); - test('Error handling for IS_SAMPLE_ORGANIZATION_QUERY mock', async () => { + it('Error handling for IS_SAMPLE_ORGANIZATION_QUERY mock', async () => { mockURL = '123'; setItem('SuperAdmin', true); - jest.spyOn(toast, 'error'); + vi.spyOn(toast, 'error'); await act(async () => { render( @@ -270,10 +289,10 @@ describe('Delete Organization Component', () => { }); }); - test('Error handling for DELETE_ORGANIZATION_MUTATION mock', async () => { + it('Error handling for DELETE_ORGANIZATION_MUTATION mock', async () => { mockURL = '456'; setItem('SuperAdmin', true); - jest.spyOn(toast, 'error'); + vi.spyOn(toast, 'error'); await act(async () => { render( diff --git a/src/components/OrgSettings/General/OrgProfileFieldSettings/OrgProfileFieldSettings.test.tsx b/src/components/OrgSettings/General/OrgProfileFieldSettings/OrgProfileFieldSettings.spec.tsx similarity index 86% rename from src/components/OrgSettings/General/OrgProfileFieldSettings/OrgProfileFieldSettings.test.tsx rename to src/components/OrgSettings/General/OrgProfileFieldSettings/OrgProfileFieldSettings.spec.tsx index 8db8773381..45bdfbc122 100644 --- a/src/components/OrgSettings/General/OrgProfileFieldSettings/OrgProfileFieldSettings.test.tsx +++ b/src/components/OrgSettings/General/OrgProfileFieldSettings/OrgProfileFieldSettings.spec.tsx @@ -12,6 +12,18 @@ import { } from 'GraphQl/Mutations/mutations'; import { ORGANIZATION_CUSTOM_FIELDS } from 'GraphQl/Queries/Queries'; import { ToastContainer, toast } from 'react-toastify'; +import { vi } from 'vitest'; + +/** + * Unit Tests for `OrgProfileFieldSettings` Component + * + * - Saving Custom Field: Verifies success and failure of adding a custom field. + * - Typing Custom Field Name: Ensures input updates correctly. + * - Handling No Custom Fields: Displays message when no custom fields exist. + * - Removing Custom Field: Verifies success and failure of removing a custom field. + * - Error Handling: Ensures error messages for GraphQL mutations are displayed. + * - Mock GraphQL Responses: Mocks GraphQL queries and mutations for different scenarios. + */ const MOCKS = [ { @@ -161,7 +173,7 @@ async function wait(ms = 100): Promise { } describe('Testing Save Button', () => { - test('Testing Failure Case For Fetching Custom field', async () => { + it('Testing Failure Case For Fetching Custom field', async () => { render( { screen.queryByText('Failed to fetch custom field'), ).toBeInTheDocument(); }); - test('Saving Organization Custom Field', async () => { + it('Saving Organization Custom Field', async () => { render( @@ -195,7 +207,7 @@ describe('Testing Save Button', () => { expect(screen.queryByText('Field added successfully')).toBeInTheDocument(); }); - test('Testing Failure Case For Saving Custom Field', async () => { + it('Testing Failure Case For Saving Custom Field', async () => { render( @@ -218,7 +230,7 @@ describe('Testing Save Button', () => { ).toBeInTheDocument(); }); - test('Testing Typing Organization Custom Field Name', async () => { + it('Testing Typing Organization Custom Field Name', async () => { const { getByTestId } = render( @@ -232,7 +244,7 @@ describe('Testing Save Button', () => { const fieldNameInput = getByTestId('customFieldInput'); userEvent.type(fieldNameInput, 'Age'); }); - test('When No Custom Data is Present', async () => { + it('When No Custom Data is Present', async () => { const { getByText } = render( @@ -244,7 +256,7 @@ describe('Testing Save Button', () => { await wait(); expect(getByText('No custom fields available')).toBeInTheDocument(); }); - test('Testing Remove Custom Field Button', async () => { + it('Testing Remove Custom Field Button', async () => { render( @@ -262,8 +274,8 @@ describe('Testing Save Button', () => { ).toBeInTheDocument(); }); - test('Testing Failure Case For Removing Custom Field', async () => { - const toastSpy = jest.spyOn(toast, 'error'); + it('Testing Failure Case For Removing Custom Field', async () => { + const toastSpy = vi.spyOn(toast, 'error'); render( diff --git a/src/components/OrgSettings/General/OrgUpdate/OrgUpdate.test.tsx b/src/components/OrgSettings/General/OrgUpdate/OrgUpdate.spec.tsx similarity index 90% rename from src/components/OrgSettings/General/OrgUpdate/OrgUpdate.test.tsx rename to src/components/OrgSettings/General/OrgUpdate/OrgUpdate.spec.tsx index 6304bb3ec9..2a6496d69a 100644 --- a/src/components/OrgSettings/General/OrgUpdate/OrgUpdate.test.tsx +++ b/src/components/OrgSettings/General/OrgUpdate/OrgUpdate.spec.tsx @@ -11,6 +11,18 @@ import { MOCKS_ERROR_ORGLIST, MOCKS_ERROR_UPDATE_ORGLIST, } from './OrgUpdateMocks'; +import { vi } from 'vitest'; + +/** + * Unit Tests for `OrgUpdate` Component + * + * - Rendering Component with Props: Verifies if labels and input fields are correctly rendered based on mock data. + * - Updating Organization: Ensures the form updates with new data and saves changes correctly. + * - Error Handling: Verifies error messages when organization cannot be found or updated. + * - Toast on Error: Verifies that an error toast is shown when the update fails. + * - Form Field Values: Ensures form values are correctly displayed and updated. + * - GraphQL Mock Responses: Mocks GraphQL responses for success and error scenarios. + */ const link = new StaticMockLink(MOCKS, true); @@ -45,9 +57,9 @@ describe('Testing Organization Update', () => { isVisible: true, }; - global.alert = jest.fn(); + global.alert = vi.fn(); - test('should render props and text elements test for the page component along with mock data', async () => { + it('should render props and text elements test for the page component along with mock data', async () => { act(() => { render( @@ -95,7 +107,7 @@ describe('Testing Organization Update', () => { expect(isVisible).not.toBeChecked(); }); - test('Should Update organization properly', async () => { + it('Should Update organization properly', async () => { await act(async () => { render( @@ -168,7 +180,7 @@ describe('Testing Organization Update', () => { expect(isVisible).toBeChecked(); }); - test('Should render error occured text when Organization Could not be found', async () => { + it('Should render error occured text when Organization Could not be found', async () => { act(() => { render( @@ -182,7 +194,7 @@ describe('Testing Organization Update', () => { expect(screen.getByText(/Mock Graphql Error/i)).toBeInTheDocument(); }); - test('Should show error occured toast when Organization could not be updated', async () => { + it('Should show error occured toast when Organization could not be updated', async () => { await act(async () => { render( From 9cdb9ea94bc2fd540712fc592a3c4598d92f0493 Mon Sep 17 00:00:00 2001 From: Pranav Nathe <93403830+pranavnathe@users.noreply.github.com> Date: Thu, 26 Dec 2024 17:51:17 +0530 Subject: [PATCH 07/13] Refactor IconComponent from Jest to Vitest #2836 (#2919) --- .../{IconComponent.test.tsx => IconComponent.spec.tsx} | 5 +++++ 1 file changed, 5 insertions(+) rename src/components/IconComponent/{IconComponent.test.tsx => IconComponent.spec.tsx} (94%) diff --git a/src/components/IconComponent/IconComponent.test.tsx b/src/components/IconComponent/IconComponent.spec.tsx similarity index 94% rename from src/components/IconComponent/IconComponent.test.tsx rename to src/components/IconComponent/IconComponent.spec.tsx index 3ba6ccd84d..b398fe7986 100644 --- a/src/components/IconComponent/IconComponent.test.tsx +++ b/src/components/IconComponent/IconComponent.spec.tsx @@ -1,6 +1,7 @@ import React from 'react'; import { render, screen } from '@testing-library/react'; import IconComponent from './IconComponent'; +import { describe, it, expect } from 'vitest'; const screenTestIdMap: Record> = { MyOrganizations: { @@ -83,6 +84,10 @@ const screenTestIdMap: Record> = { name: 'My Pledges', testId: 'Icon-Component-My-Pledges', }, + LeaveOrganization: { + name: 'Leave Organization', + testId: 'Icon-Component-Leave-Organization', + }, Volunteer: { name: 'Volunteer', testId: 'Icon-Component-Volunteer', From b466e3732bdd162df06589ec454021cbf364845c Mon Sep 17 00:00:00 2001 From: Devender singh shekhawat <50149675+devender18@users.noreply.github.com> Date: Thu, 26 Dec 2024 17:55:52 +0530 Subject: [PATCH 08/13] refactor css files in src/screens/LoginPage(fixes #2509) (#2918) * refactor css files in src/screens/LoginPage(fixes #2509) * changes as per code rabit --- src/screens/LoginPage/LoginPage.module.css | 269 -------------------- src/screens/LoginPage/LoginPage.tsx | 2 +- src/style/app.module.css | 278 +++++++++++++++++++++ 3 files changed, 279 insertions(+), 270 deletions(-) delete mode 100644 src/screens/LoginPage/LoginPage.module.css diff --git a/src/screens/LoginPage/LoginPage.module.css b/src/screens/LoginPage/LoginPage.module.css deleted file mode 100644 index 6f58138c34..0000000000 --- a/src/screens/LoginPage/LoginPage.module.css +++ /dev/null @@ -1,269 +0,0 @@ -.login_background { - min-height: 100vh; -} - -.communityLogo { - object-fit: contain; -} - -.row .left_portion { - display: flex; - justify-content: center; - align-items: center; - flex-direction: column; - height: 100vh; -} - -.selectOrgText input { - outline: none !important; -} - -.row .left_portion .inner .palisadoes_logo { - width: 600px; - height: auto; -} - -.row .right_portion { - min-height: 100vh; - position: relative; - overflow-y: scroll; - display: flex; - flex-direction: column; - justify-content: center; - padding: 1rem 2.5rem; - background: var(--bs-white); -} - -.row .right_portion::-webkit-scrollbar { - display: none; -} - -.row .right_portion .langChangeBtn { - margin: 0; - position: absolute; - top: 1rem; - left: 1rem; -} - -.langChangeBtnStyle { - width: 7.5rem; - height: 2.2rem; - padding: 0; -} - -.row .right_portion .talawa_logo { - height: 5rem; - width: 5rem; - display: block; - margin: 1.5rem auto 1rem; - -webkit-animation: zoomIn 0.3s ease-in-out; - animation: zoomIn 0.3s ease-in-out; -} - -.row .orText { - display: block; - position: absolute; - top: 0; - left: calc(50% - 2.6rem); - margin: 0 auto; - padding: 0.35rem 2rem; - z-index: 100; - background: var(--bs-white); - color: var(--bs-secondary); -} - -.email_button { - position: absolute; - z-index: 10; - bottom: 0; - right: 0; - height: 100%; - display: flex; - background-color: var(--search-button-bg); - border-color: var(--search-button-border); - justify-content: center; - align-items: center; -} - -.login_btn { - background-color: var(--search-button-bg); - border-color: var(--search-button-border); - margin-top: 1rem; - /* mt-3: Bootstrap margin spacing utility (3 = 1rem) */ - margin-bottom: 1rem; - /* mb-3: Bootstrap margin spacing utility (3 = 1rem) */ - width: 100%; -} - -.reg_btn { - background-color: var(--dropdown-border-color); - border-color: var(--dropdown-border-color); - margin-top: 1rem; - color: white; - /* mt-3: Bootstrap margin spacing utility (3 = 1rem) */ - margin-bottom: 1rem; - /* mb-3: Bootstrap margin spacing utility (3 = 1rem) */ - width: 100%; -} - -@media (max-width: 992px) { - .row .left_portion { - padding: 0 2rem; - } - - .row .left_portion .inner .palisadoes_logo { - width: 100%; - } -} - -@media (max-width: 769px) { - .row { - flex-direction: column-reverse; - } - - .row .right_portion, - .row .left_portion { - height: unset; - } - - .row .right_portion { - min-height: 100vh; - overflow-y: unset; - } - - .row .left_portion .inner { - display: flex; - justify-content: center; - } - - .row .left_portion .inner .palisadoes_logo { - height: 70px; - width: unset; - position: absolute; - margin: 0.5rem; - top: 0; - right: 0; - z-index: 100; - } - - .row .left_portion .inner p { - margin-bottom: 0; - padding: 1rem; - } - - .socialIcons { - margin-bottom: 1rem; - } -} - -@media (max-width: 577px) { - .row .right_portion { - padding: 1rem 1rem 0 1rem; - } - - .row .right_portion .langChangeBtn { - position: absolute; - margin: 1rem; - left: 0; - top: 0; - } - - .marginTopForReg { - margin-top: 4rem !important; - } - - .row .right_portion .talawa_logo { - height: 120px; - margin: 0 auto 2rem auto; - } - - .socialIcons { - margin-bottom: 1rem; - } -} - -.active_tab { - -webkit-animation: fadeIn 0.3s ease-in-out; - animation: fadeIn 0.3s ease-in-out; -} - -@-webkit-keyframes zoomIn { - 0% { - opacity: 0; - -webkit-transform: scale(0.5); - transform: scale(0.5); - } - - 100% { - opacity: 1; - -webkit-transform: scale(1); - transform: scale(1); - } -} - -@keyframes zoomIn { - 0% { - opacity: 0; - -webkit-transform: scale(0.5); - transform: scale(0.5); - } - - 100% { - opacity: 1; - -webkit-transform: scale(1); - transform: scale(1); - } -} - -@-webkit-keyframes fadeIn { - 0% { - opacity: 0; - -webkit-transform: translateY(2rem); - transform: translateY(2rem); - } - - 100% { - opacity: 1; - -webkit-transform: translateY(0); - transform: translateY(0); - } -} - -@keyframes fadeIn { - 0% { - opacity: 0; - -webkit-transform: translateY(2rem); - transform: translateY(2rem); - } - - 100% { - opacity: 1; - -webkit-transform: translateY(0); - transform: translateY(0); - } -} - -.socialIcons { - display: flex; - gap: 16px; - justify-content: center; -} - -.password_checks { - display: flex; - justify-content: space-between; - align-items: flex-start; - flex-direction: column; -} - -.password_check_element { - margin-top: -10px; -} - -.password_check_element_top { - margin-top: 18px; -} - -.password_check_element_bottom { - margin-bottom: -20px; -} diff --git a/src/screens/LoginPage/LoginPage.tsx b/src/screens/LoginPage/LoginPage.tsx index 180009926c..605811c834 100644 --- a/src/screens/LoginPage/LoginPage.tsx +++ b/src/screens/LoginPage/LoginPage.tsx @@ -30,7 +30,7 @@ import LoginPortalToggle from 'components/LoginPortalToggle/LoginPortalToggle'; import { errorHandler } from 'utils/errorHandler'; import useLocalStorage from 'utils/useLocalstorage'; import { socialMediaLinks } from '../../constants'; -import styles from './LoginPage.module.css'; +import styles from 'style/app.module.css'; import type { InterfaceQueryOrganizationListObject } from 'utils/interfaces'; import { Autocomplete, TextField } from '@mui/material'; import useSession from 'utils/useSession'; diff --git a/src/style/app.module.css b/src/style/app.module.css index db6b79477c..3bc46315f9 100644 --- a/src/style/app.module.css +++ b/src/style/app.module.css @@ -1718,6 +1718,157 @@ form > input { z-index: 1; } +.login_background { + min-height: 100vh; +} + +.communityLogo { + object-fit: contain; +} + +.row .left_portion { + display: flex; + justify-content: center; + align-items: center; + flex-direction: column; + height: 100vh; +} + +.selectOrgText input { + outline: none !important; +} + +.row .left_portion .inner .palisadoes_logo { + width: 600px; + height: auto; +} + +.row .right_portion { + min-height: 100vh; + position: relative; + overflow-y: scroll; + display: flex; + flex-direction: column; + justify-content: center; + padding: 1rem 2.5rem; + background: var(--bs-white); +} + +.row .right_portion::-webkit-scrollbar { + width: 8px; +} + +.row .right_portion::-webkit-scrollbar-track { + background: transparent; +} + +.row .right_portion::-webkit-scrollbar-thumb { + background-color: rgba(0, 0, 0, 0.2); + border-radius: 4px; +} + +.row .right_portion .langChangeBtn { + margin: 0; + position: absolute; + top: 1rem; + left: 1rem; +} + +.langChangeBtnStyle { + width: 7.5rem; + height: 2.2rem; + padding: 0; +} + +.talawa_logo { + height: clamp(3rem, 8vw, 5rem); + width: auto; + aspect-ratio: 1; + display: block; + margin: 1.5rem auto 1rem; + @media (prefers-reduced-motion: no-preference) { + -webkit-animation: zoomIn 0.3s ease-in-out; + animation: zoomIn 0.3s ease-in-out; + } +} + +.row .orText { + display: block; + position: absolute; + top: 0; + left: calc(50% - 2.6rem); + margin: 0 auto; + padding: 0.35rem 2rem; + z-index: 100; + background: var(--bs-white); + color: var(--bs-secondary); +} + +.email_button { + position: absolute; + z-index: 10; + bottom: 0; + right: 0; + height: 100%; + display: flex; + background-color: var(--search-button-bg); + border-color: var(--search-button-border); + justify-content: center; + align-items: center; +} + +.login_btn { + background-color: var(--search-button-bg); + border-color: var(--search-button-border); + margin-top: 1rem; + margin-bottom: 1rem; + width: 100%; + transition: background-color 0.2s ease; + cursor: pointer; +} + +.reg_btn { + background-color: var(--dropdown-border-color); + border-color: var(--dropdown-border-color); + margin-top: 1rem; + color: white; + margin-bottom: 1rem; + width: 100%; + transition: background-color 0.2s ease; + cursor: pointer; +} + +.active_tab { + -webkit-animation: fadeIn 0.3s ease-in-out; + animation: fadeIn 0.3s ease-in-out; +} + +.socialIcons { + display: flex; + gap: 16px; + justify-content: center; +} + +.password_checks { + display: flex; + justify-content: space-between; + align-items: flex-start; + flex-direction: column; + gap: var(--spacing-md, 1rem); +} + +.password_check_element { + padding: var(--spacing-sm, 0.5rem) 0; +} + +.password_check_element_top { + margin-top: var(--spacing-lg, 1.125rem); +} + +.password_check_element_bottom { + margin-bottom: var(--spacing-lg, 1.25rem); +} + @media (max-width: 450px) { .itemCardOrgList .loadingWrapper { height: unset; @@ -1887,6 +2038,133 @@ form > input { } } +@media (max-width: 992px) { + .row .left_portion { + padding: 0 2rem; + } + .row .left_portion .inner .palisadoes_logo { + width: 100%; + } +} + +@media (max-width: 769px) { + .row { + flex-direction: column-reverse; + } + .row .right_portion, + .row .left_portion { + height: unset; + } + .row .right_portion { + min-height: 100vh; + overflow-y: unset; + } + .row .left_portion .inner { + display: flex; + justify-content: center; + } + .row .left_portion .inner .palisadoes_logo { + height: 70px; + width: unset; + position: absolute; + margin: 0.5rem; + top: 0; + right: 0; + z-index: 100; + } + .row .left_portion .inner p { + margin-bottom: 0; + padding: 1rem; + } + .socialIcons { + margin-bottom: 1rem; + } +} + +@media (max-width: 577px) { + .row .right_portion { + padding: 1rem 1rem 0 1rem; + } + .row .right_portion .langChangeBtn { + position: absolute; + margin: 1rem; + left: 0; + top: 0; + } + .marginTopForReg { + margin-top: 4rem !important; + } + .row .right_portion .talawa_logo { + height: 120px; + margin: 0 auto 2rem auto; + } + .socialIcons { + margin-bottom: 1rem; + } +} + +@media (prefers-reduced-motion: reduce) { + .talawa_logo { + animation: none; + } + + .active_tab { + animation: none; + } +} + +@-webkit-keyframes zoomIn { + 0% { + opacity: 0; + -webkit-transform: scale(0.5); + transform: scale(0.5); + } + 100% { + opacity: 1; + -webkit-transform: scale(1); + transform: scale(1); + } +} + +@keyframes zoomIn { + 0% { + opacity: 0; + -webkit-transform: scale(0.5); + transform: scale(0.5); + } + 100% { + opacity: 1; + -webkit-transform: scale(1); + transform: scale(1); + } +} + +@-webkit-keyframes fadeIn { + 0% { + opacity: 0; + -webkit-transform: translateY(2rem); + transform: translateY(2rem); + } + 100% { + opacity: 1; + -webkit-transform: translateY(0); + transform: translateY(0); + } +} + +@keyframes fadeIn { + 0% { + opacity: 0; + -webkit-transform: translateY(2rem); + transform: translateY(2rem); + } + 100% { + opacity: 1; + -webkit-transform: translateY(0); + transform: translateY(0); + } +} + /* For mobile devices */ @media (max-width: 520px) { From 7a4eac87c8bfcbd540ceb580311d114f2c77b8d0 Mon Sep 17 00:00:00 2001 From: Pranav Nathe <93403830+pranavnathe@users.noreply.github.com> Date: Thu, 26 Dec 2024 17:56:57 +0530 Subject: [PATCH 09/13] Refactor OrgDelete.test.tsx from Jest to Vitest #2812 (#2921) --- .../OrgDelete/{OrgDelete.test.tsx => OrgDelete.spec.tsx} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename src/components/OrgDelete/{OrgDelete.test.tsx => OrgDelete.spec.tsx} (86%) diff --git a/src/components/OrgDelete/OrgDelete.test.tsx b/src/components/OrgDelete/OrgDelete.spec.tsx similarity index 86% rename from src/components/OrgDelete/OrgDelete.test.tsx rename to src/components/OrgDelete/OrgDelete.spec.tsx index b9b9ca2572..23f8dcdde5 100644 --- a/src/components/OrgDelete/OrgDelete.test.tsx +++ b/src/components/OrgDelete/OrgDelete.spec.tsx @@ -3,7 +3,7 @@ import { render, screen } from '@testing-library/react'; import type { NormalizedCacheObject } from '@apollo/client'; import { ApolloClient, ApolloProvider, InMemoryCache } from '@apollo/client'; import { I18nextProvider } from 'react-i18next'; - +import { describe, it, expect } from 'vitest'; import OrgDelete from './OrgDelete'; import i18nForTest from 'utils/i18nForTest'; import { BACKEND_URL } from 'Constant/constant'; @@ -14,7 +14,7 @@ const client: ApolloClient = new ApolloClient({ }); describe('Testing Organization People List Card', () => { - test('should render props and text elements test for the page component', () => { + it('should render props and text elements test for the page component', () => { render( From 13f16b9a047c708a7aa2f37dee77436fe24338f3 Mon Sep 17 00:00:00 2001 From: Syed Ali Ul Hasan Date: Thu, 26 Dec 2024 17:58:13 +0530 Subject: [PATCH 10/13] refactored src/components/ProfileDropdown/ from jest to vitest, added test cases (#2922) --- ...down.test.tsx => ProfileDropdown.spec.tsx} | 139 ++++++++++++++++-- 1 file changed, 128 insertions(+), 11 deletions(-) rename src/components/ProfileDropdown/{ProfileDropdown.test.tsx => ProfileDropdown.spec.tsx} (52%) diff --git a/src/components/ProfileDropdown/ProfileDropdown.test.tsx b/src/components/ProfileDropdown/ProfileDropdown.spec.tsx similarity index 52% rename from src/components/ProfileDropdown/ProfileDropdown.test.tsx rename to src/components/ProfileDropdown/ProfileDropdown.spec.tsx index 785f33ee92..06883768e6 100644 --- a/src/components/ProfileDropdown/ProfileDropdown.test.tsx +++ b/src/components/ProfileDropdown/ProfileDropdown.spec.tsx @@ -1,17 +1,29 @@ import React, { act } from 'react'; -import { render, screen } from '@testing-library/react'; +import { render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { BrowserRouter } from 'react-router-dom'; import ProfileDropdown from './ProfileDropdown'; -import 'jest-localstorage-mock'; import { MockedProvider } from '@apollo/react-testing'; import { REVOKE_REFRESH_TOKEN } from 'GraphQl/Mutations/mutations'; import useLocalStorage from 'utils/useLocalstorage'; import { I18nextProvider } from 'react-i18next'; import i18nForTest from 'utils/i18nForTest'; import { GET_COMMUNITY_SESSION_TIMEOUT_DATA } from 'GraphQl/Queries/Queries'; +import { vi } from 'vitest'; const { setItem } = useLocalStorage(); + +const mockNavigate = vi.fn(); + +// Mock useNavigate hook +vi.mock('react-router-dom', async () => { + const actual = await vi.importActual('react-router-dom'); + return { + ...actual, + useNavigate: () => mockNavigate, + }; +}); + const MOCKS = [ { request: { @@ -38,13 +50,13 @@ const MOCKS = [ }, ]; -jest.mock('react-toastify', () => ({ +vi.mock('react-toastify', () => ({ toast: { - success: jest.fn(), - warn: jest.fn(), - error: jest.fn(), + success: vi.fn(), + warn: vi.fn(), + error: vi.fn(), }, - clear: jest.fn(), + clear: vi.fn(), })); beforeEach(() => { @@ -60,11 +72,11 @@ beforeEach(() => { }); afterEach(() => { - jest.clearAllMocks(); + vi.clearAllMocks(); localStorage.clear(); }); afterEach(() => { - jest.clearAllMocks(); + vi.clearAllMocks(); localStorage.clear(); }); @@ -130,19 +142,124 @@ describe('ProfileDropdown Component', () => { describe('Member screen routing testing', () => { test('member screen', async () => { + setItem('SuperAdmin', false); + setItem('AdminFor', []); + render( - + + + , ); + await act(async () => { userEvent.click(screen.getByTestId('togDrop')); }); + await act(async () => { + userEvent.click(screen.getByTestId('profileBtn')); + }); + + expect(mockNavigate).toHaveBeenCalledWith('/user/settings'); + }); + }); + + test('handles error when revoking refresh token during logout', async () => { + // Mock the revokeRefreshToken mutation to throw an error + const MOCKS_WITH_ERROR = [ + { + request: { + query: REVOKE_REFRESH_TOKEN, + }, + error: new Error('Failed to revoke refresh token'), + }, + ]; + + const consoleErrorMock = vi + .spyOn(console, 'error') + .mockImplementation(() => {}); + + render( + + + + + , + ); + + // Open the dropdown + await act(async () => { + userEvent.click(screen.getByTestId('togDrop')); + }); + + // Click the logout button + await act(async () => { + userEvent.click(screen.getByTestId('logoutBtn')); + }); + + // Wait for any pending promises + await waitFor(() => { + // Assert that console.error was called + expect(consoleErrorMock).toHaveBeenCalledWith( + 'Error revoking refresh token:', + expect.any(Error), + ); + }); + + // Cleanup mock + consoleErrorMock.mockRestore(); + }); + + test('navigates to /user/settings for a user', async () => { + setItem('SuperAdmin', false); + setItem('AdminFor', []); + + render( + + + + + + + , + ); + + await act(async () => { + userEvent.click(screen.getByTestId('togDrop')); + }); + + await act(async () => { userEvent.click(screen.getByTestId('profileBtn')); - expect(global.window.location.pathname).toBe('/user/settings'); }); + + expect(mockNavigate).toHaveBeenCalledWith('/user/settings'); + }); + + test('navigates to /member/:userID for non-user roles', async () => { + setItem('SuperAdmin', true); // Set as admin + setItem('id', '123'); + + render( + + + + + + + , + ); + + await act(async () => { + userEvent.click(screen.getByTestId('togDrop')); + }); + + await act(async () => { + userEvent.click(screen.getByTestId('profileBtn')); + }); + + expect(mockNavigate).toHaveBeenCalledWith('/member/123'); }); }); From 1475df08894431d5b1ecb8135d7c0927efcb1645 Mon Sep 17 00:00:00 2001 From: Ramneet Singh <144323012+Ramneet04@users.noreply.github.com> Date: Thu, 26 Dec 2024 18:13:29 +0530 Subject: [PATCH 11/13] Refactored src/components/OrgPeopleListCard/OrgPeopleListCard.test.tsx #2814 (#2920) * file name changed * migration done --- ...{OrgPeopleListCard.test.tsx => OrgPeopleListCard.spec.tsx} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename src/components/OrgPeopleListCard/{OrgPeopleListCard.test.tsx => OrgPeopleListCard.spec.tsx} (96%) diff --git a/src/components/OrgPeopleListCard/OrgPeopleListCard.test.tsx b/src/components/OrgPeopleListCard/OrgPeopleListCard.spec.tsx similarity index 96% rename from src/components/OrgPeopleListCard/OrgPeopleListCard.test.tsx rename to src/components/OrgPeopleListCard/OrgPeopleListCard.spec.tsx index 7cee31107f..0fb2c39599 100644 --- a/src/components/OrgPeopleListCard/OrgPeopleListCard.test.tsx +++ b/src/components/OrgPeopleListCard/OrgPeopleListCard.spec.tsx @@ -9,7 +9,7 @@ import { REMOVE_MEMBER_MUTATION } from 'GraphQl/Mutations/mutations'; import i18nForTest from 'utils/i18nForTest'; import { BrowserRouter } from 'react-router-dom'; import { StaticMockLink } from 'utils/StaticMockLink'; - +import { describe, test, expect, vi } from 'vitest'; const MOCKS = [ { request: { @@ -41,7 +41,7 @@ describe('Testing Organization People List Card', () => { toggleRemoveModal: () => true, id: '1', }; - global.alert = jest.fn(); + global.alert = vi.fn(); test('should render props and text elements test for the page component', async () => { global.confirm = (): boolean => true; From 732f8c97204d602956748963f103949e747ab5f7 Mon Sep 17 00:00:00 2001 From: Nikhil Raj <125121367+hustlernik@users.noreply.github.com> Date: Thu, 26 Dec 2024 18:51:49 +0530 Subject: [PATCH 12/13] [REFACTOR]: Jest to Vitest migration for UserListCard.test.tsx (#2924) * refactor: jest to vitest for UserListCard.test.tsx * unchange tagTemplate.ts --- ...istCard.test.tsx => UserListCard.spec.tsx} | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) rename src/components/UserListCard/{UserListCard.test.tsx => UserListCard.spec.tsx} (77%) diff --git a/src/components/UserListCard/UserListCard.test.tsx b/src/components/UserListCard/UserListCard.spec.tsx similarity index 77% rename from src/components/UserListCard/UserListCard.test.tsx rename to src/components/UserListCard/UserListCard.spec.tsx index e2ad552507..6a3b2d42d8 100644 --- a/src/components/UserListCard/UserListCard.test.tsx +++ b/src/components/UserListCard/UserListCard.spec.tsx @@ -1,5 +1,5 @@ -import React, { act } from 'react'; -import { render, screen } from '@testing-library/react'; +import React from 'react'; +import { render, screen, act } from '@testing-library/react'; import { MockedProvider } from '@apollo/react-testing'; import userEvent from '@testing-library/user-event'; import { I18nextProvider } from 'react-i18next'; @@ -9,6 +9,7 @@ import { ADD_ADMIN_MUTATION } from 'GraphQl/Mutations/mutations'; import i18nForTest from 'utils/i18nForTest'; import { BrowserRouter } from 'react-router-dom'; import { StaticMockLink } from 'utils/StaticMockLink'; +import { vi, describe, it, beforeEach } from 'vitest'; const MOCKS = [ { @@ -30,17 +31,15 @@ const MOCKS = [ const link = new StaticMockLink(MOCKS, true); async function wait(ms = 100): Promise { - await act(() => { - return new Promise((resolve) => { - setTimeout(resolve, ms); - }); - }); + await act(() => new Promise((resolve) => setTimeout(resolve, ms))); } describe('Testing User List Card', () => { - global.alert = jest.fn(); + beforeEach(() => { + vi.spyOn(global, 'alert').mockImplementation(() => {}); + }); - test('Should render props and text elements test for the page component', async () => { + it('Should render props and text elements test for the page component', async () => { const props = { id: '456', }; @@ -56,11 +55,10 @@ describe('Testing User List Card', () => { ); await wait(); - userEvent.click(screen.getByText(/Add Admin/i)); }); - test('Should render text elements when props value is not passed', async () => { + it('Should render text elements when props value is not passed', async () => { const props = { id: '456', }; From aa9c90383fa9dc59ed5452aa265c8b2ae8223565 Mon Sep 17 00:00:00 2001 From: Aadhil Ahamed Date: Thu, 26 Dec 2024 19:03:43 +0530 Subject: [PATCH 13/13] Refactored src/components/UsersTableItem/UserTableItem.test.tsx from Jest to Vitest #2826 (#2926) --- ...leItem.test.tsx => UserTableItem.spec.tsx} | 56 +++++++------------ 1 file changed, 20 insertions(+), 36 deletions(-) rename src/components/UsersTableItem/{UserTableItem.test.tsx => UserTableItem.spec.tsx} (98%) diff --git a/src/components/UsersTableItem/UserTableItem.test.tsx b/src/components/UsersTableItem/UserTableItem.spec.tsx similarity index 98% rename from src/components/UsersTableItem/UserTableItem.test.tsx rename to src/components/UsersTableItem/UserTableItem.spec.tsx index 687165b78d..a0b0c39c86 100644 --- a/src/components/UsersTableItem/UserTableItem.test.tsx +++ b/src/components/UsersTableItem/UserTableItem.spec.tsx @@ -13,11 +13,9 @@ const link = new StaticMockLink(MOCKS, true); const link2 = new StaticMockLink(MOCKS2, true); const link3 = new StaticMockLink(MOCKS_UPDATE, true); import useLocalStorage from 'utils/useLocalstorage'; -import { - REMOVE_ADMIN_MUTATION, - REMOVE_MEMBER_MUTATION, -} from 'GraphQl/Mutations/mutations'; import userEvent from '@testing-library/user-event'; +import { vi } from 'vitest'; +import type * as RouterTypes from 'react-router-dom'; const { setItem } = useLocalStorage(); @@ -28,29 +26,34 @@ async function wait(ms = 100): Promise { }); }); } -const resetAndRefetchMock = jest.fn(); +const resetAndRefetchMock = vi.fn(); -jest.mock('react-toastify', () => ({ +vi.mock('react-toastify', () => ({ toast: { - success: jest.fn(), - error: jest.fn(), - warning: jest.fn(), + success: vi.fn(), + error: vi.fn(), + warning: vi.fn(), }, })); Object.defineProperty(window, 'location', { value: { - replace: jest.fn(), + replace: vi.fn(), }, writable: true, }); -const mockNavgatePush = jest.fn(); +const mockNavgatePush = vi.fn(); -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useNavigate: () => mockNavgatePush, -})); +vi.mock('react-router-dom', async () => { + const actual = (await vi.importActual( + 'react-router-dom', + )) as typeof RouterTypes; + return { + ...actual, + useNavigate: () => mockNavgatePush, + }; +}); beforeEach(() => { setItem('SuperAdmin', true); @@ -59,11 +62,11 @@ beforeEach(() => { afterEach(() => { localStorage.clear(); - jest.clearAllMocks(); + vi.clearAllMocks(); }); describe('Testing User Table Item', () => { - console.error = jest.fn((message) => { + console.error = vi.fn((message) => { if (message.includes('validateDOMNesting')) { return; } @@ -1183,25 +1186,6 @@ describe('Testing User Table Item', () => { resetAndRefetch: resetAndRefetchMock, }; - const mocks = [ - { - request: { - query: REMOVE_MEMBER_MUTATION, - variables: { - userId: '123', - orgId: 'xyz', - }, - }, - result: { - errors: [ - { - message: 'User does not exist', - }, - ], - }, - }, - ]; - render(