diff --git a/src/style/app.module.css b/src/style/app.module.css
index 982cec9672..d21c2bb845 100644
--- a/src/style/app.module.css
+++ b/src/style/app.module.css
@@ -539,6 +539,116 @@ hr {
color: var(--bs-primary) !important;
}
+.pageNotFound {
+ position: relative;
+ bottom: 20px;
+}
+
+.pageNotFound h3 {
+ font-family: 'Roboto', sans-serif;
+ font-weight: normal;
+ letter-spacing: 1px;
+}
+
+.pageNotFound .brand span {
+ margin-top: 50px;
+ font-size: 40px;
+}
+.pageNotFound .brand h3 {
+ font-weight: 300;
+ margin: 10px 0 0 0;
+}
+.pageNotFound h1.head {
+ font-size: 250px;
+ font-weight: 900;
+ color: #31bb6b;
+ letter-spacing: 25px;
+ margin: 10px 0 0 0;
+}
+.pageNotFound h1.head span {
+ position: relative;
+ display: inline-block;
+}
+.pageNotFound h1.head span:before,
+.pageNotFound h1.head span:after {
+ position: absolute;
+ top: 50%;
+ width: 50%;
+ height: 1px;
+ background: #fff;
+ content: '';
+}
+.pageNotFound h1.head span:before {
+ left: -55%;
+}
+.pageNotFound h1.head span:after {
+ right: -55%;
+}
+
+@media (max-width: 1024px) {
+ .pageNotFound h1.head {
+ font-size: 200px;
+ letter-spacing: 25px;
+ }
+}
+
+@media (max-width: 768px) {
+ .pageNotFound h1.head {
+ font-size: 150px;
+ letter-spacing: 25px;
+ }
+}
+
+@media (max-width: 640px) {
+ .pageNotFound h1.head {
+ font-size: 150px;
+ letter-spacing: 0;
+ }
+}
+
+@media (max-width: 480px) {
+ .pageNotFound .brand h3 {
+ font-size: 20px;
+ }
+ .pageNotFound h1.head {
+ font-size: 130px;
+ letter-spacing: 0;
+ }
+ .pageNotFound h1.head span:before,
+ .pageNotFound h1.head span:after {
+ width: 40%;
+ }
+ .pageNotFound h1.head span:before {
+ left: -45%;
+ }
+ .pageNotFound h1.head span:after {
+ right: -45%;
+ }
+ .pageNotFound p {
+ font-size: 18px;
+ }
+}
+
+@media (max-width: 320px) {
+ .pageNotFound .brand h3 {
+ font-size: 16px;
+ }
+ .pageNotFound h1.head {
+ font-size: 100px;
+ letter-spacing: 0;
+ }
+ .pageNotFound h1.head span:before,
+ .pageNotFound h1.head span:after {
+ width: 25%;
+ }
+ .pageNotFound h1.head span:before {
+ left: -30%;
+ }
+ .pageNotFound h1.head span:after {
+ right: -30%;
+ }
+}
+
@media (max-width: 520px) {
.btnsContainer {
margin-bottom: 0;
From 13aad7cf5a30e62cc75a57d22acdc7ca98850d7b Mon Sep 17 00:00:00 2001
From: Bandhan Majumder <133476557+bandhan-majumder@users.noreply.github.com>
Date: Sun, 22 Dec 2024 19:28:59 +0530
Subject: [PATCH 032/133] refactor: jest to vitest of itemUpdateStatusModal :
fixes #2557 (#2714)
---
...est.tsx => ItemUpdateStatusModal.spec.tsx} | 19 ++++++++++---------
1 file changed, 10 insertions(+), 9 deletions(-)
rename src/screens/OrganizationActionItems/{ItemUpdateStatusModal.test.tsx => ItemUpdateStatusModal.spec.tsx} (96%)
diff --git a/src/screens/OrganizationActionItems/ItemUpdateStatusModal.test.tsx b/src/screens/OrganizationActionItems/ItemUpdateStatusModal.spec.tsx
similarity index 96%
rename from src/screens/OrganizationActionItems/ItemUpdateStatusModal.test.tsx
rename to src/screens/OrganizationActionItems/ItemUpdateStatusModal.spec.tsx
index aa28b14d40..4d9e16d11e 100644
--- a/src/screens/OrganizationActionItems/ItemUpdateStatusModal.test.tsx
+++ b/src/screens/OrganizationActionItems/ItemUpdateStatusModal.spec.tsx
@@ -16,11 +16,12 @@ import { toast } from 'react-toastify';
import ItemUpdateStatusModal, {
type InterfaceItemUpdateStatusModalProps,
} from './ItemUpdateStatusModal';
+import { vi } from 'vitest';
-jest.mock('react-toastify', () => ({
+vi.mock('react-toastify', () => ({
toast: {
- success: jest.fn(),
- error: jest.fn(),
+ success: vi.fn(),
+ error: vi.fn(),
},
}));
@@ -35,8 +36,8 @@ const t = JSON.parse(
const itemProps: InterfaceItemUpdateStatusModalProps[] = [
{
isOpen: true,
- hide: jest.fn(),
- actionItemsRefetch: jest.fn(),
+ hide: vi.fn(),
+ actionItemsRefetch: vi.fn(),
actionItem: {
_id: 'actionItemId1',
assignee: null,
@@ -75,8 +76,8 @@ const itemProps: InterfaceItemUpdateStatusModalProps[] = [
},
{
isOpen: true,
- hide: jest.fn(),
- actionItemsRefetch: jest.fn(),
+ hide: vi.fn(),
+ actionItemsRefetch: vi.fn(),
actionItem: {
_id: 'actionItemId1',
assignee: null,
@@ -148,8 +149,8 @@ const itemProps: InterfaceItemUpdateStatusModalProps[] = [
},
{
isOpen: true,
- hide: jest.fn(),
- actionItemsRefetch: jest.fn(),
+ hide: vi.fn(),
+ actionItemsRefetch: vi.fn(),
actionItem: {
_id: 'actionItemId1',
assignee: {
From ca0b0f679703324bee740a7007fda3b2a197db32 Mon Sep 17 00:00:00 2001
From: Bandhan Majumder <133476557+bandhan-majumder@users.noreply.github.com>
Date: Sun, 22 Dec 2024 19:58:26 +0530
Subject: [PATCH 033/133] refactor: jest to vitest : fixes #2557 (#2713)
---
...odal.test.tsx => ItemDeleteModal.spec.tsx} | 23 +++++++++++++------
1 file changed, 16 insertions(+), 7 deletions(-)
rename src/screens/OrganizationActionItems/{ItemDeleteModal.test.tsx => ItemDeleteModal.spec.tsx} (91%)
diff --git a/src/screens/OrganizationActionItems/ItemDeleteModal.test.tsx b/src/screens/OrganizationActionItems/ItemDeleteModal.spec.tsx
similarity index 91%
rename from src/screens/OrganizationActionItems/ItemDeleteModal.test.tsx
rename to src/screens/OrganizationActionItems/ItemDeleteModal.spec.tsx
index fffeebfd7f..5bdb1ffde1 100644
--- a/src/screens/OrganizationActionItems/ItemDeleteModal.test.tsx
+++ b/src/screens/OrganizationActionItems/ItemDeleteModal.spec.tsx
@@ -3,7 +3,13 @@ import type { ApolloLink } from '@apollo/client';
import { MockedProvider } from '@apollo/react-testing';
import { LocalizationProvider } from '@mui/x-date-pickers';
import type { RenderResult } from '@testing-library/react';
-import { fireEvent, render, screen, waitFor } from '@testing-library/react';
+import {
+ fireEvent,
+ render,
+ screen,
+ waitFor,
+ act,
+} from '@testing-library/react';
import { I18nextProvider } from 'react-i18next';
import { Provider } from 'react-redux';
import { BrowserRouter } from 'react-router-dom';
@@ -16,11 +22,12 @@ import { toast } from 'react-toastify';
import ItemDeleteModal, {
type InterfaceItemDeleteModalProps,
} from './ItemDeleteModal';
+import { vi } from 'vitest';
-jest.mock('react-toastify', () => ({
+vi.mock('react-toastify', () => ({
toast: {
- success: jest.fn(),
- error: jest.fn(),
+ success: vi.fn(),
+ error: vi.fn(),
},
}));
@@ -34,8 +41,8 @@ const t = JSON.parse(
const itemProps: InterfaceItemDeleteModalProps = {
isOpen: true,
- hide: jest.fn(),
- actionItemsRefetch: jest.fn(),
+ hide: vi.fn(),
+ actionItemsRefetch: vi.fn(),
actionItem: {
_id: 'actionItemId1',
assignee: null,
@@ -102,7 +109,9 @@ describe('Testing ItemDeleteModal', () => {
renderItemDeleteModal(link1, itemProps);
expect(screen.getByTestId('deleteyesbtn')).toBeInTheDocument();
- fireEvent.click(screen.getByTestId('deleteyesbtn'));
+ await act(() => {
+ fireEvent.click(screen.getByTestId('deleteyesbtn'));
+ });
await waitFor(() => {
expect(itemProps.actionItemsRefetch).toHaveBeenCalled();
From ed0a01cc93e30858b2ecc8450e9ab64a2d898734 Mon Sep 17 00:00:00 2001
From: Bandhan Majumder <133476557+bandhan-majumder@users.noreply.github.com>
Date: Sun, 22 Dec 2024 19:59:16 +0530
Subject: [PATCH 034/133] Refactor: jest to vitest of itemModal : fixes #2557
(#2715)
---
...{ItemModal.test.tsx => ItemModal.spec.tsx} | 33 ++++++++++---------
1 file changed, 17 insertions(+), 16 deletions(-)
rename src/screens/OrganizationActionItems/{ItemModal.test.tsx => ItemModal.spec.tsx} (98%)
diff --git a/src/screens/OrganizationActionItems/ItemModal.test.tsx b/src/screens/OrganizationActionItems/ItemModal.spec.tsx
similarity index 98%
rename from src/screens/OrganizationActionItems/ItemModal.test.tsx
rename to src/screens/OrganizationActionItems/ItemModal.spec.tsx
index a58496e6df..1fe3d6fca5 100644
--- a/src/screens/OrganizationActionItems/ItemModal.test.tsx
+++ b/src/screens/OrganizationActionItems/ItemModal.spec.tsx
@@ -21,12 +21,13 @@ import { StaticMockLink } from 'utils/StaticMockLink';
import { toast } from 'react-toastify';
import type { InterfaceItemModalProps } from './ItemModal';
import ItemModal from './ItemModal';
+import { vi } from 'vitest';
-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(),
},
}));
@@ -45,28 +46,28 @@ const t = {
const itemProps: InterfaceItemModalProps[] = [
{
isOpen: true,
- hide: jest.fn(),
+ hide: vi.fn(),
orgId: 'orgId',
eventId: undefined,
- actionItemsRefetch: jest.fn(),
+ actionItemsRefetch: vi.fn(),
editMode: false,
actionItem: null,
},
{
isOpen: true,
- hide: jest.fn(),
+ hide: vi.fn(),
orgId: 'orgId',
eventId: 'eventId',
- actionItemsRefetch: jest.fn(),
+ actionItemsRefetch: vi.fn(),
editMode: false,
actionItem: null,
},
{
isOpen: true,
- hide: jest.fn(),
+ hide: vi.fn(),
orgId: 'orgId',
eventId: undefined,
- actionItemsRefetch: jest.fn(),
+ actionItemsRefetch: vi.fn(),
editMode: true,
actionItem: {
_id: 'actionItemId1',
@@ -106,10 +107,10 @@ const itemProps: InterfaceItemModalProps[] = [
},
{
isOpen: true,
- hide: jest.fn(),
+ hide: vi.fn(),
orgId: 'orgId',
eventId: undefined,
- actionItemsRefetch: jest.fn(),
+ actionItemsRefetch: vi.fn(),
editMode: true,
actionItem: {
_id: 'actionItemId2',
@@ -149,10 +150,10 @@ const itemProps: InterfaceItemModalProps[] = [
},
{
isOpen: true,
- hide: jest.fn(),
+ hide: vi.fn(),
orgId: 'orgId',
eventId: 'eventId',
- actionItemsRefetch: jest.fn(),
+ actionItemsRefetch: vi.fn(),
editMode: true,
actionItem: {
_id: 'actionItemId2',
@@ -202,10 +203,10 @@ const itemProps: InterfaceItemModalProps[] = [
},
{
isOpen: true,
- hide: jest.fn(),
+ hide: vi.fn(),
orgId: 'orgId',
eventId: 'eventId',
- actionItemsRefetch: jest.fn(),
+ actionItemsRefetch: vi.fn(),
editMode: true,
actionItem: {
_id: 'actionItemId2',
From e2a86ae4773ade0d0cb835167bb5f905a1a2d6b6 Mon Sep 17 00:00:00 2001
From: Bandhan Majumder <133476557+bandhan-majumder@users.noreply.github.com>
Date: Sun, 22 Dec 2024 19:59:59 +0530
Subject: [PATCH 035/133] refactor: jest to vitest of itemViewModal : fixes
#2557 (#2716)
* refactor: jest to vitest of itemViewModal : fixes #2557
* Update ItemViewModal.spec.tsx
---
...iewModal.test.tsx => ItemViewModal.spec.tsx} | 17 +++++++++--------
1 file changed, 9 insertions(+), 8 deletions(-)
rename src/screens/OrganizationActionItems/{ItemViewModal.test.tsx => ItemViewModal.spec.tsx} (97%)
diff --git a/src/screens/OrganizationActionItems/ItemViewModal.test.tsx b/src/screens/OrganizationActionItems/ItemViewModal.spec.tsx
similarity index 97%
rename from src/screens/OrganizationActionItems/ItemViewModal.test.tsx
rename to src/screens/OrganizationActionItems/ItemViewModal.spec.tsx
index 297cfab6a8..b6423e356d 100644
--- a/src/screens/OrganizationActionItems/ItemViewModal.test.tsx
+++ b/src/screens/OrganizationActionItems/ItemViewModal.spec.tsx
@@ -18,11 +18,12 @@ import type {
InterfaceUserInfo,
InterfaceVolunteerGroupInfo,
} from 'utils/interfaces';
+import { vi } from 'vitest';
-jest.mock('react-toastify', () => ({
+vi.mock('react-toastify', () => ({
toast: {
- success: jest.fn(),
- error: jest.fn(),
+ success: vi.fn(),
+ error: vi.fn(),
},
}));
@@ -86,7 +87,7 @@ const actionItemCategory = {
const itemProps: InterfaceViewModalProps[] = [
{
isOpen: true,
- hide: jest.fn(),
+ hide: vi.fn(),
item: {
_id: 'actionItemId1',
assignee: createAssignee(assigneeWithoutImage),
@@ -108,7 +109,7 @@ const itemProps: InterfaceViewModalProps[] = [
},
{
isOpen: true,
- hide: jest.fn(),
+ hide: vi.fn(),
item: {
_id: 'actionItemId2',
assignee: createAssignee(assigneeWithImage),
@@ -130,7 +131,7 @@ const itemProps: InterfaceViewModalProps[] = [
},
{
isOpen: true,
- hide: jest.fn(),
+ hide: vi.fn(),
item: {
_id: 'actionItemId2',
assignee: null,
@@ -152,7 +153,7 @@ const itemProps: InterfaceViewModalProps[] = [
},
{
isOpen: true,
- hide: jest.fn(),
+ hide: vi.fn(),
item: {
_id: 'actionItemId2',
assignee: null,
@@ -174,7 +175,7 @@ const itemProps: InterfaceViewModalProps[] = [
},
{
isOpen: true,
- hide: jest.fn(),
+ hide: vi.fn(),
item: {
_id: 'actionItemId2',
assignee: null,
From 84c167cf4b9f8b846f1bab04e65f9e2db62eb63c Mon Sep 17 00:00:00 2001
From: Shiva <148421597+shivasankaran18@users.noreply.github.com>
Date: Sun, 22 Dec 2024 20:05:12 +0530
Subject: [PATCH 036/133] Refactor : Vitest to EventVolunteers/VolunteerGroups
Screen (#2696)
* refactor:vitest to EventVolunteers/VolunteerGroups screen
* add:ts-doc
* fix:codereabbit sugg
---------
Co-authored-by: Peter Harrison <16875803+palisadoes@users.noreply.github.com>
---
...tsx => VolunteerGroupDeleteModal.spec.tsx} | 17 +++++++---
....test.tsx => VolunteerGroupModal.spec.tsx} | 25 +++++++++-----
...t.tsx => VolunteerGroupViewModal.spec.tsx} | 5 +--
...oups.test.tsx => VolunteerGroups.spec.tsx} | 34 +++++++++++++++----
4 files changed, 59 insertions(+), 22 deletions(-)
rename src/screens/EventVolunteers/VolunteerGroups/{VolunteerGroupDeleteModal.test.tsx => VolunteerGroupDeleteModal.spec.tsx} (92%)
rename src/screens/EventVolunteers/VolunteerGroups/{VolunteerGroupModal.test.tsx => VolunteerGroupModal.spec.tsx} (96%)
rename src/screens/EventVolunteers/VolunteerGroups/{VolunteerGroupViewModal.test.tsx => VolunteerGroupViewModal.spec.tsx} (98%)
rename src/screens/EventVolunteers/VolunteerGroups/{VolunteerGroups.test.tsx => VolunteerGroups.spec.tsx} (89%)
diff --git a/src/screens/EventVolunteers/VolunteerGroups/VolunteerGroupDeleteModal.test.tsx b/src/screens/EventVolunteers/VolunteerGroups/VolunteerGroupDeleteModal.spec.tsx
similarity index 92%
rename from src/screens/EventVolunteers/VolunteerGroups/VolunteerGroupDeleteModal.test.tsx
rename to src/screens/EventVolunteers/VolunteerGroups/VolunteerGroupDeleteModal.spec.tsx
index 05c2dab5ff..8e726028db 100644
--- a/src/screens/EventVolunteers/VolunteerGroups/VolunteerGroupDeleteModal.test.tsx
+++ b/src/screens/EventVolunteers/VolunteerGroups/VolunteerGroupDeleteModal.spec.tsx
@@ -16,11 +16,18 @@ import { toast } from 'react-toastify';
import type { InterfaceDeleteVolunteerGroupModal } from './VolunteerGroupDeleteModal';
import VolunteerGroupDeleteModal from './VolunteerGroupDeleteModal';
import userEvent from '@testing-library/user-event';
+import { vi } from 'vitest';
-jest.mock('react-toastify', () => ({
+/**
+ * Mock implementation of the `react-toastify` module.
+ * Mocks the `toast` object with `success` and `error` methods to allow testing
+ * without triggering actual toast notifications.
+ */
+
+vi.mock('react-toastify', () => ({
toast: {
- success: jest.fn(),
- error: jest.fn(),
+ success: vi.fn(),
+ error: vi.fn(),
},
}));
@@ -39,8 +46,8 @@ const t = {
const itemProps: InterfaceDeleteVolunteerGroupModal[] = [
{
isOpen: true,
- hide: jest.fn(),
- refetchGroups: jest.fn(),
+ hide: vi.fn(),
+ refetchGroups: vi.fn(),
group: {
_id: 'groupId',
name: 'Group 1',
diff --git a/src/screens/EventVolunteers/VolunteerGroups/VolunteerGroupModal.test.tsx b/src/screens/EventVolunteers/VolunteerGroups/VolunteerGroupModal.spec.tsx
similarity index 96%
rename from src/screens/EventVolunteers/VolunteerGroups/VolunteerGroupModal.test.tsx
rename to src/screens/EventVolunteers/VolunteerGroups/VolunteerGroupModal.spec.tsx
index 2fc0b2e348..79b1d94545 100644
--- a/src/screens/EventVolunteers/VolunteerGroups/VolunteerGroupModal.test.tsx
+++ b/src/screens/EventVolunteers/VolunteerGroups/VolunteerGroupModal.spec.tsx
@@ -22,11 +22,18 @@ import { toast } from 'react-toastify';
import type { InterfaceVolunteerGroupModal } from './VolunteerGroupModal';
import GroupModal from './VolunteerGroupModal';
import userEvent from '@testing-library/user-event';
+import { vi } from 'vitest';
-jest.mock('react-toastify', () => ({
+/**
+ * Mock implementation of the `react-toastify` module.
+ * Mocks the `toast` object with `success` and `error` methods to allow testing
+ * without triggering actual toast notifications.
+ */
+
+vi.mock('react-toastify', () => ({
toast: {
- success: jest.fn(),
- error: jest.fn(),
+ success: vi.fn(),
+ error: vi.fn(),
},
}));
@@ -45,19 +52,19 @@ const t = {
const itemProps: InterfaceVolunteerGroupModal[] = [
{
isOpen: true,
- hide: jest.fn(),
+ hide: vi.fn(),
eventId: 'eventId',
orgId: 'orgId',
- refetchGroups: jest.fn(),
+ refetchGroups: vi.fn(),
mode: 'create',
group: null,
},
{
isOpen: true,
- hide: jest.fn(),
+ hide: vi.fn(),
eventId: 'eventId',
orgId: 'orgId',
- refetchGroups: jest.fn(),
+ refetchGroups: vi.fn(),
mode: 'edit',
group: {
_id: 'groupId',
@@ -96,10 +103,10 @@ const itemProps: InterfaceVolunteerGroupModal[] = [
},
{
isOpen: true,
- hide: jest.fn(),
+ hide: vi.fn(),
eventId: 'eventId',
orgId: 'orgId',
- refetchGroups: jest.fn(),
+ refetchGroups: vi.fn(),
mode: 'edit',
group: {
_id: 'groupId',
diff --git a/src/screens/EventVolunteers/VolunteerGroups/VolunteerGroupViewModal.test.tsx b/src/screens/EventVolunteers/VolunteerGroups/VolunteerGroupViewModal.spec.tsx
similarity index 98%
rename from src/screens/EventVolunteers/VolunteerGroups/VolunteerGroupViewModal.test.tsx
rename to src/screens/EventVolunteers/VolunteerGroups/VolunteerGroupViewModal.spec.tsx
index 94c34923a2..b029909809 100644
--- a/src/screens/EventVolunteers/VolunteerGroups/VolunteerGroupViewModal.test.tsx
+++ b/src/screens/EventVolunteers/VolunteerGroups/VolunteerGroupViewModal.spec.tsx
@@ -11,6 +11,7 @@ import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
import i18n from 'utils/i18nForTest';
import type { InterfaceVolunteerGroupViewModal } from './VolunteerGroupViewModal';
import VolunteerGroupViewModal from './VolunteerGroupViewModal';
+import { vi } from 'vitest';
const t = {
...JSON.parse(
@@ -25,7 +26,7 @@ const t = {
const itemProps: InterfaceVolunteerGroupViewModal[] = [
{
isOpen: true,
- hide: jest.fn(),
+ hide: vi.fn(),
group: {
_id: 'groupId',
name: 'Group 1',
@@ -63,7 +64,7 @@ const itemProps: InterfaceVolunteerGroupViewModal[] = [
},
{
isOpen: true,
- hide: jest.fn(),
+ hide: vi.fn(),
group: {
_id: 'groupId',
name: 'Group 1',
diff --git a/src/screens/EventVolunteers/VolunteerGroups/VolunteerGroups.test.tsx b/src/screens/EventVolunteers/VolunteerGroups/VolunteerGroups.spec.tsx
similarity index 89%
rename from src/screens/EventVolunteers/VolunteerGroups/VolunteerGroups.test.tsx
rename to src/screens/EventVolunteers/VolunteerGroups/VolunteerGroups.spec.tsx
index 0dcba34a3a..2ce6e6a9dd 100644
--- a/src/screens/EventVolunteers/VolunteerGroups/VolunteerGroups.test.tsx
+++ b/src/screens/EventVolunteers/VolunteerGroups/VolunteerGroups.spec.tsx
@@ -7,13 +7,14 @@ import { fireEvent, render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { I18nextProvider } from 'react-i18next';
import { Provider } from 'react-redux';
-import { MemoryRouter, Route, Routes } from 'react-router-dom';
+import { MemoryRouter, Route, Routes, useParams } from 'react-router-dom';
import { store } from 'state/store';
import { StaticMockLink } from 'utils/StaticMockLink';
import i18n from 'utils/i18nForTest';
import VolunteerGroups from './VolunteerGroups';
import type { ApolloLink } from '@apollo/client';
import { MOCKS, MOCKS_EMPTY, MOCKS_ERROR } from './VolunteerGroups.mocks';
+import { vi } from 'vitest';
const link1 = new StaticMockLink(MOCKS);
const link2 = new StaticMockLink(MOCKS_ERROR);
@@ -61,19 +62,30 @@ const renderVolunteerGroups = (link: ApolloLink): RenderResult => {
);
};
+/** Mock useParams to provide consistent test data */
+
describe('Testing VolunteerGroups Screen', () => {
beforeAll(() => {
- jest.mock('react-router-dom', () => ({
- ...jest.requireActual('react-router-dom'),
- useParams: () => ({ orgId: 'orgId', eventId: 'eventId' }),
- }));
+ vi.mock('react-router-dom', async () => {
+ const actualDom = await vi.importActual('react-router-dom');
+ return {
+ ...actualDom,
+ useParams: vi.fn(),
+ };
+ });
});
afterAll(() => {
- jest.clearAllMocks();
+ vi.clearAllMocks();
});
+ const mockRouteParams = (orgId = 'orgId', eventId = 'eventId'): void => {
+ vi.mocked(useParams).mockReturnValue({ orgId, eventId });
+ };
+
it('should redirect to fallback URL if URL params are undefined', async () => {
+ /** Mocking the useParams hook to return undefined parameters */
+ mockRouteParams('', '');
render(
@@ -98,12 +110,14 @@ describe('Testing VolunteerGroups Screen', () => {
});
it('should render Groups screen', async () => {
+ mockRouteParams();
renderVolunteerGroups(link1);
const searchInput = await screen.findByTestId('searchBy');
expect(searchInput).toBeInTheDocument();
});
it('Check Sorting Functionality', async () => {
+ mockRouteParams();
renderVolunteerGroups(link1);
const searchInput = await screen.findByTestId('searchBy');
expect(searchInput).toBeInTheDocument();
@@ -133,6 +147,7 @@ describe('Testing VolunteerGroups Screen', () => {
});
it('Search by Groups', async () => {
+ mockRouteParams();
renderVolunteerGroups(link1);
const searchInput = await screen.findByTestId('searchBy');
expect(searchInput).toBeInTheDocument();
@@ -153,6 +168,7 @@ describe('Testing VolunteerGroups Screen', () => {
});
it('Search by Leader', async () => {
+ mockRouteParams();
renderVolunteerGroups(link1);
const searchInput = await screen.findByTestId('searchBy');
expect(searchInput).toBeInTheDocument();
@@ -174,6 +190,7 @@ describe('Testing VolunteerGroups Screen', () => {
});
it('should render screen with No Groups', async () => {
+ mockRouteParams();
renderVolunteerGroups(link3);
await waitFor(() => {
@@ -183,6 +200,7 @@ describe('Testing VolunteerGroups Screen', () => {
});
it('Error while fetching groups data', async () => {
+ mockRouteParams();
renderVolunteerGroups(link2);
await waitFor(() => {
@@ -191,6 +209,7 @@ describe('Testing VolunteerGroups Screen', () => {
});
it('Open and close ViewModal', async () => {
+ mockRouteParams();
renderVolunteerGroups(link1);
const viewGroupBtn = await screen.findAllByTestId('viewGroupBtn');
@@ -201,6 +220,7 @@ describe('Testing VolunteerGroups Screen', () => {
});
it('Open and Close Delete Modal', async () => {
+ mockRouteParams();
renderVolunteerGroups(link1);
const deleteGroupBtn = await screen.findAllByTestId('deleteGroupBtn');
@@ -211,6 +231,7 @@ describe('Testing VolunteerGroups Screen', () => {
});
it('Open and close GroupModal (Edit)', async () => {
+ mockRouteParams();
renderVolunteerGroups(link1);
const editGroupBtn = await screen.findAllByTestId('editGroupBtn');
@@ -221,6 +242,7 @@ describe('Testing VolunteerGroups Screen', () => {
});
it('Open and close GroupModal (Create)', async () => {
+ mockRouteParams();
renderVolunteerGroups(link1);
const createGroupBtn = await screen.findByTestId('createGroupBtn');
From 3d6b6bc778b51f182cb56abba6179fe850d0d38f Mon Sep 17 00:00:00 2001
From: Gurram Karthik <167804249+gurramkarthiknetha@users.noreply.github.com>
Date: Sun, 22 Dec 2024 20:10:49 +0530
Subject: [PATCH 037/133] fixed #2505 :Refactor CSS Structure for
EventVolunteers: Improved Maintainability and UI Consistency (#2675)
* fixed-2505
* changed acc to bot
* changed acc to coderabbin
* removed due to conflicts
* final change
* resloved conflict
* changed some file to improve the codecov
* improved time
* deleted file
* changed some path
* changed acc to code rabbin
* updated
* changed acc to code rabbin
* fixed-time
* decreased the time
---
.../OrganizationScreen.test.tsx | 1 +
.../EventVolunteers.module.css | 266 ------------------
.../EventVolunteers/Requests/Requests.tsx | 22 +-
.../EventVolunteers/VolunteerContainer.tsx | 2 +-
.../VolunteerGroupDeleteModal.tsx | 2 +-
.../VolunteerGroups/VolunteerGroupModal.tsx | 2 +-
.../VolunteerGroupViewModal.tsx | 10 +-
.../VolunteerGroups/VolunteerGroups.tsx | 26 +-
.../Volunteers/VolunteerCreateModal.tsx | 2 +-
.../Volunteers/VolunteerDeleteModal.tsx | 2 +-
.../Volunteers/VolunteerViewModal.tsx | 6 +-
.../EventVolunteers/Volunteers/Volunteers.tsx | 26 +-
.../Volunteer/Groups/GroupModal.tsx | 2 +-
.../UserPortal/Volunteer/Groups/Groups.tsx | 2 +-
src/setupTests.ts | 2 +-
src/style/app.module.css | 182 ++++++++++++
16 files changed, 236 insertions(+), 319 deletions(-)
delete mode 100644 src/screens/EventVolunteers/EventVolunteers.module.css
diff --git a/src/components/OrganizationScreen/OrganizationScreen.test.tsx b/src/components/OrganizationScreen/OrganizationScreen.test.tsx
index 9bb95bbd4a..d1c4c81c27 100644
--- a/src/components/OrganizationScreen/OrganizationScreen.test.tsx
+++ b/src/components/OrganizationScreen/OrganizationScreen.test.tsx
@@ -85,6 +85,7 @@ describe('Testing OrganizationScreen', () => {
const openButton = screen.getByTestId('openMenu');
fireEvent.click(openButton);
+ // Check for expand class after opening
expect(screen.getByTestId('mainpageright')).toHaveClass(styles.contract);
});
diff --git a/src/screens/EventVolunteers/EventVolunteers.module.css b/src/screens/EventVolunteers/EventVolunteers.module.css
deleted file mode 100644
index 84b19f0a9f..0000000000
--- a/src/screens/EventVolunteers/EventVolunteers.module.css
+++ /dev/null
@@ -1,266 +0,0 @@
-/* Toggle Btn */
-.toggleGroup {
- width: 50%;
- min-width: 20rem;
- margin: 0.5rem 0rem;
-}
-
-.toggleBtn {
- padding: 0rem;
- height: 2rem;
- display: flex;
- justify-content: center;
- align-items: center;
-}
-
-.toggleBtn:hover {
- color: #31bb6b !important;
-}
-
-input[type='radio']:checked + label {
- background-color: #31bb6a50 !important;
-}
-
-input[type='radio']:checked + label:hover {
- color: black !important;
-}
-
-.actionItemsContainer {
- height: 90vh;
-}
-
-.actionItemModal {
- max-width: 80vw;
- margin-top: 2vh;
- margin-left: 13vw;
-}
-
-.datediv {
- display: flex;
- flex-direction: row;
-}
-
-.datebox {
- width: 90%;
- border-radius: 7px;
- outline: none;
- box-shadow: none;
- padding-top: 2px;
- padding-bottom: 2px;
- padding-right: 5px;
- padding-left: 5px;
- margin-right: 5px;
- margin-left: 5px;
-}
-
-.dropdownToggle {
- margin-bottom: 0;
- display: flex;
-}
-
-.dropdownModalToggle {
- width: 50%;
-}
-
-.errorIcon {
- transform: scale(1.5);
- color: var(--bs-danger);
- margin-bottom: 1rem;
-}
-
-.greenregbtn {
- margin: 1rem 0 0;
- margin-top: 15px;
- border: 1px solid var(--bs-gray-300);
- box-shadow: 0 2px 2px var(--bs-gray-300);
- padding: 10px 10px;
- border-radius: 5px;
- background-color: var(--bs-primary);
- width: 100%;
- font-size: 16px;
- color: var(--bs-white);
- outline: none;
- font-weight: 600;
- cursor: pointer;
- transition:
- transform 0.2s,
- box-shadow 0.2s;
- width: 100%;
-}
-
-hr {
- border: none;
- height: 1px;
- background-color: var(--bs-gray-500);
- margin: 1rem;
-}
-
-.iconContainer {
- display: flex;
- justify-content: flex-end;
-}
-.icon {
- margin: 1px;
-}
-
-.message {
- margin-top: 25%;
- display: flex;
- justify-content: center;
- align-items: center;
- flex-direction: column;
-}
-
-.preview {
- display: flex;
- flex-direction: row;
- font-weight: 900;
- font-size: 16px;
- color: rgb(80, 80, 80);
-}
-
-.removeFilterIcon {
- cursor: pointer;
-}
-
-.searchForm {
- display: inline;
-}
-
-.view {
- margin-left: 2%;
- font-weight: 600;
- font-size: 16px;
- color: var(--bs-gray-600);
-}
-
-/* header (search, filter, dropdown) */
-.btnsContainer {
- display: flex;
- margin: 0.5rem 0 1.5rem 0;
-}
-
-.btnsContainer .input {
- flex: 1;
- min-width: 18rem;
- position: relative;
-}
-
-.btnsContainer input {
- outline: 1px solid var(--bs-gray-400);
-}
-
-.btnsContainer .input button {
- width: 52px;
-}
-
-.noOutline input {
- outline: none;
-}
-
-.noOutline input:disabled {
- -webkit-text-fill-color: black !important;
-}
-
-.noOutline textarea:disabled {
- -webkit-text-fill-color: black !important;
-}
-
-.inputField {
- margin-top: 10px;
- margin-bottom: 10px;
- background-color: white;
- box-shadow: 0 1px 1px #31bb6b;
-}
-
-.inputField > button {
- padding-top: 10px;
- padding-bottom: 10px;
-}
-
-.dropdown {
- background-color: white;
- border: 1px solid #31bb6b;
- position: relative;
- display: inline-block;
- color: #31bb6b;
-}
-
-/* Action Items Data Grid */
-.rowBackground {
- background-color: var(--bs-white);
- max-height: 120px;
-}
-
-.tableHeader {
- background-color: var(--bs-primary);
- color: var(--bs-white);
- font-size: 1rem;
-}
-
-.chipIcon {
- height: 0.9rem !important;
-}
-
-.chip {
- height: 1.5rem !important;
-}
-
-.active {
- background-color: #31bb6a50 !important;
-}
-
-.pending {
- background-color: #ffd76950 !important;
- color: #bb952bd0 !important;
- border-color: #bb952bd0 !important;
-}
-
-/* Modals */
-.itemModal {
- max-width: 80vw;
- margin-top: 2vh;
- margin-left: 13vw;
-}
-
-.titlemodal {
- color: #707070;
- font-weight: 600;
- font-size: 32px;
- width: 65%;
- margin-bottom: 0px;
-}
-
-.modalCloseBtn {
- width: 40px;
- height: 40px;
- padding: 1rem;
- display: flex;
- justify-content: center;
- align-items: center;
-}
-
-.imageContainer {
- display: flex;
- align-items: center;
- justify-content: center;
- margin-right: 0.5rem;
-}
-
-.TableImage {
- object-fit: cover;
- width: 25px !important;
- height: 25px !important;
- border-radius: 100% !important;
-}
-
-.avatarContainer {
- width: 28px;
- height: 26px;
-}
-
-/* Modal Table (Groups & Assignments) */
-.modalTable {
- max-height: 220px;
- overflow-y: auto;
-}
diff --git a/src/screens/EventVolunteers/Requests/Requests.tsx b/src/screens/EventVolunteers/Requests/Requests.tsx
index 41abcad763..b19be3d2a0 100644
--- a/src/screens/EventVolunteers/Requests/Requests.tsx
+++ b/src/screens/EventVolunteers/Requests/Requests.tsx
@@ -13,7 +13,7 @@ import {
type GridColDef,
} from '@mui/x-data-grid';
import Avatar from 'components/Avatar/Avatar';
-import styles from '../EventVolunteers.module.css';
+import styles from '../../../style/app.module.css';
import { USER_VOLUNTEER_MEMBERSHIP } from 'GraphQl/Queries/EventVolunteerQueries';
import type { InterfaceVolunteerMembership } from 'utils/interfaces';
import dayjs from 'dayjs';
@@ -154,7 +154,7 @@ function requests(): JSX.Element {
align: 'center',
headerAlign: 'center',
sortable: false,
- headerClassName: `${styles.tableHeader}`,
+ headerClassName: `${styles.tableHeaders}`,
renderCell: (params: GridCellParams) => {
return params.row.id;
},
@@ -167,7 +167,7 @@ function requests(): JSX.Element {
minWidth: 100,
headerAlign: 'center',
sortable: false,
- headerClassName: `${styles.tableHeader}`,
+ headerClassName: `${styles.tableHeaders}`,
renderCell: (params: GridCellParams) => {
const { firstName, lastName, image } = params.row.volunteer.user;
return (
@@ -180,14 +180,14 @@ function requests(): JSX.Element {
src={image}
alt="volunteer"
data-testid={`volunteer_image`}
- className={styles.TableImage}
+ className={styles.TableImages}
/>
) : (
@@ -205,7 +205,7 @@ function requests(): JSX.Element {
minWidth: 150,
align: 'center',
headerAlign: 'center',
- headerClassName: `${styles.tableHeader}`,
+ headerClassName: `${styles.tableHeaders}`,
sortable: false,
renderCell: (params: GridCellParams) => {
return dayjs(params.row.createdAt).format('DD/MM/YYYY');
@@ -219,7 +219,7 @@ function requests(): JSX.Element {
minWidth: 100,
headerAlign: 'center',
sortable: false,
- headerClassName: `${styles.tableHeader}`,
+ headerClassName: `${styles.tableHeaders}`,
renderCell: (params: GridCellParams) => {
return (
<>
@@ -251,7 +251,7 @@ function requests(): JSX.Element {
return (
{/* Header with search, filter and Create Button */}
-
+
{
setSearchValue(e.target.value);
@@ -282,7 +282,7 @@ function requests(): JSX.Element {
@@ -316,7 +316,7 @@ function requests(): JSX.Element {
hideFooter={true}
getRowId={(row) => row._id}
sx={dataGridStyle}
- getRowClassName={() => `${styles.rowBackground}`}
+ getRowClassName={() => `${styles.rowBackgrounds}`}
autoHeight
rowHeight={65}
rows={requests.map((request, index) => ({
diff --git a/src/screens/EventVolunteers/VolunteerContainer.tsx b/src/screens/EventVolunteers/VolunteerContainer.tsx
index 1a425a706e..e026c6f7c8 100644
--- a/src/screens/EventVolunteers/VolunteerContainer.tsx
+++ b/src/screens/EventVolunteers/VolunteerContainer.tsx
@@ -1,7 +1,7 @@
import React, { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { Navigate, useParams } from 'react-router-dom';
-import styles from './EventVolunteers.module.css';
+import styles from '../../style/app.module.css';
import { HiUserGroup, HiUser } from 'react-icons/hi2';
import Volunteers from './Volunteers/Volunteers';
import VolunteerGroups from './VolunteerGroups/VolunteerGroups';
diff --git a/src/screens/EventVolunteers/VolunteerGroups/VolunteerGroupDeleteModal.tsx b/src/screens/EventVolunteers/VolunteerGroups/VolunteerGroupDeleteModal.tsx
index 33132bfd33..89c788e220 100644
--- a/src/screens/EventVolunteers/VolunteerGroups/VolunteerGroupDeleteModal.tsx
+++ b/src/screens/EventVolunteers/VolunteerGroups/VolunteerGroupDeleteModal.tsx
@@ -1,5 +1,5 @@
import { Button, Modal } from 'react-bootstrap';
-import styles from '../EventVolunteers.module.css';
+import styles from '../../../style/app.module.css';
import React from 'react';
import { useTranslation } from 'react-i18next';
import { useMutation } from '@apollo/client';
diff --git a/src/screens/EventVolunteers/VolunteerGroups/VolunteerGroupModal.tsx b/src/screens/EventVolunteers/VolunteerGroups/VolunteerGroupModal.tsx
index 5bfb1eff2b..e36ecaa0bd 100644
--- a/src/screens/EventVolunteers/VolunteerGroups/VolunteerGroupModal.tsx
+++ b/src/screens/EventVolunteers/VolunteerGroups/VolunteerGroupModal.tsx
@@ -5,7 +5,7 @@ import type {
InterfaceUserInfo,
InterfaceVolunteerGroupInfo,
} from 'utils/interfaces';
-import styles from '../EventVolunteers.module.css';
+import styles from '../../../style/app.module.css';
import React, { useCallback, useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useMutation, useQuery } from '@apollo/client';
diff --git a/src/screens/EventVolunteers/VolunteerGroups/VolunteerGroupViewModal.tsx b/src/screens/EventVolunteers/VolunteerGroups/VolunteerGroupViewModal.tsx
index 70994bd4e5..5fb090649f 100644
--- a/src/screens/EventVolunteers/VolunteerGroups/VolunteerGroupViewModal.tsx
+++ b/src/screens/EventVolunteers/VolunteerGroups/VolunteerGroupViewModal.tsx
@@ -1,6 +1,6 @@
import { Button, Form, Modal } from 'react-bootstrap';
import type { InterfaceVolunteerGroupInfo } from 'utils/interfaces';
-import styles from '../EventVolunteers.module.css';
+import styles from '../../../style/app.module.css';
import React from 'react';
import { useTranslation } from 'react-i18next';
import {
@@ -123,14 +123,14 @@ const VolunteerGroupViewModal: React.FC = ({
src={leader.image}
alt="Volunteer"
data-testid="leader_image"
- className={styles.TableImage}
+ className={styles.TableImages}
/>
) : (
= ({
src={creator.image}
alt="Volunteer"
data-testid="creator_image"
- className={styles.TableImage}
+ className={styles.TableImages}
/>
) : (
{
return (
{
const { _id, firstName, lastName, image } = params.row.leader;
return (
@@ -194,14 +194,14 @@ function volunteerGroups(): JSX.Element {
src={image}
alt="Assignee"
data-testid={`image${_id + 1}`}
- className={styles.TableImage}
+ className={styles.TableImages}
/>
) : (
@@ -219,7 +219,7 @@ function volunteerGroups(): JSX.Element {
align: 'center',
headerAlign: 'center',
sortable: false,
- headerClassName: `${styles.tableHeader}`,
+ headerClassName: `${styles.tableHeaders}`,
renderCell: (params: GridCellParams) => {
return (
@@ -235,7 +235,7 @@ function volunteerGroups(): JSX.Element {
align: 'center',
headerAlign: 'center',
sortable: false,
- headerClassName: `${styles.tableHeader}`,
+ headerClassName: `${styles.tableHeaders}`,
renderCell: (params: GridCellParams) => {
return (
@@ -252,7 +252,7 @@ function volunteerGroups(): JSX.Element {
minWidth: 100,
headerAlign: 'center',
sortable: false,
- headerClassName: `${styles.tableHeader}`,
+ headerClassName: `${styles.tableHeaders}`,
renderCell: (params: GridCellParams) => {
return (
<>
@@ -293,7 +293,7 @@ function volunteerGroups(): JSX.Element {
return (
{/* Header with search, filter and Create Button */}
-
+
{
setSearchValue(e.target.value);
@@ -325,7 +325,7 @@ function volunteerGroups(): JSX.Element {
@@ -350,7 +350,7 @@ function volunteerGroups(): JSX.Element {
@@ -400,7 +400,7 @@ function volunteerGroups(): JSX.Element {
),
}}
sx={dataGridStyle}
- getRowClassName={() => `${styles.rowBackground}`}
+ getRowClassName={() => `${styles.rowBackgrounds}`}
autoHeight
rowHeight={65}
rows={groups.map((group, index) => ({
diff --git a/src/screens/EventVolunteers/Volunteers/VolunteerCreateModal.tsx b/src/screens/EventVolunteers/Volunteers/VolunteerCreateModal.tsx
index 6b4a1e3f0c..dee45376db 100644
--- a/src/screens/EventVolunteers/Volunteers/VolunteerCreateModal.tsx
+++ b/src/screens/EventVolunteers/Volunteers/VolunteerCreateModal.tsx
@@ -1,7 +1,7 @@
import type { ChangeEvent } from 'react';
import { Button, Form, Modal } from 'react-bootstrap';
import type { InterfaceUserInfo } from 'utils/interfaces';
-import styles from '../EventVolunteers.module.css';
+import styles from '../../../style/app.module.css';
import React, { useCallback, useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useMutation, useQuery } from '@apollo/client';
diff --git a/src/screens/EventVolunteers/Volunteers/VolunteerDeleteModal.tsx b/src/screens/EventVolunteers/Volunteers/VolunteerDeleteModal.tsx
index 8f253fdf50..5c841a2f11 100644
--- a/src/screens/EventVolunteers/Volunteers/VolunteerDeleteModal.tsx
+++ b/src/screens/EventVolunteers/Volunteers/VolunteerDeleteModal.tsx
@@ -1,5 +1,5 @@
import { Button, Modal } from 'react-bootstrap';
-import styles from '../EventVolunteers.module.css';
+import styles from '../../../style/app.module.css';
import React from 'react';
import { useTranslation } from 'react-i18next';
import { useMutation } from '@apollo/client';
diff --git a/src/screens/EventVolunteers/Volunteers/VolunteerViewModal.tsx b/src/screens/EventVolunteers/Volunteers/VolunteerViewModal.tsx
index 0904d34b9c..830bacf8cc 100644
--- a/src/screens/EventVolunteers/Volunteers/VolunteerViewModal.tsx
+++ b/src/screens/EventVolunteers/Volunteers/VolunteerViewModal.tsx
@@ -1,6 +1,6 @@
import { Button, Form, Modal } from 'react-bootstrap';
import type { InterfaceEventVolunteerInfo } from 'utils/interfaces';
-import styles from '../EventVolunteers.module.css';
+import styles from '../../../style/app.module.css';
import React from 'react';
import { useTranslation } from 'react-i18next';
import {
@@ -83,14 +83,14 @@ const VolunteerViewModal: React.FC = ({
src={user.image}
alt="Volunteer"
data-testid="volunteer_image"
- className={styles.TableImage}
+ className={styles.TableImages}
/>
) : (
{
const { _id, firstName, lastName, image } = params.row.user;
return (
@@ -192,7 +192,7 @@ function volunteers(): JSX.Element {
src={image}
alt="volunteer"
data-testid="volunteer_image"
- className={styles.TableImage}
+ className={styles.TableImages}
/>
) : (
@@ -200,7 +200,7 @@ function volunteers(): JSX.Element {
key={_id + '1'}
dataTestId="volunteer_avatar"
containerStyle={styles.imageContainer}
- avatarStyle={styles.TableImage}
+ avatarStyle={styles.TableImages}
name={firstName + ' ' + lastName}
alt={firstName + ' ' + lastName}
/>
@@ -219,7 +219,7 @@ function volunteers(): JSX.Element {
minWidth: 100,
headerAlign: 'center',
sortable: false,
- headerClassName: `${styles.tableHeader}`,
+ headerClassName: `${styles.tableHeaders}`,
renderCell: (params: GridCellParams) => {
return (
{
return (
{
return (
@@ -278,7 +278,7 @@ function volunteers(): JSX.Element {
minWidth: 100,
headerAlign: 'center',
sortable: false,
- headerClassName: `${styles.tableHeader}`,
+ headerClassName: `${styles.tableHeaders}`,
renderCell: (params: GridCellParams) => {
return (
<>
@@ -310,7 +310,7 @@ function volunteers(): JSX.Element {
return (
{/* Header with search, filter and Create Button */}
-
+
{
setSearchValue(e.target.value);
@@ -341,7 +341,7 @@ function volunteers(): JSX.Element {
@@ -365,7 +365,7 @@ function volunteers(): JSX.Element {
@@ -421,7 +421,7 @@ function volunteers(): JSX.Element {
),
}}
sx={dataGridStyle}
- getRowClassName={() => `${styles.rowBackground}`}
+ getRowClassName={() => `${styles.rowBackgrounds}`}
autoHeight
rowHeight={65}
rows={volunteers.map((volunteer, index) => ({
diff --git a/src/screens/UserPortal/Volunteer/Groups/GroupModal.tsx b/src/screens/UserPortal/Volunteer/Groups/GroupModal.tsx
index 4ae162cd70..27f461b462 100644
--- a/src/screens/UserPortal/Volunteer/Groups/GroupModal.tsx
+++ b/src/screens/UserPortal/Volunteer/Groups/GroupModal.tsx
@@ -5,7 +5,7 @@ import type {
InterfaceVolunteerGroupInfo,
InterfaceVolunteerMembership,
} from 'utils/interfaces';
-import styles from 'screens/EventVolunteers/EventVolunteers.module.css';
+import styles from 'style/app.module.css';
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useMutation, useQuery } from '@apollo/client';
diff --git a/src/screens/UserPortal/Volunteer/Groups/Groups.tsx b/src/screens/UserPortal/Volunteer/Groups/Groups.tsx
index 3941f461d5..160dc0b23a 100644
--- a/src/screens/UserPortal/Volunteer/Groups/Groups.tsx
+++ b/src/screens/UserPortal/Volunteer/Groups/Groups.tsx
@@ -16,7 +16,7 @@ import {
} from '@mui/x-data-grid';
import { debounce, Stack } from '@mui/material';
import Avatar from 'components/Avatar/Avatar';
-import styles from 'screens/EventVolunteers/EventVolunteers.module.css';
+import styles from '../../../../style/app.module.css';
import { EVENT_VOLUNTEER_GROUP_LIST } from 'GraphQl/Queries/EventVolunteerQueries';
import VolunteerGroupViewModal from 'screens/EventVolunteers/VolunteerGroups/VolunteerGroupViewModal';
import useLocalStorage from 'utils/useLocalstorage';
diff --git a/src/setupTests.ts b/src/setupTests.ts
index eac7093309..f0b48b39d0 100644
--- a/src/setupTests.ts
+++ b/src/setupTests.ts
@@ -32,4 +32,4 @@ jestPreviewConfigure({
autoPreview: true,
});
-jest.setTimeout(15000);
+jest.setTimeout(17000);
diff --git a/src/style/app.module.css b/src/style/app.module.css
index d21c2bb845..365b00556b 100644
--- a/src/style/app.module.css
+++ b/src/style/app.module.css
@@ -868,3 +868,185 @@ hr {
max-height: calc(100vh - 18rem);
overflow: auto;
}
+
+#individualRadio,
+#requestsRadio,
+#groupsRadio,
+.toggleBtn:hover {
+ color: var(--brand-primary) !important;
+}
+
+input[type='radio']:checked + label {
+ background-color: var(--brand-primary-light) !important;
+}
+
+.dropdownToggle {
+ margin-bottom: 0;
+ display: flex;
+}
+
+.dropdownModalToggle {
+ width: 50%;
+}
+
+.greenregbtn {
+ margin-top: 1rem;
+ border: 1px solid var(--bs-gray-300);
+ box-shadow: 0 2px 2px var(--bs-gray-300);
+ padding: 10px 10px;
+ border-radius: 5px;
+ background-color: var(--bs-primary);
+ width: 100%;
+ font-size: 16px;
+ color: var(--bs-white);
+ outline: none;
+ font-weight: 600;
+ cursor: pointer;
+ transition:
+ transform 0.2s,
+ box-shadow 0.2s;
+}
+
+.removeFilterIcon {
+ cursor: pointer;
+}
+
+.searchForm {
+ display: inline;
+}
+
+.view {
+ margin-left: 2%;
+ font-weight: 600;
+ font-size: 16px;
+ color: var(--bs-gray-600);
+}
+
+/* header (search, filter, dropdown) */
+.btncon .btnsContainer {
+ display: flex;
+ margin: 0.5rem 0 1.5rem 0;
+}
+
+.btncon .btnsContainer .input {
+ flex: 1;
+ min-width: 18rem;
+ position: relative;
+}
+
+.btncon .btnsContainer input {
+ outline: 1px solid var(--bs-gray-400);
+}
+
+.btncon .btnsContainer .input button {
+ width: 52px;
+}
+
+.noOutline input:disabled {
+ -webkit-text-fill-color: black !important;
+}
+
+.noOutline textarea:disabled {
+ color: var(--bs-black) !important;
+ opacity: 1;
+}
+
+.inputField {
+ margin-top: 10px;
+ margin-bottom: 10px;
+ background-color: white;
+ box-shadow: 0 1px 1px var(--brand-primary);
+}
+
+.inputField > button {
+ padding-top: 10px;
+ padding-bottom: 10px;
+}
+
+.dropdowns {
+ background-color: white;
+ border: 1px solid #31bb6b;
+ position: relative;
+ display: inline-block;
+ color: #31bb6b;
+}
+
+/* Action Items Data Grid */
+.rowBackgrounds {
+ background-color: var(--bs-white);
+ max-height: 120px;
+}
+
+.tableHeaders {
+ background-color: var(--bs-primary);
+ color: var(--bs-white);
+ font-size: 1rem;
+}
+
+.chipIcon {
+ height: 0.9rem !important;
+}
+
+.chip {
+ height: 1.5rem !important;
+}
+
+.active {
+ background-color: var(--status-active-bg);
+}
+
+.pending {
+ background-color: var(--status-pending-bg);
+ color: var(--status-pending-text);
+ border-color: var(--status-pending-border);
+}
+
+/* Modals */
+.itemModal {
+ max-width: 80vw;
+ margin-top: 2vh;
+ margin-left: 13vw;
+}
+
+.titlemodal {
+ color: #707070;
+ font-weight: 600;
+ font-size: 32px;
+ width: 65%;
+ margin-bottom: 0px;
+}
+
+.modalCloseBtn {
+ width: 40px;
+ height: 40px;
+ padding: 1rem;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+}
+
+.imageContainer {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ margin-right: 0.5rem;
+}
+
+.TableImages {
+ object-fit: cover;
+ width: var(--image-width, 100%);
+ height: var(--image-height, auto);
+ border-radius: 0;
+ margin-right: var(--image-spacing, 8px);
+}
+
+.avatarContainer {
+ width: 28px;
+ height: 26px;
+}
+
+/* Modal Table (Groups & Assignments) */
+.modalTable {
+ max-height: 220px;
+ overflow-y: auto;
+}
From 139e9854a3b37079fa09d8e6a4cec53cc6883e4c Mon Sep 17 00:00:00 2001
From: Abhishek Raj <113784630+abbi4code@users.noreply.github.com>
Date: Sun, 22 Dec 2024 20:15:55 +0530
Subject: [PATCH 038/133] chore: migrated checkinwrapper tests jest to vitest
(#2709)
---
...InWrapper.test.tsx => CheckInWrapper.spec.tsx} | 15 ++++++++++++++-
1 file changed, 14 insertions(+), 1 deletion(-)
rename src/components/CheckIn/{CheckInWrapper.test.tsx => CheckInWrapper.spec.tsx} (76%)
diff --git a/src/components/CheckIn/CheckInWrapper.test.tsx b/src/components/CheckIn/CheckInWrapper.spec.tsx
similarity index 76%
rename from src/components/CheckIn/CheckInWrapper.test.tsx
rename to src/components/CheckIn/CheckInWrapper.spec.tsx
index 81f53d0043..06b2695f88 100644
--- a/src/components/CheckIn/CheckInWrapper.test.tsx
+++ b/src/components/CheckIn/CheckInWrapper.spec.tsx
@@ -13,6 +13,19 @@ import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
import { checkInQueryMock } from './mocks';
import { StaticMockLink } from 'utils/StaticMockLink';
+/**
+ * This file contains unit tests for the CheckInWrapper component.
+ *
+ * The tests cover:
+ * - Rendering and behavior of the modal component.
+ * - Functionality of the button to open and close the modal.
+ * - Integration with mocked GraphQL queries for testing Apollo Client.
+ *
+ * Purpose:
+ * These tests ensure that the CheckInWrapper component behaves as expected
+ * when opening and closing modals, and correctly integrates with its dependencies.
+ */
+
const link = new StaticMockLink(checkInQueryMock, true);
describe('Testing CheckIn Wrapper', () => {
@@ -20,7 +33,7 @@ describe('Testing CheckIn Wrapper', () => {
eventId: 'event123',
};
- test('The button to open and close the modal should work properly', async () => {
+ it('The button to open and close the modal should work properly', async () => {
render(
From 685a12c3566e4d32f02da96a7e8a65bdaee2bed9 Mon Sep 17 00:00:00 2001
From: Mayank Jha <132004139+MayankJha014@users.noreply.github.com>
Date: Mon, 23 Dec 2024 03:46:05 +0530
Subject: [PATCH 039/133] manage tag css to app.module (#2722)
* manage tag css to app.module
* coderaddit ai chnages
---
src/screens/ManageTag/ManageTag.module.css | 127 ---------------------
src/style/app.module.css | 40 ++++---
2 files changed, 23 insertions(+), 144 deletions(-)
delete mode 100644 src/screens/ManageTag/ManageTag.module.css
diff --git a/src/screens/ManageTag/ManageTag.module.css b/src/screens/ManageTag/ManageTag.module.css
deleted file mode 100644
index deecd4a9b7..0000000000
--- a/src/screens/ManageTag/ManageTag.module.css
+++ /dev/null
@@ -1,127 +0,0 @@
-.btnsContainer {
- display: flex;
- margin: 2rem 0;
-}
-
-.btnsContainer .btnsBlock {
- display: flex;
- width: max-content;
-}
-
-.btnsContainer .btnsBlock button {
- margin-left: 1rem;
- display: flex;
- justify-content: center;
- align-items: center;
-}
-
-.btnsContainer .input {
- flex: 1;
- position: relative;
- max-width: 60%;
- justify-content: space-between;
-}
-
-.btnsContainer input {
- outline: 1px solid var(--bs-gray-400);
-}
-
-.btnsContainer .input button {
- width: 52px;
-}
-
-@media (max-width: 1020px) {
- .btnsContainer {
- flex-direction: column;
- margin: 1.5rem 0;
- }
-
- .btnsContainer .btnsBlock {
- margin: 1.5rem 0 0 0;
- justify-content: space-between;
- }
-
- .btnsContainer .btnsBlock button {
- margin: 0;
- }
-
- .btnsContainer .btnsBlock div button {
- margin-right: 1.5rem;
- }
-}
-
-/* For mobile devices */
-
-@media (max-width: 520px) {
- .btnsContainer {
- margin-bottom: 0;
- }
-
- .btnsContainer .btnsBlock {
- display: block;
- margin-top: 1rem;
- margin-right: 0;
- }
-
- .btnsContainer .btnsBlock div {
- flex: 1;
- }
-
- .btnsContainer .btnsBlock div[title='Sort organizations'] {
- margin-right: 0.5rem;
- }
-
- .btnsContainer .btnsBlock button {
- margin-bottom: 1rem;
- margin-right: 0;
- width: 100%;
- }
-}
-
-.errorContainer {
- min-height: 100vh;
-}
-
-.errorMessage {
- margin-top: 25%;
- display: flex;
- justify-content: center;
- align-items: center;
- flex-direction: column;
-}
-
-.errorIcon {
- transform: scale(1.5);
- color: var(--bs-danger);
- margin-bottom: 1rem;
-}
-
-.tableHeader {
- background-color: var(--bs-primary);
- color: var(--bs-white);
- font-size: 1rem;
-}
-
-.rowBackground {
- background-color: var(--bs-white);
- max-height: 120px;
-}
-
-.tagsBreadCrumbs {
- color: var(--bs-gray);
- cursor: pointer;
-}
-
-.tagsBreadCrumbs:hover {
- color: var(--bs-blue);
- font-weight: 600;
- text-decoration: underline;
-}
-
-.manageTagScrollableDiv {
- scrollbar-width: thin;
- scrollbar-color: var(--bs-gray-400) var(--bs-white);
-
- max-height: calc(100vh - 18rem);
- overflow: auto;
-}
diff --git a/src/style/app.module.css b/src/style/app.module.css
index 365b00556b..56dc7e8854 100644
--- a/src/style/app.module.css
+++ b/src/style/app.module.css
@@ -218,6 +218,7 @@
.btnsContainer .btnsBlock {
display: flex;
+ width: max-content;
}
.btnsContainer .btnsBlock button {
@@ -230,6 +231,12 @@
.btnsContainer .input {
flex: 1;
position: relative;
+ max-width: 60%;
+ justify-content: space-between;
+}
+
+.btnsContainer input {
+ outline: 1px solid var(--bs-gray-400);
}
.btnsContainer .input button {
@@ -363,6 +370,8 @@
.rowBackground {
background-color: var(--row-background);
+ max-height: 120px;
+ overflow-y: auto;
}
.tableHeader {
@@ -430,6 +439,20 @@
cursor: pointer;
}
+.manageTagScrollableDiv {
+ scrollbar-width: thin;
+ scrollbar-color: var(--bs-gray-400) var(--bs-white);
+
+ max-height: calc(100vh - 18rem);
+ overflow: auto;
+}
+
+.tagsBreadCrumbs:hover {
+ color: var(--bs-blue);
+ font-weight: 600;
+ text-decoration: underline;
+}
+
.orgUserTagsScrollableDiv {
scrollbar-width: auto;
scrollbar-color: var(--bs-gray-400) var(--bs-white);
@@ -727,11 +750,6 @@ hr {
}
}
-.btnsContainer .btnsBlock {
- display: flex;
- width: max-content;
-}
-
.btnsContainer .btnsBlock button {
margin-left: 1rem;
display: flex;
@@ -739,13 +757,6 @@ hr {
align-items: center;
}
-.btnsContainer .input {
- flex: 1;
- position: relative;
- max-width: 60%;
- justify-content: space-between;
-}
-
.btnsContainer input {
outline: 1px solid var(--bs-gray-400);
}
@@ -815,11 +826,6 @@ hr {
color: var(--bs-white);
font-size: 1rem;
}
-.rowBackground {
- background-color: var(--bs-white);
- max-height: 120px;
- overflow-y: auto;
-}
.subTagsLink {
color: var(--bs-blue);
From e31ccf655d122726fef4d87a29f9dcf85d966763 Mon Sep 17 00:00:00 2001
From: Syed Ali Ul Hasan
Date: Mon, 23 Dec 2024 03:55:50 +0530
Subject: [PATCH 040/133] refactored
src/screens/UserPortal/Volunteer/Invitations from jest to vitest (#2723)
---
...itations.test.tsx => Invitations.spec.tsx} | 25 +++++++++++--------
1 file changed, 14 insertions(+), 11 deletions(-)
rename src/screens/UserPortal/Volunteer/Invitations/{Invitations.test.tsx => Invitations.spec.tsx} (96%)
diff --git a/src/screens/UserPortal/Volunteer/Invitations/Invitations.test.tsx b/src/screens/UserPortal/Volunteer/Invitations/Invitations.spec.tsx
similarity index 96%
rename from src/screens/UserPortal/Volunteer/Invitations/Invitations.test.tsx
rename to src/screens/UserPortal/Volunteer/Invitations/Invitations.spec.tsx
index 2c0cafc6a9..867f95c1aa 100644
--- a/src/screens/UserPortal/Volunteer/Invitations/Invitations.test.tsx
+++ b/src/screens/UserPortal/Volunteer/Invitations/Invitations.spec.tsx
@@ -21,14 +21,24 @@ import {
} from './Invitations.mocks';
import { toast } from 'react-toastify';
import useLocalStorage from 'utils/useLocalstorage';
+import { vi, expect } from 'vitest';
-jest.mock('react-toastify', () => ({
+vi.mock('react-toastify', () => ({
toast: {
- success: jest.fn(),
- error: jest.fn(),
+ success: vi.fn(),
+ error: vi.fn(),
},
}));
+vi.mock('react-router-dom', async () => {
+ const actual = await vi.importActual('react-router-dom');
+ return {
+ ...actual,
+ useParams: () => ({ orgId: 'orgId' }),
+ useNavigate: vi.fn(),
+ };
+});
+
const { setItem } = useLocalStorage();
const link1 = new StaticMockLink(MOCKS);
@@ -79,19 +89,12 @@ const renderInvitations = (link: ApolloLink): RenderResult => {
};
describe('Testing Invvitations Screen', () => {
- beforeAll(() => {
- jest.mock('react-router-dom', () => ({
- ...jest.requireActual('react-router-dom'),
- useParams: () => ({ orgId: 'orgId' }),
- }));
- });
-
beforeEach(() => {
setItem('userId', 'userId');
});
afterAll(() => {
- jest.clearAllMocks();
+ vi.clearAllMocks();
});
it('should redirect to fallback URL if URL params are undefined', async () => {
From cda28369f4a71e8a7175b9bd4c7916251e647792 Mon Sep 17 00:00:00 2001
From: khushi santosh patil
<143253539+khushipatil1523@users.noreply.github.com>
Date: Mon, 23 Dec 2024 04:02:55 +0530
Subject: [PATCH 041/133] convert from jest to vitest #2486 (#2705)
* convert from jest to vitest
* changes done
* changes done
* changes done
---
...ments.test.tsx => Advertisements.spec.tsx} | 41 +++++++++++--------
1 file changed, 24 insertions(+), 17 deletions(-)
rename src/components/Advertisements/{Advertisements.test.tsx => Advertisements.spec.tsx} (96%)
diff --git a/src/components/Advertisements/Advertisements.test.tsx b/src/components/Advertisements/Advertisements.spec.tsx
similarity index 96%
rename from src/components/Advertisements/Advertisements.test.tsx
rename to src/components/Advertisements/Advertisements.spec.tsx
index 88bbb1255c..1e2d92b392 100644
--- a/src/components/Advertisements/Advertisements.test.tsx
+++ b/src/components/Advertisements/Advertisements.spec.tsx
@@ -1,4 +1,6 @@
import React, { act } from 'react';
+import { describe, test, expect, vi } from 'vitest';
+
import {
ApolloClient,
ApolloLink,
@@ -7,25 +9,28 @@ import {
InMemoryCache,
} from '@apollo/client';
import { MockedProvider } from '@apollo/client/testing';
+
import { fireEvent, render, screen } from '@testing-library/react';
-import 'jest-location-mock';
import type { DocumentNode, NormalizedCacheObject } from '@apollo/client';
import userEvent from '@testing-library/user-event';
import { BACKEND_URL } from 'Constant/constant';
-import { ADD_ADVERTISEMENT_MUTATION } from 'GraphQl/Mutations/mutations';
+
+import { ADD_ADVERTISEMENT_MUTATION } from '../../GraphQl/Mutations/mutations';
import {
ORGANIZATIONS_LIST,
ORGANIZATION_ADVERTISEMENT_LIST,
PLUGIN_GET,
-} from 'GraphQl/Queries/Queries';
+} from '../../GraphQl/Queries/Queries';
+
import { I18nextProvider } from 'react-i18next';
+
import { Provider } from 'react-redux';
import { BrowserRouter } from 'react-router-dom';
import { ToastContainer } from 'react-toastify';
-import { store } from 'state/store';
-import i18nForTest from 'utils/i18nForTest';
-import useLocalStorage from 'utils/useLocalstorage';
+import { store } from '../../state/store';
+import i18nForTest from '../../utils/i18nForTest';
+import useLocalStorage from '../../utils/useLocalstorage';
import Advertisement from './Advertisements';
const { getItem } = useLocalStorage();
@@ -50,18 +55,22 @@ const client: ApolloClient = new ApolloClient({
link: ApolloLink.from([httpLink]),
});
-jest.mock('components/AddOn/support/services/Plugin.helper', () => ({
+vi.mock('components/AddOn/support/services/Plugin.helper', () => ({
__esModule: true,
- default: jest.fn().mockImplementation(() => ({
- fetchInstalled: jest.fn().mockResolvedValue([]),
- fetchStore: jest.fn().mockResolvedValue([]),
+ default: vi.fn().mockImplementation(() => ({
+ fetchInstalled: vi.fn().mockResolvedValue([]),
+ fetchStore: vi.fn().mockResolvedValue([]),
})),
}));
let mockID: string | undefined = '1';
-jest.mock('react-router-dom', () => ({
- ...jest.requireActual('react-router-dom'),
- useParams: () => ({ orgId: mockID }),
-}));
+
+vi.mock('react-router-dom', async () => {
+ const actual = await vi.importActual('react-router-dom');
+ return {
+ ...actual,
+ useParams: () => ({ orgId: mockID }),
+ };
+});
const today = new Date();
const tomorrow = today;
@@ -466,18 +475,16 @@ describe('Testing Advertisement Component', () => {
/\b(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)\s+(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s+(\d{1,2})\s+(\d{4})\b/,
);
let dateObject = new Date();
-
if (dateMatch) {
const monthName = dateMatch[1];
const day = parseInt(dateMatch[2], 10);
const year = parseInt(dateMatch[3], 10);
-
const monthIndex =
'JanFebMarAprMayJunJulAugSepOctNovDec'.indexOf(monthName) / 3;
dateObject = new Date(year, monthIndex, day);
}
-
+ console.log(dateObject);
expect(dateObject.getTime()).toBeLessThan(new Date().getTime());
});
From 986bef80972fef714745a932d77f890cf3d1dbf7 Mon Sep 17 00:00:00 2001
From: Peter Harrison <16875803+palisadoes@users.noreply.github.com>
Date: Sun, 22 Dec 2024 14:33:24 -0800
Subject: [PATCH 042/133] Revert "convert from jest to vitest #2486 (#2705)"
(#2731)
This reverts commit cda28369f4a71e8a7175b9bd4c7916251e647792.
---
...ments.spec.tsx => Advertisements.test.tsx} | 41 ++++++++-----------
1 file changed, 17 insertions(+), 24 deletions(-)
rename src/components/Advertisements/{Advertisements.spec.tsx => Advertisements.test.tsx} (96%)
diff --git a/src/components/Advertisements/Advertisements.spec.tsx b/src/components/Advertisements/Advertisements.test.tsx
similarity index 96%
rename from src/components/Advertisements/Advertisements.spec.tsx
rename to src/components/Advertisements/Advertisements.test.tsx
index 1e2d92b392..88bbb1255c 100644
--- a/src/components/Advertisements/Advertisements.spec.tsx
+++ b/src/components/Advertisements/Advertisements.test.tsx
@@ -1,6 +1,4 @@
import React, { act } from 'react';
-import { describe, test, expect, vi } from 'vitest';
-
import {
ApolloClient,
ApolloLink,
@@ -9,28 +7,25 @@ import {
InMemoryCache,
} from '@apollo/client';
import { MockedProvider } from '@apollo/client/testing';
-
import { fireEvent, render, screen } from '@testing-library/react';
+import 'jest-location-mock';
import type { DocumentNode, NormalizedCacheObject } from '@apollo/client';
import userEvent from '@testing-library/user-event';
import { BACKEND_URL } from 'Constant/constant';
-
-import { ADD_ADVERTISEMENT_MUTATION } from '../../GraphQl/Mutations/mutations';
+import { ADD_ADVERTISEMENT_MUTATION } from 'GraphQl/Mutations/mutations';
import {
ORGANIZATIONS_LIST,
ORGANIZATION_ADVERTISEMENT_LIST,
PLUGIN_GET,
-} from '../../GraphQl/Queries/Queries';
-
+} from 'GraphQl/Queries/Queries';
import { I18nextProvider } from 'react-i18next';
-
import { Provider } from 'react-redux';
import { BrowserRouter } from 'react-router-dom';
import { ToastContainer } from 'react-toastify';
-import { store } from '../../state/store';
-import i18nForTest from '../../utils/i18nForTest';
-import useLocalStorage from '../../utils/useLocalstorage';
+import { store } from 'state/store';
+import i18nForTest from 'utils/i18nForTest';
+import useLocalStorage from 'utils/useLocalstorage';
import Advertisement from './Advertisements';
const { getItem } = useLocalStorage();
@@ -55,22 +50,18 @@ const client: ApolloClient = new ApolloClient({
link: ApolloLink.from([httpLink]),
});
-vi.mock('components/AddOn/support/services/Plugin.helper', () => ({
+jest.mock('components/AddOn/support/services/Plugin.helper', () => ({
__esModule: true,
- default: vi.fn().mockImplementation(() => ({
- fetchInstalled: vi.fn().mockResolvedValue([]),
- fetchStore: vi.fn().mockResolvedValue([]),
+ default: jest.fn().mockImplementation(() => ({
+ fetchInstalled: jest.fn().mockResolvedValue([]),
+ fetchStore: jest.fn().mockResolvedValue([]),
})),
}));
let mockID: string | undefined = '1';
-
-vi.mock('react-router-dom', async () => {
- const actual = await vi.importActual('react-router-dom');
- return {
- ...actual,
- useParams: () => ({ orgId: mockID }),
- };
-});
+jest.mock('react-router-dom', () => ({
+ ...jest.requireActual('react-router-dom'),
+ useParams: () => ({ orgId: mockID }),
+}));
const today = new Date();
const tomorrow = today;
@@ -475,16 +466,18 @@ describe('Testing Advertisement Component', () => {
/\b(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)\s+(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s+(\d{1,2})\s+(\d{4})\b/,
);
let dateObject = new Date();
+
if (dateMatch) {
const monthName = dateMatch[1];
const day = parseInt(dateMatch[2], 10);
const year = parseInt(dateMatch[3], 10);
+
const monthIndex =
'JanFebMarAprMayJunJulAugSepOctNovDec'.indexOf(monthName) / 3;
dateObject = new Date(year, monthIndex, day);
}
- console.log(dateObject);
+
expect(dateObject.getTime()).toBeLessThan(new Date().getTime());
});
From 3c6f6dae1f1aa00dc64a99331a167669b8a52375 Mon Sep 17 00:00:00 2001
From: IITI-tushar <165766280+IITI-tushar@users.noreply.github.com>
Date: Mon, 23 Dec 2024 04:05:16 +0530
Subject: [PATCH 043/133] Add AdvertisementEntry.spec.tsx for Vitest migration
(#2680)
* Add AdvertisementEntry.spec.tsx for Vitest migration
* Update AdvertisementEntry.spec.tsx removes eslint-disable
* Update AdvertisementEntry.spec.tsx
* Update AdvertisementEntry.spec.tsx
* Update AdvertisementEntry.spec.tsx
* Update AdvertisementEntry.spec.tsx
* Update AdvertisementEntry.spec.tsx
* Update AdvertisementEntry.spec.tsx
* Update AdvertisementEntry.spec.tsx
* Update AdvertisementEntry.spec.tsx
* Update AdvertisementEntry.spec.tsx
* Update AdvertisementEntry.spec.tsx
---
.../AdvertisementEntry.spec.tsx | 649 ++++++++++++++++++
1 file changed, 649 insertions(+)
create mode 100644 src/components/Advertisements/core/AdvertisementEntry/AdvertisementEntry.spec.tsx
diff --git a/src/components/Advertisements/core/AdvertisementEntry/AdvertisementEntry.spec.tsx b/src/components/Advertisements/core/AdvertisementEntry/AdvertisementEntry.spec.tsx
new file mode 100644
index 0000000000..4d27df6e22
--- /dev/null
+++ b/src/components/Advertisements/core/AdvertisementEntry/AdvertisementEntry.spec.tsx
@@ -0,0 +1,649 @@
+import React from 'react';
+import { render, fireEvent, waitFor, screen } from '@testing-library/react';
+import {
+ ApolloClient,
+ ApolloProvider,
+ InMemoryCache,
+ ApolloLink,
+ HttpLink,
+} from '@apollo/client';
+import type { NormalizedCacheObject } from '@apollo/client';
+import { BrowserRouter } from 'react-router-dom';
+import AdvertisementEntry from './AdvertisementEntry';
+import AdvertisementRegister from '../AdvertisementRegister/AdvertisementRegister';
+import { Provider } from 'react-redux';
+import { store } from 'state/store';
+import { BACKEND_URL } from 'Constant/constant';
+import i18nForTest from 'utils/i18nForTest';
+import { I18nextProvider } from 'react-i18next';
+import dayjs from 'dayjs';
+import useLocalStorage from 'utils/useLocalstorage';
+import { MockedProvider } from '@apollo/client/testing';
+import { ORGANIZATION_ADVERTISEMENT_LIST } from 'GraphQl/Queries/OrganizationQueries';
+import { DELETE_ADVERTISEMENT_BY_ID } from 'GraphQl/Mutations/mutations';
+import { describe, it, expect, vi, beforeEach } from 'vitest';
+import '@testing-library/jest-dom';
+
+const { getItem } = useLocalStorage();
+
+const httpLink = new HttpLink({
+ uri: BACKEND_URL,
+ headers: {
+ authorization: 'Bearer ' + getItem('token') || '',
+ },
+});
+const translations = JSON.parse(
+ JSON.stringify(
+ i18nForTest.getDataByLanguage('en')?.translation?.advertisement ?? null,
+ ),
+);
+
+const client: ApolloClient = new ApolloClient({
+ cache: new InMemoryCache(),
+ link: ApolloLink.from([httpLink]),
+});
+
+const mockUseMutation = vi.fn();
+vi.mock('@apollo/client', async () => {
+ const actual = await vi.importActual('@apollo/client');
+ return {
+ ...actual,
+ useMutation: () => mockUseMutation(),
+ };
+});
+
+vi.mock('react-router-dom', async () => {
+ const actual = await vi.importActual('react-router-dom');
+ return {
+ ...actual,
+ useParams: () => ({ orgId: '1' }),
+ };
+});
+
+describe('Testing Advertisement Entry Component', () => {
+ beforeEach(() => {
+ vi.clearAllMocks();
+ });
+
+ it('Testing rendering and deleting of advertisement', async () => {
+ const deleteAdByIdMock = vi.fn();
+ mockUseMutation.mockReturnValue([deleteAdByIdMock]);
+ const { getByTestId, getAllByText } = render(
+
+
+
+
+
+
+
+
+ ,
+ );
+
+ //Testing rendering
+ expect(getByTestId('AdEntry')).toBeInTheDocument();
+ expect(getAllByText('POPUP')[0]).toBeInTheDocument();
+ expect(getAllByText('Advert1')[0]).toBeInTheDocument();
+ expect(screen.getByTestId('media')).toBeInTheDocument();
+
+ //Testing successful deletion
+ fireEvent.click(getByTestId('moreiconbtn'));
+ fireEvent.click(getByTestId('deletebtn'));
+
+ await waitFor(() => {
+ expect(screen.getByTestId('delete_title')).toBeInTheDocument();
+ expect(screen.getByTestId('delete_body')).toBeInTheDocument();
+ });
+
+ fireEvent.click(getByTestId('delete_yes'));
+
+ await waitFor(() => {
+ expect(deleteAdByIdMock).toHaveBeenCalledWith({
+ variables: {
+ id: '1',
+ },
+ });
+ const deletedMessage = screen.queryByText('Advertisement Deleted');
+ expect(deletedMessage).toBeNull();
+ });
+
+ //Testing unsuccessful deletion
+ deleteAdByIdMock.mockRejectedValueOnce(new Error('Deletion Failed'));
+
+ fireEvent.click(getByTestId('moreiconbtn'));
+
+ fireEvent.click(getByTestId('delete_yes'));
+
+ await waitFor(() => {
+ expect(deleteAdByIdMock).toHaveBeenCalledWith({
+ variables: {
+ id: '1',
+ },
+ });
+ const deletionFailedText = screen.queryByText((content, element) => {
+ return (
+ element?.textContent === 'Deletion Failed' &&
+ element.tagName.toLowerCase() === 'div'
+ );
+ });
+ expect(deletionFailedText).toBeNull();
+ });
+ });
+
+ it('should use default props when none are provided', () => {
+ render(
+ ,
+ : void {
+ throw new Error('Function not implemented.');
+ }}
+ />,
+ );
+
+ //Check if component renders with default ''(empty string)
+ const elements = screen.getAllByText(''); // This will return an array of matching elements
+ elements.forEach((element) => expect(element).toBeInTheDocument());
+
+ // Check that the component renders with default `mediaUrl` (empty string)
+ const mediaElement = screen.getByTestId('media');
+ expect(mediaElement).toHaveAttribute('src', '');
+
+ // Check that the component renders with default `endDate`
+ const defaultEndDate = new Date().toDateString();
+ expect(screen.getByText(`Ends on ${defaultEndDate}`)).toBeInTheDocument();
+
+ // Check that the component renders with default `startDate`
+ const defaultStartDate = new Date().toDateString();
+ expect(screen.getByText(`Ends on ${defaultStartDate}`)).toBeInTheDocument(); //fix text "Ends on"?
+ });
+
+ it('should correctly override default props when values are provided', () => {
+ const mockName = 'Test Ad';
+ const mockType = 'Banner';
+ const mockMediaUrl = 'https://example.com/media.png';
+ const mockEndDate = new Date(2025, 11, 31);
+ const mockStartDate = new Date(2024, 0, 1);
+ const mockOrganizationId = 'org123';
+
+ const { getByText } = render(
+ ,
+ : void {
+ throw new Error('Function not implemented.');
+ }}
+ />,
+ );
+
+ // Check that the component renders with provided values
+ expect(getByText(mockName)).toBeInTheDocument();
+ expect(getByText(mockType)).toBeInTheDocument();
+ expect(screen.getByTestId('media')).toHaveAttribute('src', mockMediaUrl);
+ expect(
+ getByText(`Ends on ${mockEndDate.toDateString()}`),
+ ).toBeInTheDocument();
+ });
+
+ it('should open and close the dropdown when options button is clicked', () => {
+ const { getByTestId, queryByText, getAllByText } = render(
+
+
+
+
+
+
+
+
+ ,
+ );
+
+ // Test initial rendering
+ expect(getByTestId('AdEntry')).toBeInTheDocument();
+ expect(getAllByText('POPUP')[0]).toBeInTheDocument();
+ expect(getAllByText('Advert1')[0]).toBeInTheDocument();
+
+ // Test dropdown functionality
+ const optionsButton = getByTestId('moreiconbtn');
+
+ // Initially, the dropdown should not be visible
+ expect(queryByText('Edit')).toBeNull();
+
+ // Click to open the dropdown
+ fireEvent.click(optionsButton);
+
+ // After clicking the button, the dropdown should be visible
+ expect(queryByText('Edit')).toBeInTheDocument();
+
+ // Click again to close the dropdown
+ fireEvent.click(optionsButton);
+
+ // After the second click, the dropdown should be hidden again
+ expect(queryByText('Edit')).toBeNull();
+ });
+
+ it('Updates the advertisement and shows success toast on successful update', async () => {
+ const updateAdByIdMock = vi.fn().mockResolvedValue({
+ data: {
+ updateAdvertisement: {
+ advertisement: {
+ _id: '1',
+ name: 'Updated Advertisement',
+ mediaUrl: '',
+ startDate: dayjs(new Date()).add(1, 'day').format('YYYY-MM-DD'),
+ endDate: dayjs(new Date()).add(2, 'days').format('YYYY-MM-DD'),
+ type: 'BANNER',
+ },
+ },
+ },
+ });
+
+ mockUseMutation.mockReturnValue([updateAdByIdMock]);
+
+ render(
+
+
+
+
+
+
+
+
+ ,
+ );
+
+ const optionsButton = screen.getByTestId('moreiconbtn');
+ fireEvent.click(optionsButton);
+ fireEvent.click(screen.getByTestId('editBtn'));
+
+ fireEvent.change(screen.getByLabelText('Enter name of Advertisement'), {
+ target: { value: 'Updated Advertisement' },
+ });
+
+ expect(screen.getByLabelText('Enter name of Advertisement')).toHaveValue(
+ 'Updated Advertisement',
+ );
+
+ fireEvent.change(screen.getByLabelText(translations.Rtype), {
+ target: { value: 'BANNER' },
+ });
+ expect(screen.getByLabelText(translations.Rtype)).toHaveValue('BANNER');
+
+ fireEvent.change(screen.getByLabelText(translations.RstartDate), {
+ target: { value: dayjs().add(1, 'day').format('YYYY-MM-DD') },
+ });
+
+ fireEvent.change(screen.getByLabelText(translations.RendDate), {
+ target: { value: dayjs().add(2, 'days').format('YYYY-MM-DD') },
+ });
+
+ fireEvent.click(screen.getByTestId('addonupdate'));
+
+ expect(updateAdByIdMock).toHaveBeenCalledWith({
+ variables: {
+ id: '1',
+ name: 'Updated Advertisement',
+ type: 'BANNER',
+ startDate: dayjs().add(1, 'day').format('YYYY-MM-DD'),
+ endDate: dayjs().add(2, 'days').format('YYYY-MM-DD'),
+ },
+ });
+ });
+
+ it('Simulating if the mutation doesnt have data variable while updating', async () => {
+ const updateAdByIdMock = vi.fn().mockResolvedValue({
+ updateAdvertisement: {
+ _id: '1',
+ name: 'Updated Advertisement',
+ type: 'BANNER',
+ },
+ });
+
+ mockUseMutation.mockReturnValue([updateAdByIdMock]);
+
+ render(
+
+
+
+
+
+
+
+
+ ,
+ );
+
+ const optionsButton = screen.getByTestId('moreiconbtn');
+ fireEvent.click(optionsButton);
+ fireEvent.click(screen.getByTestId('editBtn'));
+
+ fireEvent.change(screen.getByLabelText('Enter name of Advertisement'), {
+ target: { value: 'Updated Advertisement' },
+ });
+
+ expect(screen.getByLabelText('Enter name of Advertisement')).toHaveValue(
+ 'Updated Advertisement',
+ );
+
+ fireEvent.change(screen.getByLabelText(translations.Rtype), {
+ target: { value: 'BANNER' },
+ });
+ expect(screen.getByLabelText(translations.Rtype)).toHaveValue('BANNER');
+
+ fireEvent.click(screen.getByTestId('addonupdate'));
+
+ expect(updateAdByIdMock).toHaveBeenCalledWith({
+ variables: {
+ id: '1',
+ name: 'Updated Advertisement',
+ type: 'BANNER',
+ },
+ });
+ });
+
+ it('Simulating if the mutation does not have data variable while registering', async () => {
+ vi.stubGlobal('location', {
+ reload: vi.fn(),
+ href: 'https://example.com/page/id=1',
+ });
+
+ const createAdByIdMock = vi.fn().mockResolvedValue({
+ data1: {
+ createAdvertisement: {
+ _id: '1',
+ },
+ },
+ });
+
+ mockUseMutation.mockReturnValue([createAdByIdMock]);
+
+ render(
+
+
+
+
+ {
+
+ }
+
+
+
+ ,
+ );
+
+ fireEvent.click(screen.getByTestId('createAdvertisement'));
+
+ fireEvent.change(screen.getByLabelText('Enter name of Advertisement'), {
+ target: { value: 'Updated Advertisement' },
+ });
+
+ expect(screen.getByLabelText('Enter name of Advertisement')).toHaveValue(
+ 'Updated Advertisement',
+ );
+
+ fireEvent.change(screen.getByLabelText(translations.Rtype), {
+ target: { value: 'BANNER' },
+ });
+ expect(screen.getByLabelText(translations.Rtype)).toHaveValue('BANNER');
+
+ fireEvent.change(screen.getByLabelText(translations.RstartDate), {
+ target: { value: '2023-01-01' },
+ });
+ expect(screen.getByLabelText(translations.RstartDate)).toHaveValue(
+ '2023-01-01',
+ );
+
+ fireEvent.change(screen.getByLabelText(translations.RendDate), {
+ target: { value: '2023-02-01' },
+ });
+ expect(screen.getByLabelText(translations.RendDate)).toHaveValue(
+ '2023-02-01',
+ );
+
+ fireEvent.click(screen.getByTestId('addonregister'));
+
+ expect(createAdByIdMock).toHaveBeenCalledWith({
+ variables: {
+ organizationId: '1',
+ name: 'Updated Advertisement',
+ file: '',
+ type: 'BANNER',
+ startDate: dayjs(new Date('2023-01-01')).format('YYYY-MM-DD'),
+ endDate: dayjs(new Date('2023-02-01')).format('YYYY-MM-DD'),
+ },
+ });
+ });
+
+ it('delete advertisement', async () => {
+ const deleteAdByIdMock = vi.fn();
+ const mocks = [
+ {
+ request: {
+ query: ORGANIZATION_ADVERTISEMENT_LIST,
+ variables: {
+ id: '1',
+ first: 2,
+ after: null,
+ last: null,
+ before: null,
+ },
+ },
+ result: {
+ data: {
+ organizations: [
+ {
+ _id: '1',
+ advertisements: {
+ edges: [
+ {
+ node: {
+ _id: '1',
+ name: 'Advertisement1',
+ startDate: '2022-01-01',
+ endDate: '2023-01-01',
+ mediaUrl: 'http://example1.com',
+ },
+ cursor: 'cursor1',
+ },
+ {
+ node: {
+ _id: '2',
+ name: 'Advertisement2',
+ startDate: '2024-02-01',
+ endDate: '2025-02-01',
+ mediaUrl: 'http://example2.com',
+ },
+ cursor: 'cursor2',
+ },
+ {
+ node: {
+ _id: '3',
+ name: 'Advertisement1',
+ startDate: '2022-01-01',
+ endDate: '2023-01-01',
+ mediaUrl: 'http://example1.com',
+ },
+ cursor: 'cursor3',
+ },
+ {
+ node: {
+ _id: '4',
+ name: 'Advertisement2',
+ startDate: '2024-02-01',
+ endDate: '2025-02-01',
+ mediaUrl: 'http://example2.com',
+ },
+ cursor: 'cursor4',
+ },
+ {
+ node: {
+ _id: '5',
+ name: 'Advertisement1',
+ startDate: '2022-01-01',
+ endDate: '2023-01-01',
+ mediaUrl: 'http://example1.com',
+ },
+ cursor: 'cursor5',
+ },
+ {
+ node: {
+ _id: '6',
+ name: 'Advertisement2',
+ startDate: '2024-02-01',
+ endDate: '2025-02-01',
+ mediaUrl: 'http://example2.com',
+ },
+ cursor: 'cursor6',
+ },
+ ],
+ pageInfo: {
+ startCursor: 'cursor1',
+ endCursor: 'cursor6',
+ hasNextPage: true,
+ hasPreviousPage: false,
+ },
+ totalCount: 8,
+ },
+ },
+ ],
+ },
+ },
+ },
+ {
+ request: {
+ query: DELETE_ADVERTISEMENT_BY_ID,
+ variables: {
+ id: '1',
+ },
+ },
+ result: {
+ data: {
+ advertisements: {
+ _id: null,
+ },
+ },
+ },
+ },
+ ];
+ mockUseMutation.mockReturnValue([deleteAdByIdMock]);
+ const { getByTestId, getAllByText } = render(
+
+
+
+
+
+
+
+
+
+
+ ,
+ );
+
+ //Testing rendering
+ expect(getByTestId('AdEntry')).toBeInTheDocument();
+ expect(getAllByText('POPUP')[0]).toBeInTheDocument();
+ expect(getAllByText('Advert1')[0]).toBeInTheDocument();
+ expect(screen.getByTestId('media')).toBeInTheDocument();
+
+ //Testing successful deletion
+ fireEvent.click(getByTestId('moreiconbtn'));
+ fireEvent.click(getByTestId('deletebtn'));
+
+ await waitFor(() => {
+ expect(screen.getByTestId('delete_title')).toBeInTheDocument();
+ expect(screen.getByTestId('delete_body')).toBeInTheDocument();
+ });
+
+ fireEvent.click(getByTestId('delete_yes'));
+
+ await waitFor(() => {
+ expect(deleteAdByIdMock).toHaveBeenCalledWith({
+ variables: {
+ id: '1',
+ },
+ });
+ const deletedMessage = screen.queryByText('Advertisement Deleted');
+ expect(deletedMessage).toBeNull();
+ });
+
+ //Testing unsuccessful deletion
+ deleteAdByIdMock.mockRejectedValueOnce(new Error('Deletion Failed'));
+
+ fireEvent.click(getByTestId('moreiconbtn'));
+
+ fireEvent.click(getByTestId('delete_yes'));
+
+ await waitFor(() => {
+ expect(deleteAdByIdMock).toHaveBeenCalledWith({
+ variables: {
+ id: '1',
+ },
+ });
+ const deletionFailedText = screen.queryByText((content, element) => {
+ return (
+ element?.textContent === 'Deletion Failed' &&
+ element.tagName.toLowerCase() === 'div'
+ );
+ });
+ expect(deletionFailedText).toBeNull();
+ });
+ });
+});
From 8633bc67eb4cfbcdeb9dc0b608683fcf17f715a6 Mon Sep 17 00:00:00 2001
From: IITI-tushar <165766280+IITI-tushar@users.noreply.github.com>
Date: Mon, 23 Dec 2024 04:06:27 +0530
Subject: [PATCH 044/133] update and rename Settings.test.tsx to
Settings.spec.tsx fixes #2579 (#2718)
* Update and rename Settings.test.tsx to Settings.spec.tsx
* Update Settings.spec.tsx- removed-deprecated-methods-suggested-by-coderabbit
---
.../{Settings.test.tsx => Settings.spec.tsx} | 38 +++++++++----------
1 file changed, 17 insertions(+), 21 deletions(-)
rename src/screens/UserPortal/Settings/{Settings.test.tsx => Settings.spec.tsx} (92%)
diff --git a/src/screens/UserPortal/Settings/Settings.test.tsx b/src/screens/UserPortal/Settings/Settings.spec.tsx
similarity index 92%
rename from src/screens/UserPortal/Settings/Settings.test.tsx
rename to src/screens/UserPortal/Settings/Settings.spec.tsx
index fd9e1ed350..39d853862f 100644
--- a/src/screens/UserPortal/Settings/Settings.test.tsx
+++ b/src/screens/UserPortal/Settings/Settings.spec.tsx
@@ -1,5 +1,6 @@
-import React, { act } from 'react';
-import { fireEvent, render, screen } from '@testing-library/react';
+import React from 'react';
+import { describe, expect, beforeAll, vi } from 'vitest';
+import { render, screen, fireEvent, act } from '@testing-library/react';
import { MockedProvider } from '@apollo/react-testing';
import { I18nextProvider } from 'react-i18next';
import { UPDATE_USER_MUTATION } from 'GraphQl/Mutations/mutations';
@@ -119,31 +120,27 @@ const resizeWindow = (width: number): void => {
async function wait(ms = 100): Promise {
await act(async () => {
- return new Promise((resolve) => {
- setTimeout(resolve, ms);
- });
+ vi.advanceTimersByTime(ms);
});
}
describe('Testing Settings Screen [User Portal]', () => {
- // Mock implementation of matchMedia
beforeAll(() => {
+ vi.useFakeTimers();
Object.defineProperty(window, 'matchMedia', {
writable: true,
- value: jest.fn().mockImplementation((query) => ({
+ value: vi.fn().mockImplementation((query) => ({
matches: false,
media: query,
onchange: null,
- addListener: jest.fn(), // Deprecated
- removeListener: jest.fn(), // Deprecated
- addEventListener: jest.fn(),
- removeEventListener: jest.fn(),
- dispatchEvent: jest.fn(),
+ addEventListener: vi.fn(),
+ removeEventListener: vi.fn(),
+ dispatchEvent: vi.fn(),
})),
});
});
- test('Screen should be rendered properly', async () => {
+ it('Screen should be rendered properly', async () => {
await act(async () => {
render(
@@ -163,7 +160,7 @@ describe('Testing Settings Screen [User Portal]', () => {
expect(screen.queryAllByText('Settings')).not.toBe([]);
});
- test('input works properly', async () => {
+ it('input works properly', async () => {
await act(async () => {
render(
@@ -220,7 +217,7 @@ describe('Testing Settings Screen [User Portal]', () => {
expect(screen.getByTestId('profile-picture')).toBeInTheDocument();
});
- test('resetChangesBtn works properly', async () => {
+ it('resetChangesBtn works properly', async () => {
await act(async () => {
render(
@@ -253,7 +250,7 @@ describe('Testing Settings Screen [User Portal]', () => {
expect(screen.getByLabelText('Birth Date')).toHaveValue('2024-03-01');
});
- test('resetChangesBtn works properly when the details are empty', async () => {
+ it('resetChangesBtn works properly when the details are empty', async () => {
await act(async () => {
render(
@@ -286,7 +283,7 @@ describe('Testing Settings Screen [User Portal]', () => {
expect(screen.getByLabelText('Birth Date')).toHaveValue('');
});
- test('sidebar', async () => {
+ it('sidebar', async () => {
await act(async () => {
render(
@@ -311,7 +308,7 @@ describe('Testing Settings Screen [User Portal]', () => {
act(() => openMenuBtn.click());
});
- test('Testing sidebar when the screen size is less than or equal to 820px', async () => {
+ it('Testing sidebar when the screen size is less than or equal to 820px', async () => {
resizeWindow(800);
await act(async () => {
render(
@@ -328,7 +325,6 @@ describe('Testing Settings Screen [User Portal]', () => {
});
await wait();
-
screen.debug();
const openMenuBtn = screen.queryByTestId('openMenu');
@@ -348,7 +344,7 @@ describe('Testing Settings Screen [User Portal]', () => {
}
});
- test('renders events attended card correctly', async () => {
+ it('renders events attended card correctly', async () => {
render(
@@ -368,7 +364,7 @@ describe('Testing Settings Screen [User Portal]', () => {
expect(screen.getByText('No Events Attended')).toBeInTheDocument();
});
- test('renders events attended card correctly with events', async () => {
+ it('renders events attended card correctly with events', async () => {
const mockEventsAttended = [
{ _id: '1', title: 'Event 1' },
{ _id: '2', title: 'Event 2' },
From 8a21cbbcb27a954820266a02bcd5e83a194ec5b0 Mon Sep 17 00:00:00 2001
From: Nikhil Raj <125121367+hustlernik@users.noreply.github.com>
Date: Mon, 23 Dec 2024 04:08:04 +0530
Subject: [PATCH 045/133] fix:smooth infinite scroll for users list (#2726)
---
src/screens/Users/Users.tsx | 112 ++++++++++++++++++------------------
1 file changed, 56 insertions(+), 56 deletions(-)
diff --git a/src/screens/Users/Users.tsx b/src/screens/Users/Users.tsx
index 3ea165d7b0..b046679a00 100644
--- a/src/screens/Users/Users.tsx
+++ b/src/screens/Users/Users.tsx
@@ -70,6 +70,7 @@ const Users = (): JSX.Element => {
const { getItem } = useLocalStorage();
const perPageResult = 12;
+ const tableLoaderRowLength = 4;
const [isLoading, setIsLoading] = useState(true);
const [hasMore, setHasMore] = useState(true);
const [isLoadingMore, setIsLoadingMore] = useState(false);
@@ -432,67 +433,66 @@ const Users = (): JSX.Element => {
) : (
- {isLoading ? (
-
- ) : (
-
- }
- hasMore={hasMore}
- className={styles.listBox}
- data-testid="users-list"
- endMessage={
-
-
{tCommon('endOfResults')}
-
- }
- >
-
-
-
- {headerTitles.map((title: string, index: number) => {
+ {isLoading && (
+
+ )}
+
+ }
+ hasMore={hasMore}
+ className={styles.listBox}
+ data-testid="users-list"
+ endMessage={
+
+
{tCommon('endOfResults')}
+
+ }
+ >
+
+
+
+ {headerTitles.map((title: string, index: number) => {
+ return (
+
+ {title}
+ |
+ );
+ })}
+
+
+
+ {usersData &&
+ displayedUsers.map(
+ (user: InterfaceQueryUserListItem, index: number) => {
return (
-
- {title}
- |
+
);
- })}
-
-
-
- {usersData &&
- displayedUsers.map(
- (user: InterfaceQueryUserListItem, index: number) => {
- return (
-
- );
- },
- )}
-
-
-
- )}
+ },
+ )}
+
+
+
)}
>
);
};
-
export default Users;
From a295db30220035bbd00ef60c7977ae63c325436c Mon Sep 17 00:00:00 2001
From: Rafiul Hasan <67283985+rafidoth@users.noreply.github.com>
Date: Mon, 23 Dec 2024 04:40:07 +0600
Subject: [PATCH 046/133] Fixes #2670 : Refactored src/screen/PageNotFound
component test from jest to vitest (#2708)
* Refactored Refactor: src/screens/PageNotFound from Jest to Vitest
* Refactored :src/screens/PageNotFound from Jest to Vitest
* Refactored :src/screens/PageNotFound from Jest to Vitest
* Refactored :src/screens/PageNotFound from Jest to Vitest
---
...otFound.test.tsx => PageNotFound.spec.tsx} | 22 +++++++++----------
1 file changed, 11 insertions(+), 11 deletions(-)
rename src/screens/PageNotFound/{PageNotFound.test.tsx => PageNotFound.spec.tsx} (68%)
diff --git a/src/screens/PageNotFound/PageNotFound.test.tsx b/src/screens/PageNotFound/PageNotFound.spec.tsx
similarity index 68%
rename from src/screens/PageNotFound/PageNotFound.test.tsx
rename to src/screens/PageNotFound/PageNotFound.spec.tsx
index 501d9f7ef3..4557eb5af4 100644
--- a/src/screens/PageNotFound/PageNotFound.test.tsx
+++ b/src/screens/PageNotFound/PageNotFound.spec.tsx
@@ -8,11 +8,11 @@ import { store } from 'state/store';
import PageNotFound from './PageNotFound';
import i18nForTest from 'utils/i18nForTest';
import useLocalStorage from 'utils/useLocalstorage';
-
+import { it, expect, describe } from 'vitest';
const { setItem } = useLocalStorage();
describe('Testing Page not found component', () => {
- test('Component should be rendered properly for User', () => {
+ it('should render component properly for User', () => {
//setItem('AdminFor', undefined);
render(
@@ -24,15 +24,15 @@ describe('Testing Page not found component', () => {
,
);
- expect(screen.getByText(/Talawa User/i)).toBeTruthy();
- expect(screen.getByText(/404/i)).toBeTruthy();
+ expect(screen.getByText(/Talawa User/i)).toBeInTheDocument();
+ expect(screen.getByText(/404/i)).toBeInTheDocument();
expect(
screen.getByText(/Oops! The Page you requested was not found!/i),
- ).toBeTruthy();
- expect(screen.getByText(/Back to Home/i)).toBeTruthy();
+ ).toBeInTheDocument();
+ expect(screen.getByText(/Back to Home/i)).toBeInTheDocument();
});
- test('Component should be rendered properly for ADMIN or SUPERADMIN', () => {
+ it('should render properly for ADMIN or SUPERADMIN', () => {
setItem('AdminFor', [
{
_id: '6537904485008f171cf29924',
@@ -49,11 +49,11 @@ describe('Testing Page not found component', () => {
,
);
- expect(screen.getByText(/Talawa Admin Portal/i)).toBeTruthy();
- expect(screen.getByText(/404/i)).toBeTruthy();
+ expect(screen.getByText(/Talawa Admin Portal/i)).toBeInTheDocument();
+ expect(screen.getByText(/404/i)).toBeInTheDocument();
expect(
screen.getByText(/Oops! The Page you requested was not found!/i),
- ).toBeTruthy();
- expect(screen.getByText(/Back to Home/i)).toBeTruthy();
+ ).toBeInTheDocument();
+ expect(screen.getByText(/Back to Home/i)).toBeInTheDocument();
});
});
From d5a790d262477fd1a79cc0acfbcccfad20bea969 Mon Sep 17 00:00:00 2001
From: Vedant Gupta <115912707+im-vedant@users.noreply.github.com>
Date: Mon, 23 Dec 2024 04:12:07 +0530
Subject: [PATCH 047/133] Refactor: src/screens/OrganizationVenues from Jest to
Vitest (#2665)
* Refactored some code
* Migrate src/screens/OrganizationVenues from jest to vitest
* Revert "Refactored some code"
This reverts commit 02eb9d4fa59009ba81d93d5b137ba2d0f95eae23.
* replaced vi.mock with vi.doMock
* Add comments
* Suppressed Css error
* Fix customTableCell issue
* add data-testid attributes for toggle state for improved testability
* feat: updated jest config and package-lock.json to include identity-obj-proxy to mock Css modules
* Fix linting errors
* refactor : src\components\MemberDetail\customTableCell.test.tsx and src\components\OrganizationScreen\OrganizationScreen.test.tsx from jest to vitest
* Removed data-expanded attribute from mainpageright div
* Add test cases in src/components/MemberDetail/CustomTableCell
---------
Co-authored-by: im-vedant <194vedantgutpa@gmail.com>
Co-authored-by: Peter Harrison <16875803+palisadoes@users.noreply.github.com>
---
.../MemberDetail/customTableCell.spec.tsx | 160 ++++++++++++++++
.../MemberDetail/customTableCell.test.tsx | 171 ------------------
...n.test.tsx => OrganizationScreen.spec.tsx} | 7 +-
...s.test.tsx => OrganizationVenues.spec.tsx} | 38 ++--
4 files changed, 187 insertions(+), 189 deletions(-)
create mode 100644 src/components/MemberDetail/customTableCell.spec.tsx
delete mode 100644 src/components/MemberDetail/customTableCell.test.tsx
rename src/components/OrganizationScreen/{OrganizationScreen.test.tsx => OrganizationScreen.spec.tsx} (95%)
rename src/screens/OrganizationVenues/{OrganizationVenues.test.tsx => OrganizationVenues.spec.tsx} (92%)
diff --git a/src/components/MemberDetail/customTableCell.spec.tsx b/src/components/MemberDetail/customTableCell.spec.tsx
new file mode 100644
index 0000000000..81a088d5bb
--- /dev/null
+++ b/src/components/MemberDetail/customTableCell.spec.tsx
@@ -0,0 +1,160 @@
+import React from 'react';
+import { render, screen, waitFor } from '@testing-library/react';
+import { MockedProvider } from '@apollo/client/testing';
+import { BrowserRouter } from 'react-router-dom';
+import { CustomTableCell } from './customTableCell';
+import { EVENT_DETAILS } from 'GraphQl/Queries/Queries';
+import { vi } from 'vitest';
+vi.mock('react-toastify', () => ({
+ toast: {
+ success: vi.fn(),
+ error: vi.fn(),
+ },
+}));
+
+const mocks = [
+ {
+ request: {
+ query: EVENT_DETAILS,
+ variables: { id: 'event123' },
+ },
+ result: {
+ data: {
+ event: {
+ _id: 'event123',
+ title: 'Test Event',
+ description: 'This is a test event description',
+ startDate: '2023-05-01',
+ endDate: '2023-05-02',
+ startTime: '09:00:00',
+ endTime: '17:00:00',
+ allDay: false,
+ location: 'Test Location',
+ recurring: true,
+ baseRecurringEvent: {
+ _id: 'recurringEvent123',
+ },
+ organization: {
+ _id: 'org456',
+ members: [
+ { _id: 'member1', firstName: 'John', lastName: 'Doe' },
+ { _id: 'member2', firstName: 'Jane', lastName: 'Smith' },
+ ],
+ },
+ attendees: [{ _id: 'user1' }, { _id: 'user2' }],
+ },
+ },
+ },
+ },
+];
+
+describe('CustomTableCell', () => {
+ it('renders event details correctly', async () => {
+ render(
+
+
+
+
+ ,
+ );
+
+ await waitFor(() => screen.getByTestId('custom-row'));
+
+ expect(screen.getByText('Test Event')).toBeInTheDocument();
+ expect(
+ screen.getByText(
+ new Date('2023-05-01').toLocaleDateString(undefined, {
+ year: 'numeric',
+ month: 'long',
+ day: 'numeric',
+ timeZone: 'UTC',
+ }),
+ ),
+ ).toBeInTheDocument();
+ expect(screen.getByText('Yes')).toBeInTheDocument();
+ expect(screen.getByText('2')).toBeInTheDocument();
+
+ const link = screen.getByRole('link', { name: 'Test Event' });
+ expect(link).toHaveAttribute('href', '/event/org456/event123');
+ });
+
+ it('displays loading state', () => {
+ render(
+
+
+ ,
+ );
+
+ expect(screen.getByRole('progressbar')).toBeInTheDocument();
+ });
+
+ it('displays error state', async () => {
+ const errorMock = [
+ {
+ request: {
+ query: EVENT_DETAILS,
+ variables: { id: 'event123' },
+ },
+ error: new Error('An error occurred'),
+ },
+ ];
+
+ render(
+
+
+ ,
+ );
+
+ await waitFor(() => {
+ expect(
+ screen.getByText(
+ 'Unable to load event details. Please try again later.',
+ ),
+ ).toBeInTheDocument();
+ });
+ });
+
+ it('displays no event found message', async () => {
+ const noEventMock = [
+ {
+ request: {
+ query: EVENT_DETAILS,
+ variables: { id: 'event123' },
+ },
+ result: {
+ data: {
+ event: null,
+ },
+ },
+ },
+ ];
+
+ render(
+
+
+ ,
+ );
+
+ await waitFor(() => {
+ expect(
+ screen.getByText('Event not found or has been deleted'),
+ ).toBeInTheDocument();
+ });
+ });
+});
diff --git a/src/components/MemberDetail/customTableCell.test.tsx b/src/components/MemberDetail/customTableCell.test.tsx
deleted file mode 100644
index bc296a74f3..0000000000
--- a/src/components/MemberDetail/customTableCell.test.tsx
+++ /dev/null
@@ -1,171 +0,0 @@
-import React from 'react';
-import { render, screen, waitFor } from '@testing-library/react';
-import { MockedProvider } from '@apollo/client/testing';
-import { BrowserRouter } from 'react-router-dom';
-import { CustomTableCell } from './customTableCell';
-import { EVENT_DETAILS } from 'GraphQl/Queries/Queries';
-
-jest.mock('react-toastify', () => ({
- toast: {
- success: jest.fn(),
- error: jest.fn(),
- },
-}));
-
-const mocks = [
- {
- request: {
- query: EVENT_DETAILS,
- variables: { id: 'event123' },
- },
- result: {
- data: {
- event: {
- _id: 'event123',
- title: 'Test Event',
- description: 'This is a test event description',
- startDate: '2023-05-01',
- endDate: '2023-05-02',
- startTime: '09:00:00',
- endTime: '17:00:00',
- allDay: false,
- location: 'Test Location',
- recurring: true,
- baseRecurringEvent: {
- _id: 'recurringEvent123',
- },
- organization: {
- _id: 'org456',
- members: [
- { _id: 'member1', firstName: 'John', lastName: 'Doe' },
- { _id: 'member2', firstName: 'Jane', lastName: 'Smith' },
- ],
- },
- attendees: [{ _id: 'user1' }, { _id: 'user2' }],
- },
- },
- },
- },
-];
-
-describe('CustomTableCell', () => {
- it('renders event details correctly', async () => {
- render(
-
-
-
-
- ,
- );
-
- await waitFor(() => screen.getByTestId('custom-row'));
-
- expect(screen.getByText('Test Event')).toBeInTheDocument();
- expect(screen.getByText('May 1, 2023')).toBeInTheDocument();
- expect(screen.getByText('Yes')).toBeInTheDocument();
- expect(screen.getByText('2')).toBeInTheDocument();
-
- const link = screen.getByRole('link', { name: 'Test Event' });
- expect(link).toHaveAttribute('href', '/event/org456/event123');
- });
-
- it('displays loading state', () => {
- render(
-
-
- ,
- );
-
- expect(screen.getByRole('progressbar')).toBeInTheDocument();
- });
-
- // it('displays error state', async () => {
- // const errorMock = [
- // {
- // request: {
- // query: EVENT_DETAILS,
- // variables: { id: 'event123' },
- // },
- // error: new Error('An error occurred'),
- // },
- // ];
-
- // render(
- //
- //
- // ,
- // );
-
- // await waitFor(
- // () => {
- // expect(
- // screen.getByText('Error loading event details'),
- // ).toBeInTheDocument();
- // },
- // { timeout: 2000 },
- // );
-
- // // Check if the error message from toast has been called
- // expect(toast.error).toHaveBeenCalledWith('An error occurred');
- // });
-
- // it('displays no event found message', async () => {
- // const noEventMock = [
- // {
- // request: {
- // query: EVENT_DETAILS,
- // variables: { id: 'event123' },
- // },
- // result: {
- // data: {
- // event: {
- // _id: null,
- // title: null,
- // startDate: null,
- // description: null,
- // endDate: null,
- // startTime: null,
- // endTime: null,
- // allDay: false,
- // location: null,
- // recurring: null,
- // organization: {
- // _id: null,
- // members: [],
- // },
- // baseRecurringEvent: {
- // _id: 'recurringEvent123',
- // },
- // attendees: [],
- // },
- // },
- // },
- // },
- // ];
-
- // render(
- //
- //
- // ,
- // );
-
- // await waitFor(() => screen.getByText('No event found'));
- // expect(screen.getByText('No event found')).toBeInTheDocument();
- // });
-});
diff --git a/src/components/OrganizationScreen/OrganizationScreen.test.tsx b/src/components/OrganizationScreen/OrganizationScreen.spec.tsx
similarity index 95%
rename from src/components/OrganizationScreen/OrganizationScreen.test.tsx
rename to src/components/OrganizationScreen/OrganizationScreen.spec.tsx
index d1c4c81c27..e6a75c46d8 100644
--- a/src/components/OrganizationScreen/OrganizationScreen.test.tsx
+++ b/src/components/OrganizationScreen/OrganizationScreen.spec.tsx
@@ -2,7 +2,6 @@ import React from 'react';
import { MockedProvider } from '@apollo/react-testing';
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
import { I18nextProvider } from 'react-i18next';
-import 'jest-location-mock';
import { Provider } from 'react-redux';
import { BrowserRouter } from 'react-router-dom';
import { store } from 'state/store';
@@ -11,10 +10,10 @@ import OrganizationScreen from './OrganizationScreen';
import { ORGANIZATION_EVENT_LIST } from 'GraphQl/Queries/Queries';
import { StaticMockLink } from 'utils/StaticMockLink';
import styles from './OrganizationScreen.module.css';
-
+import { vi } from 'vitest';
const mockID: string | undefined = '123';
-jest.mock('react-router-dom', () => ({
- ...jest.requireActual('react-router-dom'),
+vi.mock('react-router-dom', async () => ({
+ ...(await vi.importActual('react-router-dom')),
useParams: () => ({ orgId: mockID }),
useMatch: () => ({ params: { eventId: 'event123', orgId: '123' } }),
}));
diff --git a/src/screens/OrganizationVenues/OrganizationVenues.test.tsx b/src/screens/OrganizationVenues/OrganizationVenues.spec.tsx
similarity index 92%
rename from src/screens/OrganizationVenues/OrganizationVenues.test.tsx
rename to src/screens/OrganizationVenues/OrganizationVenues.spec.tsx
index 5b8b9933a1..e306c56cfc 100644
--- a/src/screens/OrganizationVenues/OrganizationVenues.test.tsx
+++ b/src/screens/OrganizationVenues/OrganizationVenues.spec.tsx
@@ -1,3 +1,15 @@
+/**
+ * Tests for the OrganizationVenues component.
+ * These tests include:
+ * - Ensuring the component renders correctly with default props.
+ * - Handling the absence of `orgId` by redirecting to the homepage.
+ * - Fetching and displaying venues via Apollo GraphQL queries.
+ * - Allowing users to search venues by name or description.
+ * - Sorting venues by capacity in ascending or descending order.
+ * - Verifying that long venue names or descriptions are handled gracefully.
+ * - Testing loading states and edge cases for Apollo queries.
+ * - Mocking GraphQL mutations for venue-related actions and validating their behavior.
+ */
import React from 'react';
import { MockedProvider } from '@apollo/react-testing';
import type { RenderResult } from '@testing-library/react';
@@ -10,7 +22,6 @@ import {
} from '@testing-library/react';
import { Provider } from 'react-redux';
import { MemoryRouter, Route, Routes } from 'react-router-dom';
-import 'jest-location-mock';
import { I18nextProvider } from 'react-i18next';
import OrganizationVenues from './OrganizationVenues';
import { store } from 'state/store';
@@ -19,7 +30,7 @@ import { StaticMockLink } from 'utils/StaticMockLink';
import { VENUE_LIST } from 'GraphQl/Queries/OrganizationQueries';
import type { ApolloLink } from '@apollo/client';
import { DELETE_VENUE_MUTATION } from 'GraphQl/Mutations/VenueMutations';
-
+import { vi } from 'vitest';
const MOCKS = [
{
request: {
@@ -239,11 +250,11 @@ async function wait(ms = 100): Promise
{
});
}
-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(),
},
}));
@@ -272,14 +283,14 @@ const renderOrganizationVenue = (link: ApolloLink): RenderResult => {
describe('OrganizationVenue with missing orgId', () => {
beforeAll(() => {
- jest.mock('react-router-dom', () => ({
- ...jest.requireActual('react-router-dom'),
+ vi.doMock('react-router-dom', async () => ({
+ ...(await vi.importActual('react-router-dom')),
useParams: () => ({ orgId: undefined }),
}));
});
afterAll(() => {
- jest.clearAllMocks();
+ vi.clearAllMocks();
});
test('Redirect to /orglist when orgId is falsy/undefined', async () => {
render(
@@ -299,7 +310,6 @@ describe('OrganizationVenue with missing orgId', () => {
,
);
-
await waitFor(() => {
const paramsError = screen.getByTestId('paramsError');
expect(paramsError).toBeInTheDocument();
@@ -308,17 +318,17 @@ describe('OrganizationVenue with missing orgId', () => {
});
describe('Organisation Venues', () => {
- global.alert = jest.fn();
+ global.alert = vi.fn();
beforeAll(() => {
- jest.mock('react-router-dom', () => ({
- ...jest.requireActual('react-router-dom'),
+ vi.doMock('react-router-dom', async () => ({
+ ...(await vi.importActual('react-router-dom')),
useParams: () => ({ orgId: 'orgId' }),
}));
});
afterAll(() => {
- jest.clearAllMocks();
+ vi.clearAllMocks();
});
test('searches the venue list correctly by Name', async () => {
From 9108753fc80fb7014fda74caa9419a5e33d0179e Mon Sep 17 00:00:00 2001
From: Aaditya Agarwal
Date: Mon, 23 Dec 2024 04:14:58 +0530
Subject: [PATCH 048/133] Upgrade inquirer version to 11.0.2 (#2720)
* upgraded inqurier version
* updated custom port tests
* chaged isnan with number.isnan
* added tests for invalid port
* added reserved ports functionality
* improved type safety, maintainability and organisation
* added clear all mocks
---
package-lock.json | 1015 +++++++----------
package.json | 2 +-
.../askForCustomPort/askForCustomPort.test.ts | 112 +-
.../askForCustomPort/askForCustomPort.ts | 65 +-
.../askForTalawaApiUrl.test.ts | 14 +-
.../askForTalawaApiUrl/askForTalawaApiUrl.ts | 2 +-
6 files changed, 577 insertions(+), 633 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 24478f4f69..07a65a79c6 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -41,7 +41,7 @@
"i18next": "^23.15.1",
"i18next-browser-languagedetector": "^8.0.0",
"i18next-http-backend": "^2.6.1",
- "inquirer": "^8.0.0",
+ "inquirer": "^11.0.2",
"js-cookie": "^3.0.1",
"lcov-result-merger": "^5.0.1",
"markdown-toc": "^1.2.0",
@@ -99,7 +99,6 @@
"@typescript-eslint/eslint-plugin": "^8.11.0",
"@typescript-eslint/parser": "^8.5.0",
"@vitest/coverage-istanbul": "^2.1.5",
- "@vitest/eslint-plugin": "^1.1.14",
"babel-jest": "^29.7.0",
"cross-env": "^7.0.3",
"eslint": "^8.49.0",
@@ -109,7 +108,6 @@
"eslint-plugin-prettier": "^5.2.1",
"eslint-plugin-react": "^7.37.1",
"eslint-plugin-tsdoc": "^0.3.0",
- "eslint-plugin-vitest": "^0.5.4",
"husky": "^9.1.6",
"identity-obj-proxy": "^3.0.0",
"jest": "^27.4.5",
@@ -3159,6 +3157,239 @@
"dev": true,
"license": "BSD-3-Clause"
},
+ "node_modules/@inquirer/checkbox": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-3.0.1.tgz",
+ "integrity": "sha512-0hm2nrToWUdD6/UHnel/UKGdk1//ke5zGUpHIvk5ZWmaKezlGxZkOJXNSWsdxO/rEqTkbB3lNC2J6nBElV2aAQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@inquirer/core": "^9.2.1",
+ "@inquirer/figures": "^1.0.6",
+ "@inquirer/type": "^2.0.0",
+ "ansi-escapes": "^4.3.2",
+ "yoctocolors-cjs": "^2.1.2"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@inquirer/confirm": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-4.0.1.tgz",
+ "integrity": "sha512-46yL28o2NJ9doViqOy0VDcoTzng7rAb6yPQKU7VDLqkmbCaH4JqK4yk4XqlzNWy9PVC5pG1ZUXPBQv+VqnYs2w==",
+ "license": "MIT",
+ "dependencies": {
+ "@inquirer/core": "^9.2.1",
+ "@inquirer/type": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@inquirer/core": {
+ "version": "9.2.1",
+ "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-9.2.1.tgz",
+ "integrity": "sha512-F2VBt7W/mwqEU4bL0RnHNZmC/OxzNx9cOYxHqnXX3MP6ruYvZUZAW9imgN9+h/uBT/oP8Gh888J2OZSbjSeWcg==",
+ "license": "MIT",
+ "dependencies": {
+ "@inquirer/figures": "^1.0.6",
+ "@inquirer/type": "^2.0.0",
+ "@types/mute-stream": "^0.0.4",
+ "@types/node": "^22.5.5",
+ "@types/wrap-ansi": "^3.0.0",
+ "ansi-escapes": "^4.3.2",
+ "cli-width": "^4.1.0",
+ "mute-stream": "^1.0.0",
+ "signal-exit": "^4.1.0",
+ "strip-ansi": "^6.0.1",
+ "wrap-ansi": "^6.2.0",
+ "yoctocolors-cjs": "^2.1.2"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@inquirer/core/node_modules/signal-exit": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
+ "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/@inquirer/core/node_modules/wrap-ansi": {
+ "version": "6.2.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
+ "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/@inquirer/editor": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-3.0.1.tgz",
+ "integrity": "sha512-VA96GPFaSOVudjKFraokEEmUQg/Lub6OXvbIEZU1SDCmBzRkHGhxoFAVaF30nyiB4m5cEbDgiI2QRacXZ2hw9Q==",
+ "license": "MIT",
+ "dependencies": {
+ "@inquirer/core": "^9.2.1",
+ "@inquirer/type": "^2.0.0",
+ "external-editor": "^3.1.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@inquirer/expand": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-3.0.1.tgz",
+ "integrity": "sha512-ToG8d6RIbnVpbdPdiN7BCxZGiHOTomOX94C2FaT5KOHupV40tKEDozp12res6cMIfRKrXLJyexAZhWVHgbALSQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@inquirer/core": "^9.2.1",
+ "@inquirer/type": "^2.0.0",
+ "yoctocolors-cjs": "^2.1.2"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@inquirer/figures": {
+ "version": "1.0.9",
+ "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.9.tgz",
+ "integrity": "sha512-BXvGj0ehzrngHTPTDqUoDT3NXL8U0RxUk2zJm2A66RhCEIWdtU1v6GuUqNAgArW4PQ9CinqIWyHdQgdwOj06zQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@inquirer/input": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-3.0.1.tgz",
+ "integrity": "sha512-BDuPBmpvi8eMCxqC5iacloWqv+5tQSJlUafYWUe31ow1BVXjW2a5qe3dh4X/Z25Wp22RwvcaLCc2siHobEOfzg==",
+ "license": "MIT",
+ "dependencies": {
+ "@inquirer/core": "^9.2.1",
+ "@inquirer/type": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@inquirer/number": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-2.0.1.tgz",
+ "integrity": "sha512-QpR8jPhRjSmlr/mD2cw3IR8HRO7lSVOnqUvQa8scv1Lsr3xoAMMworcYW3J13z3ppjBFBD2ef1Ci6AE5Qn8goQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@inquirer/core": "^9.2.1",
+ "@inquirer/type": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@inquirer/password": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-3.0.1.tgz",
+ "integrity": "sha512-haoeEPUisD1NeE2IanLOiFr4wcTXGWrBOyAyPZi1FfLJuXOzNmxCJPgUrGYKVh+Y8hfGJenIfz5Wb/DkE9KkMQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@inquirer/core": "^9.2.1",
+ "@inquirer/type": "^2.0.0",
+ "ansi-escapes": "^4.3.2"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@inquirer/prompts": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-6.0.1.tgz",
+ "integrity": "sha512-yl43JD/86CIj3Mz5mvvLJqAOfIup7ncxfJ0Btnl0/v5TouVUyeEdcpknfgc+yMevS/48oH9WAkkw93m7otLb/A==",
+ "license": "MIT",
+ "dependencies": {
+ "@inquirer/checkbox": "^3.0.1",
+ "@inquirer/confirm": "^4.0.1",
+ "@inquirer/editor": "^3.0.1",
+ "@inquirer/expand": "^3.0.1",
+ "@inquirer/input": "^3.0.1",
+ "@inquirer/number": "^2.0.1",
+ "@inquirer/password": "^3.0.1",
+ "@inquirer/rawlist": "^3.0.1",
+ "@inquirer/search": "^2.0.1",
+ "@inquirer/select": "^3.0.1"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@inquirer/rawlist": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-3.0.1.tgz",
+ "integrity": "sha512-VgRtFIwZInUzTiPLSfDXK5jLrnpkuSOh1ctfaoygKAdPqjcjKYmGh6sCY1pb0aGnCGsmhUxoqLDUAU0ud+lGXQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@inquirer/core": "^9.2.1",
+ "@inquirer/type": "^2.0.0",
+ "yoctocolors-cjs": "^2.1.2"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@inquirer/search": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-2.0.1.tgz",
+ "integrity": "sha512-r5hBKZk3g5MkIzLVoSgE4evypGqtOannnB3PKTG9NRZxyFRKcfzrdxXXPcoJQsxJPzvdSU2Rn7pB7lw0GCmGAg==",
+ "license": "MIT",
+ "dependencies": {
+ "@inquirer/core": "^9.2.1",
+ "@inquirer/figures": "^1.0.6",
+ "@inquirer/type": "^2.0.0",
+ "yoctocolors-cjs": "^2.1.2"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@inquirer/select": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-3.0.1.tgz",
+ "integrity": "sha512-lUDGUxPhdWMkN/fHy1Lk7pF3nK1fh/gqeyWXmctefhxLYxlDsc7vsPBEpxrfVGDsVdyYJsiJoD4bJ1b623cV1Q==",
+ "license": "MIT",
+ "dependencies": {
+ "@inquirer/core": "^9.2.1",
+ "@inquirer/figures": "^1.0.6",
+ "@inquirer/type": "^2.0.0",
+ "ansi-escapes": "^4.3.2",
+ "yoctocolors-cjs": "^2.1.2"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@inquirer/type": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-2.0.0.tgz",
+ "integrity": "sha512-XvJRx+2KR3YXyYtPUUy+qd9i7p+GO9Ko6VIIpWlBrpWwXDv8WLFeHTxz35CfQFUiBMLXlGHhGzys7lqit9gWag==",
+ "license": "MIT",
+ "dependencies": {
+ "mute-stream": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
"node_modules/@isaacs/cliui": {
"version": "8.0.2",
"resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
@@ -5706,11 +5937,19 @@
"@types/unist": "*"
}
},
+ "node_modules/@types/mute-stream": {
+ "version": "0.0.4",
+ "resolved": "https://registry.npmjs.org/@types/mute-stream/-/mute-stream-0.0.4.tgz",
+ "integrity": "sha512-CPM9nzrCPPJHQNA9keH9CVkVI+WR5kMa+7XEs5jcGQ0VoAGnLv242w8lIVgwAEfmE4oufJRaTc9PNLQl0ioAow==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
"node_modules/@types/node": {
"version": "22.9.0",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.9.0.tgz",
"integrity": "sha512-vuyHg81vvWA1Z1ELfvLko2c8f34gyA0zaic0+Rllc5lbCnbSyuvb2Oxpm6TAUAC/2xZN3QGqxBNggD1nNR2AfQ==",
- "devOptional": true,
"dependencies": {
"undici-types": "~6.19.8"
}
@@ -5908,6 +6147,12 @@
"resolved": "https://registry.npmjs.org/@types/warning/-/warning-3.0.3.tgz",
"integrity": "sha512-D1XC7WK8K+zZEveUPY+cf4+kgauk8N4eHr/XIHXGlGYkHLud6hK9lYfZk1ry1TNh798cZUCgb6MqGEG8DkJt6Q=="
},
+ "node_modules/@types/wrap-ansi": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/@types/wrap-ansi/-/wrap-ansi-3.0.0.tgz",
+ "integrity": "sha512-ltIpx+kM7g/MLRZfkbL7EsCEjfzCcScLpkg37eXEtx5kmrAKBkTJwd1GIAjDSL8wTpM6Hzn5YO4pSb91BEwu1g==",
+ "license": "MIT"
+ },
"node_modules/@types/yargs": {
"version": "16.0.5",
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz",
@@ -6379,36 +6624,15 @@
"node": ">=18"
}
},
- "node_modules/@vitest/eslint-plugin": {
- "version": "1.1.14",
- "resolved": "https://registry.npmjs.org/@vitest/eslint-plugin/-/eslint-plugin-1.1.14.tgz",
- "integrity": "sha512-ej0cT5rUt7uvwxuu7Qxkm7fI+eaOq8vD34qGpuRoXCdvOybOlE5GDqtgvVCYbxLANkcRJfm5VDU1TnJmQRHi9g==",
- "dev": true,
- "license": "MIT",
- "peerDependencies": {
- "@typescript-eslint/utils": ">= 8.0",
- "eslint": ">= 8.57.0",
- "typescript": ">= 5.0.0",
- "vitest": "*"
- },
- "peerDependenciesMeta": {
- "typescript": {
- "optional": true
- },
- "vitest": {
- "optional": true
- }
- }
- },
"node_modules/@vitest/expect": {
- "version": "2.1.8",
- "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-2.1.8.tgz",
- "integrity": "sha512-8ytZ/fFHq2g4PJVAtDX57mayemKgDR6X3Oa2Foro+EygiOJHUXhCqBAAKQYYajZpFoIfvBCF1j6R6IYRSIUFuw==",
+ "version": "2.1.5",
+ "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-2.1.5.tgz",
+ "integrity": "sha512-nZSBTW1XIdpZvEJyoP/Sy8fUg0b8od7ZpGDkTUcfJ7wz/VoZAFzFfLyxVxGFhUjJzhYqSbIpfMtl/+k/dpWa3Q==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@vitest/spy": "2.1.8",
- "@vitest/utils": "2.1.8",
+ "@vitest/spy": "2.1.5",
+ "@vitest/utils": "2.1.5",
"chai": "^5.1.2",
"tinyrainbow": "^1.2.0"
},
@@ -6417,13 +6641,13 @@
}
},
"node_modules/@vitest/mocker": {
- "version": "2.1.8",
- "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-2.1.8.tgz",
- "integrity": "sha512-7guJ/47I6uqfttp33mgo6ga5Gr1VnL58rcqYKyShoRK9ebu8T5Rs6HN3s1NABiBeVTdWNrwUMcHH54uXZBN4zA==",
+ "version": "2.1.5",
+ "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-2.1.5.tgz",
+ "integrity": "sha512-XYW6l3UuBmitWqSUXTNXcVBUCRytDogBsWuNXQijc00dtnU/9OqpXWp4OJroVrad/gLIomAq9aW8yWDBtMthhQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@vitest/spy": "2.1.8",
+ "@vitest/spy": "2.1.5",
"estree-walker": "^3.0.3",
"magic-string": "^0.30.12"
},
@@ -6457,13 +6681,13 @@
}
},
"node_modules/@vitest/runner": {
- "version": "2.1.8",
- "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-2.1.8.tgz",
- "integrity": "sha512-17ub8vQstRnRlIU5k50bG+QOMLHRhYPAna5tw8tYbj+jzjcspnwnwtPtiOlkuKC4+ixDPTuLZiqiWWQ2PSXHVg==",
+ "version": "2.1.5",
+ "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-2.1.5.tgz",
+ "integrity": "sha512-pKHKy3uaUdh7X6p1pxOkgkVAFW7r2I818vHDthYLvUyjRfkKOU6P45PztOch4DZarWQne+VOaIMwA/erSSpB9g==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@vitest/utils": "2.1.8",
+ "@vitest/utils": "2.1.5",
"pathe": "^1.1.2"
},
"funding": {
@@ -6471,13 +6695,13 @@
}
},
"node_modules/@vitest/snapshot": {
- "version": "2.1.8",
- "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-2.1.8.tgz",
- "integrity": "sha512-20T7xRFbmnkfcmgVEz+z3AU/3b0cEzZOt/zmnvZEctg64/QZbSDJEVm9fLnnlSi74KibmRsO9/Qabi+t0vCRPg==",
+ "version": "2.1.5",
+ "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-2.1.5.tgz",
+ "integrity": "sha512-zmYw47mhfdfnYbuhkQvkkzYroXUumrwWDGlMjpdUr4jBd3HZiV2w7CQHj+z7AAS4VOtWxI4Zt4bWt4/sKcoIjg==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@vitest/pretty-format": "2.1.8",
+ "@vitest/pretty-format": "2.1.5",
"magic-string": "^0.30.12",
"pathe": "^1.1.2"
},
@@ -6485,10 +6709,23 @@
"url": "https://opencollective.com/vitest"
}
},
+ "node_modules/@vitest/snapshot/node_modules/@vitest/pretty-format": {
+ "version": "2.1.5",
+ "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-2.1.5.tgz",
+ "integrity": "sha512-4ZOwtk2bqG5Y6xRGHcveZVr+6txkH7M2e+nPFd6guSoN638v/1XQ0K06eOpi0ptVU/2tW/pIU4IoPotY/GZ9fw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "tinyrainbow": "^1.2.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
"node_modules/@vitest/spy": {
- "version": "2.1.8",
- "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-2.1.8.tgz",
- "integrity": "sha512-5swjf2q95gXeYPevtW0BLk6H8+bPlMb4Vw/9Em4hFxDcaOxS+e0LOX4yqNxoHzMR2akEB2xfpnWUzkZokmgWDg==",
+ "version": "2.1.5",
+ "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-2.1.5.tgz",
+ "integrity": "sha512-aWZF3P0r3w6DiYTVskOYuhBc7EMc3jvn1TkBg8ttylFFRqNN2XGD7V5a4aQdk6QiUzZQ4klNBSpCLJgWNdIiNw==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -6499,13 +6736,13 @@
}
},
"node_modules/@vitest/utils": {
- "version": "2.1.8",
- "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-2.1.8.tgz",
- "integrity": "sha512-dwSoui6djdwbfFmIgbIjX2ZhIoG7Ex/+xpxyiEgIGzjliY8xGkcpITKTlp6B4MgtGkF2ilvm97cPM96XZaAgcA==",
+ "version": "2.1.5",
+ "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-2.1.5.tgz",
+ "integrity": "sha512-yfj6Yrp0Vesw2cwJbP+cl04OC+IHFsuQsrsJBL9pyGeQXE56v1UAOQco+SR55Vf1nQzfV0QJg1Qum7AaWUwwYg==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@vitest/pretty-format": "2.1.8",
+ "@vitest/pretty-format": "2.1.5",
"loupe": "^3.1.2",
"tinyrainbow": "^1.2.0"
},
@@ -6513,6 +6750,19 @@
"url": "https://opencollective.com/vitest"
}
},
+ "node_modules/@vitest/utils/node_modules/@vitest/pretty-format": {
+ "version": "2.1.5",
+ "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-2.1.5.tgz",
+ "integrity": "sha512-4ZOwtk2bqG5Y6xRGHcveZVr+6txkH7M2e+nPFd6guSoN638v/1XQ0K06eOpi0ptVU/2tW/pIU4IoPotY/GZ9fw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "tinyrainbow": "^1.2.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
"node_modules/@wry/caches": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@wry/caches/-/caches-1.0.1.tgz",
@@ -6780,16 +7030,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/array-union": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
- "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/array.prototype.findlast": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz",
@@ -7364,39 +7604,6 @@
"node": ">=8"
}
},
- "node_modules/bl": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
- "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==",
- "dependencies": {
- "buffer": "^5.5.0",
- "inherits": "^2.0.4",
- "readable-stream": "^3.4.0"
- }
- },
- "node_modules/bl/node_modules/buffer": {
- "version": "5.7.1",
- "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
- "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/feross"
- },
- {
- "type": "patreon",
- "url": "https://www.patreon.com/feross"
- },
- {
- "type": "consulting",
- "url": "https://feross.org/support"
- }
- ],
- "dependencies": {
- "base64-js": "^1.3.1",
- "ieee754": "^1.1.13"
- }
- },
"node_modules/bn.js": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz",
@@ -7914,7 +8121,8 @@
"node_modules/chardet": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz",
- "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA=="
+ "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==",
+ "license": "MIT"
},
"node_modules/chart.js": {
"version": "4.4.6",
@@ -8030,17 +8238,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/cli-spinners": {
- "version": "2.9.2",
- "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz",
- "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==",
- "engines": {
- "node": ">=6"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
"node_modules/cli-truncate": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-4.0.0.tgz",
@@ -8108,11 +8305,12 @@
}
},
"node_modules/cli-width": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz",
- "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==",
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz",
+ "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==",
+ "license": "ISC",
"engines": {
- "node": ">= 10"
+ "node": ">= 12"
}
},
"node_modules/cliui": {
@@ -8859,25 +9057,6 @@
"node": ">=0.10.0"
}
},
- "node_modules/defaults": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz",
- "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==",
- "dependencies": {
- "clone": "^1.0.2"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/defaults/node_modules/clone": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz",
- "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==",
- "engines": {
- "node": ">=0.8"
- }
- },
"node_modules/defer-to-connect": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz",
@@ -9029,19 +9208,6 @@
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz",
"integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg=="
},
- "node_modules/dir-glob": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
- "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "path-type": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/doctrine": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
@@ -9851,221 +10017,68 @@
"string.prototype.matchall": "^4.0.11",
"string.prototype.repeat": "^1.0.0"
},
- "engines": {
- "node": ">=4"
- },
- "peerDependencies": {
- "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7"
- }
- },
- "node_modules/eslint-plugin-react/node_modules/doctrine": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
- "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
- "dev": true,
- "dependencies": {
- "esutils": "^2.0.2"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/eslint-plugin-react/node_modules/estraverse": {
- "version": "5.3.0",
- "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
- "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
- "dev": true,
- "engines": {
- "node": ">=4.0"
- }
- },
- "node_modules/eslint-plugin-react/node_modules/resolve": {
- "version": "2.0.0-next.5",
- "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz",
- "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==",
- "dev": true,
- "dependencies": {
- "is-core-module": "^2.13.0",
- "path-parse": "^1.0.7",
- "supports-preserve-symlinks-flag": "^1.0.0"
- },
- "bin": {
- "resolve": "bin/resolve"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/eslint-plugin-react/node_modules/semver": {
- "version": "6.3.1",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
- "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
- "dev": true,
- "bin": {
- "semver": "bin/semver.js"
- }
- },
- "node_modules/eslint-plugin-tsdoc": {
- "version": "0.3.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-tsdoc/-/eslint-plugin-tsdoc-0.3.0.tgz",
- "integrity": "sha512-0MuFdBrrJVBjT/gyhkP2BqpD0np1NxNLfQ38xXDlSs/KVVpKI2A6vN7jx2Rve/CyUsvOsMGwp9KKrinv7q9g3A==",
- "dev": true,
- "dependencies": {
- "@microsoft/tsdoc": "0.15.0",
- "@microsoft/tsdoc-config": "0.17.0"
- }
- },
- "node_modules/eslint-plugin-vitest": {
- "version": "0.5.4",
- "resolved": "https://registry.npmjs.org/eslint-plugin-vitest/-/eslint-plugin-vitest-0.5.4.tgz",
- "integrity": "sha512-um+odCkccAHU53WdKAw39MY61+1x990uXjSPguUCq3VcEHdqJrOb8OTMrbYlY6f9jAKx7x98kLVlIe3RJeJqoQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@typescript-eslint/utils": "^7.7.1"
- },
- "engines": {
- "node": "^18.0.0 || >= 20.0.0"
- },
- "peerDependencies": {
- "eslint": "^8.57.0 || ^9.0.0",
- "vitest": "*"
- },
- "peerDependenciesMeta": {
- "@typescript-eslint/eslint-plugin": {
- "optional": true
- },
- "vitest": {
- "optional": true
- }
- }
- },
- "node_modules/eslint-plugin-vitest/node_modules/@typescript-eslint/scope-manager": {
- "version": "7.18.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.18.0.tgz",
- "integrity": "sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@typescript-eslint/types": "7.18.0",
- "@typescript-eslint/visitor-keys": "7.18.0"
- },
- "engines": {
- "node": "^18.18.0 || >=20.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- }
- },
- "node_modules/eslint-plugin-vitest/node_modules/@typescript-eslint/types": {
- "version": "7.18.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz",
- "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": "^18.18.0 || >=20.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- }
- },
- "node_modules/eslint-plugin-vitest/node_modules/@typescript-eslint/typescript-estree": {
- "version": "7.18.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.18.0.tgz",
- "integrity": "sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA==",
- "dev": true,
- "license": "BSD-2-Clause",
- "dependencies": {
- "@typescript-eslint/types": "7.18.0",
- "@typescript-eslint/visitor-keys": "7.18.0",
- "debug": "^4.3.4",
- "globby": "^11.1.0",
- "is-glob": "^4.0.3",
- "minimatch": "^9.0.4",
- "semver": "^7.6.0",
- "ts-api-utils": "^1.3.0"
- },
- "engines": {
- "node": "^18.18.0 || >=20.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependenciesMeta": {
- "typescript": {
- "optional": true
- }
- }
- },
- "node_modules/eslint-plugin-vitest/node_modules/@typescript-eslint/utils": {
- "version": "7.18.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.18.0.tgz",
- "integrity": "sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@eslint-community/eslint-utils": "^4.4.0",
- "@typescript-eslint/scope-manager": "7.18.0",
- "@typescript-eslint/types": "7.18.0",
- "@typescript-eslint/typescript-estree": "7.18.0"
- },
- "engines": {
- "node": "^18.18.0 || >=20.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
+ "engines": {
+ "node": ">=4"
+ },
"peerDependencies": {
- "eslint": "^8.56.0"
+ "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7"
}
},
- "node_modules/eslint-plugin-vitest/node_modules/@typescript-eslint/visitor-keys": {
- "version": "7.18.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.18.0.tgz",
- "integrity": "sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==",
+ "node_modules/eslint-plugin-react/node_modules/doctrine": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
+ "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
"dev": true,
- "license": "MIT",
"dependencies": {
- "@typescript-eslint/types": "7.18.0",
- "eslint-visitor-keys": "^3.4.3"
+ "esutils": "^2.0.2"
},
"engines": {
- "node": "^18.18.0 || >=20.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
+ "node": ">=0.10.0"
}
},
- "node_modules/eslint-plugin-vitest/node_modules/brace-expansion": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
- "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+ "node_modules/eslint-plugin-react/node_modules/estraverse": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+ "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
"dev": true,
- "license": "MIT",
- "dependencies": {
- "balanced-match": "^1.0.0"
+ "engines": {
+ "node": ">=4.0"
}
},
- "node_modules/eslint-plugin-vitest/node_modules/minimatch": {
- "version": "9.0.5",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
- "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
+ "node_modules/eslint-plugin-react/node_modules/resolve": {
+ "version": "2.0.0-next.5",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz",
+ "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==",
"dev": true,
- "license": "ISC",
"dependencies": {
- "brace-expansion": "^2.0.1"
+ "is-core-module": "^2.13.0",
+ "path-parse": "^1.0.7",
+ "supports-preserve-symlinks-flag": "^1.0.0"
},
- "engines": {
- "node": ">=16 || 14 >=14.17"
+ "bin": {
+ "resolve": "bin/resolve"
},
"funding": {
- "url": "https://github.com/sponsors/isaacs"
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/eslint-plugin-react/node_modules/semver": {
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+ "dev": true,
+ "bin": {
+ "semver": "bin/semver.js"
+ }
+ },
+ "node_modules/eslint-plugin-tsdoc": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-tsdoc/-/eslint-plugin-tsdoc-0.3.0.tgz",
+ "integrity": "sha512-0MuFdBrrJVBjT/gyhkP2BqpD0np1NxNLfQ38xXDlSs/KVVpKI2A6vN7jx2Rve/CyUsvOsMGwp9KKrinv7q9g3A==",
+ "dev": true,
+ "dependencies": {
+ "@microsoft/tsdoc": "0.15.0",
+ "@microsoft/tsdoc-config": "0.17.0"
}
},
"node_modules/eslint-visitor-keys": {
@@ -10508,6 +10521,7 @@
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz",
"integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==",
+ "license": "MIT",
"dependencies": {
"chardet": "^0.7.0",
"iconv-lite": "^0.4.24",
@@ -10521,6 +10535,7 @@
"version": "0.4.24",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
"integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+ "license": "MIT",
"dependencies": {
"safer-buffer": ">= 2.1.2 < 3"
},
@@ -10606,28 +10621,6 @@
"bser": "2.1.1"
}
},
- "node_modules/figures": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz",
- "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==",
- "dependencies": {
- "escape-string-regexp": "^1.0.5"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/figures/node_modules/escape-string-regexp": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
- "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
- "engines": {
- "node": ">=0.8.0"
- }
- },
"node_modules/file-entry-cache": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
@@ -11062,27 +11055,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/globby": {
- "version": "11.1.0",
- "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
- "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "array-union": "^2.1.0",
- "dir-glob": "^3.0.1",
- "fast-glob": "^3.2.9",
- "ignore": "^5.2.0",
- "merge2": "^1.4.1",
- "slash": "^3.0.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
"node_modules/globrex": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz",
@@ -11242,6 +11214,7 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
"engines": {
"node": ">=8"
}
@@ -11744,79 +11717,22 @@
"dev": true
},
"node_modules/inquirer": {
- "version": "8.2.6",
- "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.6.tgz",
- "integrity": "sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg==",
- "dependencies": {
- "ansi-escapes": "^4.2.1",
- "chalk": "^4.1.1",
- "cli-cursor": "^3.1.0",
- "cli-width": "^3.0.0",
- "external-editor": "^3.0.3",
- "figures": "^3.0.0",
- "lodash": "^4.17.21",
- "mute-stream": "0.0.8",
- "ora": "^5.4.1",
- "run-async": "^2.4.0",
- "rxjs": "^7.5.5",
- "string-width": "^4.1.0",
- "strip-ansi": "^6.0.0",
- "through": "^2.3.6",
- "wrap-ansi": "^6.0.1"
- },
- "engines": {
- "node": ">=12.0.0"
- }
- },
- "node_modules/inquirer/node_modules/chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dependencies": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/chalk?sponsor=1"
- }
- },
- "node_modules/inquirer/node_modules/cli-cursor": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz",
- "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==",
- "dependencies": {
- "restore-cursor": "^3.1.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/inquirer/node_modules/restore-cursor": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz",
- "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==",
- "dependencies": {
- "onetime": "^5.1.0",
- "signal-exit": "^3.0.2"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/inquirer/node_modules/wrap-ansi": {
- "version": "6.2.0",
- "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
- "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
+ "version": "11.1.0",
+ "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-11.1.0.tgz",
+ "integrity": "sha512-CmLAZT65GG/v30c+D2Fk8+ceP6pxD6RL+hIUOWAltCmeyEqWYwqu9v76q03OvjyZ3AB0C1Ala2stn1z/rMqGEw==",
+ "license": "MIT",
"dependencies": {
- "ansi-styles": "^4.0.0",
- "string-width": "^4.1.0",
- "strip-ansi": "^6.0.0"
+ "@inquirer/core": "^9.2.1",
+ "@inquirer/prompts": "^6.0.1",
+ "@inquirer/type": "^2.0.0",
+ "@types/mute-stream": "^0.0.4",
+ "ansi-escapes": "^4.3.2",
+ "mute-stream": "^1.0.0",
+ "run-async": "^3.0.0",
+ "rxjs": "^7.8.1"
},
"engines": {
- "node": ">=8"
+ "node": ">=18"
}
},
"node_modules/internal-slot": {
@@ -12122,14 +12038,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/is-interactive": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz",
- "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==",
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/is-map": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz",
@@ -12344,17 +12252,6 @@
"integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==",
"dev": true
},
- "node_modules/is-unicode-supported": {
- "version": "0.1.0",
- "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz",
- "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==",
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
"node_modules/is-weakmap": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz",
@@ -14688,7 +14585,8 @@
"node_modules/lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
- "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
+ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
+ "dev": true
},
"node_modules/lodash._reinterpolate": {
"version": "3.0.0",
@@ -14735,36 +14633,6 @@
"lodash._reinterpolate": "^3.0.0"
}
},
- "node_modules/log-symbols": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
- "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==",
- "dependencies": {
- "chalk": "^4.1.0",
- "is-unicode-supported": "^0.1.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/log-symbols/node_modules/chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dependencies": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/chalk?sponsor=1"
- }
- },
"node_modules/log-update": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz",
@@ -15277,6 +15145,7 @@
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
"integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
+ "dev": true,
"engines": {
"node": ">=6"
}
@@ -15377,9 +15246,13 @@
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
},
"node_modules/mute-stream": {
- "version": "0.0.8",
- "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz",
- "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA=="
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-1.0.0.tgz",
+ "integrity": "sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==",
+ "license": "ISC",
+ "engines": {
+ "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+ }
},
"node_modules/nanoid": {
"version": "3.3.7",
@@ -15793,6 +15666,7 @@
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
"integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
+ "dev": true,
"dependencies": {
"mimic-fn": "^2.1.0"
},
@@ -15870,66 +15744,6 @@
"node": ">= 0.8.0"
}
},
- "node_modules/ora": {
- "version": "5.4.1",
- "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz",
- "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==",
- "dependencies": {
- "bl": "^4.1.0",
- "chalk": "^4.1.0",
- "cli-cursor": "^3.1.0",
- "cli-spinners": "^2.5.0",
- "is-interactive": "^1.0.0",
- "is-unicode-supported": "^0.1.0",
- "log-symbols": "^4.1.0",
- "strip-ansi": "^6.0.0",
- "wcwidth": "^1.0.1"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/ora/node_modules/chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dependencies": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/chalk?sponsor=1"
- }
- },
- "node_modules/ora/node_modules/cli-cursor": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz",
- "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==",
- "dependencies": {
- "restore-cursor": "^3.1.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/ora/node_modules/restore-cursor": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz",
- "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==",
- "dependencies": {
- "onetime": "^5.1.0",
- "signal-exit": "^3.0.2"
- },
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/os-browserify": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz",
@@ -15939,6 +15753,7 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
"integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==",
+ "license": "MIT",
"engines": {
"node": ">=0.10.0"
}
@@ -17642,9 +17457,10 @@
]
},
"node_modules/run-async": {
- "version": "2.4.1",
- "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz",
- "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==",
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/run-async/-/run-async-3.0.0.tgz",
+ "integrity": "sha512-540WwVDOMxA6dN6We19EcT9sc3hkXPw5mzRNGM3FkdN/vtE9NFvj5lFAPNwUDmJjXidm3v7TC1cTE7t17Ulm1Q==",
+ "license": "MIT",
"engines": {
"node": ">=0.12.0"
}
@@ -17980,7 +17796,8 @@
"node_modules/signal-exit": {
"version": "3.0.7",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
- "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="
+ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
+ "dev": true
},
"node_modules/simple-swizzle": {
"version": "0.2.2",
@@ -18438,6 +18255,7 @@
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
"dependencies": {
"has-flag": "^4.0.0"
},
@@ -18586,11 +18404,6 @@
"node": ">=8"
}
},
- "node_modules/through": {
- "version": "2.3.8",
- "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
- "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg=="
- },
"node_modules/through2": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz",
@@ -18697,6 +18510,7 @@
"version": "0.0.33",
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
"integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
+ "license": "MIT",
"dependencies": {
"os-tmpdir": "~1.0.2"
},
@@ -19537,8 +19351,7 @@
"node_modules/undici-types": {
"version": "6.19.8",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz",
- "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==",
- "devOptional": true
+ "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw=="
},
"node_modules/unicode-canonical-property-names-ecmascript": {
"version": "2.0.1",
@@ -19958,9 +19771,9 @@
}
},
"node_modules/vite-node": {
- "version": "2.1.8",
- "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-2.1.8.tgz",
- "integrity": "sha512-uPAwSr57kYjAUux+8E2j0q0Fxpn8M9VoyfGiRI8Kfktz9NcYMCenwY5RnZxnF1WTu3TGiYipirIzacLL3VVGFg==",
+ "version": "2.1.5",
+ "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-2.1.5.tgz",
+ "integrity": "sha512-rd0QIgx74q4S1Rd56XIiL2cYEdyWn13cunYBIuqh9mpmQr7gGS0IxXoP8R6OaZtNQQLyXSWbd4rXKYUbhFpK5w==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -20292,19 +20105,19 @@
}
},
"node_modules/vitest": {
- "version": "2.1.8",
- "resolved": "https://registry.npmjs.org/vitest/-/vitest-2.1.8.tgz",
- "integrity": "sha512-1vBKTZskHw/aosXqQUlVWWlGUxSJR8YtiyZDJAFeW2kPAeX6S3Sool0mjspO+kXLuxVWlEDDowBAeqeAQefqLQ==",
+ "version": "2.1.5",
+ "resolved": "https://registry.npmjs.org/vitest/-/vitest-2.1.5.tgz",
+ "integrity": "sha512-P4ljsdpuzRTPI/kbND2sDZ4VmieerR2c9szEZpjc+98Z9ebvnXmM5+0tHEKqYZumXqlvnmfWsjeFOjXVriDG7A==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@vitest/expect": "2.1.8",
- "@vitest/mocker": "2.1.8",
- "@vitest/pretty-format": "^2.1.8",
- "@vitest/runner": "2.1.8",
- "@vitest/snapshot": "2.1.8",
- "@vitest/spy": "2.1.8",
- "@vitest/utils": "2.1.8",
+ "@vitest/expect": "2.1.5",
+ "@vitest/mocker": "2.1.5",
+ "@vitest/pretty-format": "^2.1.5",
+ "@vitest/runner": "2.1.5",
+ "@vitest/snapshot": "2.1.5",
+ "@vitest/spy": "2.1.5",
+ "@vitest/utils": "2.1.5",
"chai": "^5.1.2",
"debug": "^4.3.7",
"expect-type": "^1.1.0",
@@ -20316,7 +20129,7 @@
"tinypool": "^1.0.1",
"tinyrainbow": "^1.2.0",
"vite": "^5.0.0",
- "vite-node": "2.1.8",
+ "vite-node": "2.1.5",
"why-is-node-running": "^2.3.0"
},
"bin": {
@@ -20331,8 +20144,8 @@
"peerDependencies": {
"@edge-runtime/vm": "*",
"@types/node": "^18.0.0 || >=20.0.0",
- "@vitest/browser": "2.1.8",
- "@vitest/ui": "2.1.8",
+ "@vitest/browser": "2.1.5",
+ "@vitest/ui": "2.1.5",
"happy-dom": "*",
"jsdom": "*"
},
@@ -20409,14 +20222,6 @@
"loose-envify": "^1.0.0"
}
},
- "node_modules/wcwidth": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz",
- "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==",
- "dependencies": {
- "defaults": "^1.0.3"
- }
- },
"node_modules/web-vitals": {
"version": "4.2.4",
"resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-4.2.4.tgz",
@@ -20758,6 +20563,18 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/yoctocolors-cjs": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/yoctocolors-cjs/-/yoctocolors-cjs-2.1.2.tgz",
+ "integrity": "sha512-cYVsTjKl8b+FrnidjibDWskAv7UKOfcwaVZdp/it9n1s9fU3IkgDbhdIRKCW4JDsAlECJY0ytoVPT3sK6kideA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/zen-observable": {
"version": "0.8.15",
"resolved": "https://registry.npmjs.org/zen-observable/-/zen-observable-0.8.15.tgz",
diff --git a/package.json b/package.json
index aee85b5772..a922f88205 100644
--- a/package.json
+++ b/package.json
@@ -38,7 +38,7 @@
"i18next": "^23.15.1",
"i18next-browser-languagedetector": "^8.0.0",
"i18next-http-backend": "^2.6.1",
- "inquirer": "^8.0.0",
+ "inquirer": "^11.0.2",
"js-cookie": "^3.0.1",
"lcov-result-merger": "^5.0.1",
"markdown-toc": "^1.2.0",
diff --git a/src/setup/askForCustomPort/askForCustomPort.test.ts b/src/setup/askForCustomPort/askForCustomPort.test.ts
index 0df6259ba1..c46f7b3f91 100644
--- a/src/setup/askForCustomPort/askForCustomPort.test.ts
+++ b/src/setup/askForCustomPort/askForCustomPort.test.ts
@@ -1,24 +1,110 @@
import inquirer from 'inquirer';
-import { askForCustomPort } from './askForCustomPort';
+import { askForCustomPort, validatePort } from './askForCustomPort';
jest.mock('inquirer');
describe('askForCustomPort', () => {
- test('should return default port if user provides no input', async () => {
- jest
- .spyOn(inquirer, 'prompt')
- .mockResolvedValueOnce({ customPort: '4321' });
+ beforeEach(() => {
+ jest.clearAllMocks();
+ });
+
+ describe('basic port validation', () => {
+ test('should return default port if user provides no input', async () => {
+ jest
+ .spyOn(inquirer, 'prompt')
+ .mockResolvedValueOnce({ customPort: '4321' });
+
+ const result = await askForCustomPort();
+ expect(result).toBe(4321);
+ });
+
+ test('should return user-provided port', async () => {
+ jest
+ .spyOn(inquirer, 'prompt')
+ .mockResolvedValueOnce({ customPort: '8080' });
+
+ const result = await askForCustomPort();
+ expect(result).toBe(8080);
+ });
+
+ test('should return validation error if port not between 1 and 65535', () => {
+ expect(validatePort('abcd')).toBe(
+ 'Please enter a valid port number between 1 and 65535.',
+ );
+ expect(validatePort('-1')).toBe(
+ 'Please enter a valid port number between 1 and 65535.',
+ );
+ expect(validatePort('70000')).toBe(
+ 'Please enter a valid port number between 1 and 65535.',
+ );
+ });
+ });
- const result = await askForCustomPort();
- expect(result).toBe('4321');
+ describe('retry mechanism', () => {
+ test('should handle invalid port input and prompt again', async () => {
+ jest
+ .spyOn(inquirer, 'prompt')
+ .mockResolvedValueOnce({ customPort: 'abcd' })
+ .mockResolvedValueOnce({ customPort: '8080' });
+
+ const result = await askForCustomPort();
+ expect(result).toBe(8080);
+ });
+
+ test('should return default port after maximum retry attempts', async () => {
+ jest
+ .spyOn(inquirer, 'prompt')
+ .mockResolvedValueOnce({ customPort: 'invalid-port-attempt1' })
+ .mockResolvedValueOnce({ customPort: 'invalid-port-attempt2' })
+ .mockResolvedValueOnce({ customPort: 'invalid-port-attempt3' })
+ .mockResolvedValueOnce({ customPort: 'invalid-port-attempt4' })
+ .mockResolvedValueOnce({ customPort: 'invalid-port-attempt5' })
+ .mockResolvedValueOnce({ customPort: 'invalid-port-attempt6' });
+
+ const result = await askForCustomPort();
+ expect(result).toBe(4321);
+ });
});
- test('should return user-provided port', async () => {
- jest
- .spyOn(inquirer, 'prompt')
- .mockResolvedValueOnce({ customPort: '8080' });
+ describe('reserved ports', () => {
+ test('should return user-provided port after confirming reserved port', async () => {
+ jest
+ .spyOn(inquirer, 'prompt')
+ .mockResolvedValueOnce({ customPort: '80' })
+ .mockResolvedValueOnce({ confirmPort: true });
+
+ const result = await askForCustomPort();
+ expect(result).toBe(80);
+ });
+
+ test('should re-prompt user for port if reserved port confirmation is denied', async () => {
+ jest
+ .spyOn(inquirer, 'prompt')
+ .mockResolvedValueOnce({ customPort: '80' })
+ .mockResolvedValueOnce({ confirmPort: false })
+ .mockResolvedValueOnce({ customPort: '8080' });
+
+ const result = await askForCustomPort();
+ expect(result).toBe(8080);
+ });
+
+ test('should return default port if reserved port confirmation is denied after maximum retry attempts', async () => {
+ jest
+ .spyOn(inquirer, 'prompt')
+ .mockResolvedValueOnce({ customPort: '80' })
+ .mockResolvedValueOnce({ confirmPort: false })
+ .mockResolvedValueOnce({ customPort: '80' })
+ .mockResolvedValueOnce({ confirmPort: false })
+ .mockResolvedValueOnce({ customPort: '80' })
+ .mockResolvedValueOnce({ confirmPort: false })
+ .mockResolvedValueOnce({ customPort: '80' })
+ .mockResolvedValueOnce({ confirmPort: false })
+ .mockResolvedValueOnce({ customPort: '80' })
+ .mockResolvedValueOnce({ confirmPort: false })
+ .mockResolvedValueOnce({ customPort: '80' });
- const result = await askForCustomPort();
- expect(result).toBe('8080');
+ const result = await askForCustomPort();
+ expect(result).toBe(4321);
+ });
});
});
diff --git a/src/setup/askForCustomPort/askForCustomPort.ts b/src/setup/askForCustomPort/askForCustomPort.ts
index 8a923f678f..dd0fd51854 100644
--- a/src/setup/askForCustomPort/askForCustomPort.ts
+++ b/src/setup/askForCustomPort/askForCustomPort.ts
@@ -1,14 +1,63 @@
import inquirer from 'inquirer';
-export async function askForCustomPort(): Promise {
- const { customPort } = await inquirer.prompt([
+const DEFAULT_PORT = 4321;
+const MAX_RETRY_ATTEMPTS = 5;
+
+export function validatePort(input: string): string | boolean {
+ const port = Number(input);
+ if (
+ Number.isNaN(port) ||
+ !Number.isInteger(port) ||
+ port <= 0 ||
+ port > 65535
+ ) {
+ return 'Please enter a valid port number between 1 and 65535.';
+ }
+ return true;
+}
+
+export async function reservedPortWarning(port: number): Promise {
+ const { confirmPort } = await inquirer.prompt<{ confirmPort: boolean }>([
{
- type: 'input',
- name: 'customPort',
- message:
- 'Enter custom port for development server (leave blank for default 4321):',
- default: 4321,
+ type: 'confirm',
+ name: 'confirmPort',
+ message: `Port ${port} is a reserved port. Are you sure you want to use it?`,
+ default: false,
},
]);
- return customPort;
+
+ return confirmPort;
+}
+
+export async function askForCustomPort(): Promise {
+ let remainingAttempts = MAX_RETRY_ATTEMPTS;
+
+ while (remainingAttempts--) {
+ const { customPort } = await inquirer.prompt<{ customPort: string }>([
+ {
+ type: 'input',
+ name: 'customPort',
+ message: `Enter custom port for development server (leave blank for default ${DEFAULT_PORT}):`,
+ default: DEFAULT_PORT.toString(),
+ validate: validatePort,
+ },
+ ]);
+
+ if (customPort && validatePort(customPort) === true) {
+ if (Number(customPort) >= 1024) {
+ return Number(customPort);
+ }
+
+ if (
+ Number(customPort) < 1024 &&
+ (await reservedPortWarning(Number(customPort)))
+ ) {
+ return Number(customPort);
+ }
+ }
+ }
+ console.log(
+ `\nMaximum attempts reached. Using default port ${DEFAULT_PORT}.`,
+ );
+ return DEFAULT_PORT;
}
diff --git a/src/setup/askForTalawaApiUrl/askForTalawaApiUrl.test.ts b/src/setup/askForTalawaApiUrl/askForTalawaApiUrl.test.ts
index b1490222b4..3a11a0d799 100644
--- a/src/setup/askForTalawaApiUrl/askForTalawaApiUrl.test.ts
+++ b/src/setup/askForTalawaApiUrl/askForTalawaApiUrl.test.ts
@@ -30,17 +30,9 @@ describe('askForTalawaApiUrl', () => {
});
test('should return the default endpoint when the user does not enter anything', async () => {
- const mockPrompt = jest
- .spyOn(inquirer, 'prompt')
- .mockImplementation(async (questions: any) => {
- const answers: Record = {};
- questions.forEach(
- (question: { name: string | number; default: any }) => {
- answers[question.name] = question.default;
- },
- );
- return answers;
- });
+ const mockPrompt = jest.spyOn(inquirer, 'prompt').mockResolvedValueOnce({
+ endpoint: 'http://localhost:4000/graphql/',
+ });
const result = await askForTalawaApiUrl();
diff --git a/src/setup/askForTalawaApiUrl/askForTalawaApiUrl.ts b/src/setup/askForTalawaApiUrl/askForTalawaApiUrl.ts
index 97daa1ac89..713ed7dc68 100644
--- a/src/setup/askForTalawaApiUrl/askForTalawaApiUrl.ts
+++ b/src/setup/askForTalawaApiUrl/askForTalawaApiUrl.ts
@@ -1,7 +1,7 @@
import inquirer from 'inquirer';
export async function askForTalawaApiUrl(): Promise {
- const { endpoint } = await inquirer.prompt([
+ const { endpoint } = await inquirer.prompt<{ endpoint: string }>([
{
type: 'input',
name: 'endpoint',
From 705dcbc98755fe231f9b9cf636701c2c1b132625 Mon Sep 17 00:00:00 2001
From: Akshat Gupta <88035400+Akshat76845@users.noreply.github.com>
Date: Mon, 23 Dec 2024 04:16:07 +0530
Subject: [PATCH 049/133] Refactor : src/screens/OrgContribution component from
Jest to Vitest (#2729)
* Converted from Jest to Vitest
* Converted the code from Jest to Vitest
* Converted from Jest to Vitest
---------
Co-authored-by: Akshat
---
...tion.test.tsx => OrgContribution.spec.tsx} | 20 +++++++++++--------
1 file changed, 12 insertions(+), 8 deletions(-)
rename src/screens/OrgContribution/{OrgContribution.test.tsx => OrgContribution.spec.tsx} (80%)
diff --git a/src/screens/OrgContribution/OrgContribution.test.tsx b/src/screens/OrgContribution/OrgContribution.spec.tsx
similarity index 80%
rename from src/screens/OrgContribution/OrgContribution.test.tsx
rename to src/screens/OrgContribution/OrgContribution.spec.tsx
index f9f63c6807..f12057a626 100644
--- a/src/screens/OrgContribution/OrgContribution.test.tsx
+++ b/src/screens/OrgContribution/OrgContribution.spec.tsx
@@ -1,9 +1,9 @@
-import React, { act } from 'react';
+import React from 'react';
import { MockedProvider } from '@apollo/react-testing';
import { render } from '@testing-library/react';
import { Provider } from 'react-redux';
import { BrowserRouter } from 'react-router-dom';
-import 'jest-location-mock';
+import { vi, describe, test, expect } from 'vitest';
import { I18nextProvider } from 'react-i18next';
import OrgContribution from './OrgContribution';
@@ -12,15 +12,20 @@ import i18nForTest from 'utils/i18nForTest';
import { StaticMockLink } from 'utils/StaticMockLink';
const link = new StaticMockLink([], true);
async function wait(ms = 100): Promise {
- await act(() => {
- return new Promise((resolve) => {
- setTimeout(resolve, ms);
- });
+ await new Promise((resolve) => {
+ setTimeout(resolve, ms);
});
}
describe('Organisation Contribution Page', () => {
test('should render props and text elements test for the screen', async () => {
+ Object.defineProperty(window, 'location', {
+ value: {
+ assign: vi.fn(),
+ },
+ writable: true,
+ });
+
window.location.assign('/orglist');
const { container } = render(
@@ -37,11 +42,10 @@ describe('Organisation Contribution Page', () => {
expect(container.textContent).not.toBe('Loading data...');
await wait();
-
expect(container.textContent).toMatch('Filter by Name');
expect(container.textContent).toMatch('Filter by Trans. ID');
expect(container.textContent).toMatch('Recent Stats');
expect(container.textContent).toMatch('Contribution');
- expect(window.location).toBeAt('/orglist');
+ expect(window.location.assign).toHaveBeenCalledWith('/orglist');
});
});
From 92ce58dfd00128a722943f4e38f739eaaa1eb1f1 Mon Sep 17 00:00:00 2001
From: Gurram Karthik <167804249+gurramkarthiknetha@users.noreply.github.com>
Date: Mon, 23 Dec 2024 04:21:39 +0530
Subject: [PATCH 050/133] fixed:#1887 Event and Holiday Calendar View (#2676)
* fixed-1887
* changed acc to bot
* final change
* gitpush final change
* 1 conflict resloved
* 1 conflict reslove
* 2nd conflict resloved
* changed css acc to gautam-divyanshu
* decreased time
* changed in event calendar
---------
Co-authored-by: Peter Harrison <16875803+palisadoes@users.noreply.github.com>
---
.../EventCalendar/EventCalendar.module.css | 177 ++++++++++++-
.../EventCalendar/EventCalendar.tsx | 240 +++++++-----------
src/screens/UserPortal/Posts/Posts.test.tsx | 5 +-
src/setupTests.ts | 2 +-
4 files changed, 265 insertions(+), 159 deletions(-)
diff --git a/src/components/EventCalendar/EventCalendar.module.css b/src/components/EventCalendar/EventCalendar.module.css
index 921af48bae..607d750f85 100644
--- a/src/components/EventCalendar/EventCalendar.module.css
+++ b/src/components/EventCalendar/EventCalendar.module.css
@@ -271,14 +271,6 @@
.expand_event_list {
display: block;
}
-
-.list_container {
- padding: 5px;
- width: fit-content;
- display: flex;
- flex-direction: row;
-}
-
.event_list_hour {
display: flex;
flex-direction: row;
@@ -316,7 +308,8 @@
flex-grow: 1;
}
-@media only screen and (max-width: 700px) {
+@media only screen and (max-width: var(--mobile-breakpoint)) {
+ /** @breakpoint --mobile-breakpoint: 768px */
.event_list {
display: none;
}
@@ -331,7 +324,7 @@
}
}
-@media only screen and (max-width: 500px) {
+@media only screen and (max-width: var(--small-mobile-breakpoint)) {
.btn__more {
font-size: 12px;
}
@@ -344,7 +337,22 @@
gap: 10px;
margin-top: 35px;
}
+.base_card {
+ flex: 1;
+ padding: 20px;
+ border-radius: 10px;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.15);
+}
+
+.holidays_card {
+ composes: base_card;
+ background-color: var(--holiday-card-bg);
+}
+.events_card {
+ composes: base_card;
+ background-color: #ffffff;
+}
.card__holidays {
background-color: rgba(246, 242, 229, 1);
display: flex;
@@ -415,9 +423,150 @@
border-radius: 10px;
}
-.userEvents__color {
- height: 15px;
- width: 40px;
- background: rgba(146, 200, 141, 0.5);
+.baseIndicator {
+ border-radius: 5px;
+ width: 20px;
+ height: 12px;
+ display: inline-block;
+}
+
+.holidayText {
+ font-size: 14px;
+ color: #555555;
+}
+.eventsLegend {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+}
+
+.list_container {
+ padding: 5px;
+ width: fit-content;
+ display: flex;
+ align-items: center;
+ gap: var(--indicator-spacing);
+}
+
+.holidayIndicator {
+ composes: baseIndicator;
+ background-color: rgba(0, 0, 0, 0.15);
+}
+
+:root {
+ /* Color scheme for holiday-related elements */
+ --color-user-event: rgba(139, 195, 74, 1);
+ /* Holiday colors */
+ --color-holiday-indicator: rgba(0, 0, 0, 0.15);
+ --color-holiday-date: rgba(255, 152, 0, 1);
+ /* Breakpoints for responsive design */
+ --mobile-breakpoint: 700px;
+ --small-mobile-breakpoint: 480px;
+ --text-color-primary: rgba(51, 51, 51, 1);
+ --text-color-secondary: rgba(85, 85, 85, 1);
+ /* Card styles */
+ --card-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+ --holiday-card-bg: #f6f2e5;
+ --holiday-date-color: #d35400;
+ --indicator-spacing: 8px;
+ /* Interactive states */
+ --hover-bg-color: rgba(0, 0, 0, 0.05);
+}
+.organizationIndicator {
+ composes: baseIndicator;
+ background-color: rgba(82, 172, 255, 0.5);
+}
+
+.legendText {
+ font-size: 14px;
+ color: #555555;
+}
+@media only screen and (max-width: var(--mobile-breakpoint)) {
+ .list_container,
+ .eventsLegend {
+ gap: 4px;
+ }
+
+ .holidayIndicator,
+ .organizationIndicator {
+ width: 16px;
+ height: 10px;
+ }
+
+ .holidayText,
+ .legendText {
+ font-size: 12px;
+ }
+}
+.card_title {
+ font-size: 16px;
+ font-weight: 600;
+ color: var(--text-color-primary);
+ margin-bottom: 15px;
+}
+
+.card_list {
+ list-style: none;
+ padding: 0;
+ margin: 0;
+}
+
+.card_list_item {
+ display: flex;
+ align-items: center;
+ margin-bottom: 10px;
+ font-size: 14px;
+ color: var(--text-color-secondary);
+}
+
+.holiday_date {
+ font-weight: 500;
+ margin-right: 10px;
+ color: var(--holiday-date-color);
+}
+
+.calendar_infocards {
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ align-items: flex-start;
+ gap: 20px;
+ padding: 20px;
+ background-color: var(--grey-bg-color);
+}
+.holidays_card,
+.events_card {
+ flex: 1;
+ padding: 20px;
border-radius: 10px;
+ box-shadow: var(--card-shadow);
+}
+
+.holidays_card {
+ background-color: var(--holiday-card-bg);
+}
+
+.events_card {
+ background-color: white;
+}
+
+.legend {
+ display: flex;
+ flex-direction: column;
+ gap: 12px;
+}
+
+.userEvents__color {
+ composes: baseIndicator;
+ display: inline-block;
+ background-color: rgba(139, 195, 74, 1);
+}
+
+.card_list_item:hover {
+ background-color: var(--hover-bg-color);
+ transition: background-color 0.2s ease;
+}
+.card_list_item:focus-visible {
+ background-color: var(--hover-bg-color);
+ transition: background-color 0.2s ease;
}
diff --git a/src/components/EventCalendar/EventCalendar.tsx b/src/components/EventCalendar/EventCalendar.tsx
index 575bda391e..ebcf8be942 100644
--- a/src/components/EventCalendar/EventCalendar.tsx
+++ b/src/components/EventCalendar/EventCalendar.tsx
@@ -1,16 +1,14 @@
import EventListCard from 'components/EventListCard/EventListCard';
import dayjs from 'dayjs';
+import React, { useState, useEffect, useMemo } from 'react';
import Button from 'react-bootstrap/Button';
-import React, { useState, useEffect } from 'react';
import styles from './EventCalendar.module.css';
import { ChevronLeft, ChevronRight } from '@mui/icons-material';
-import CurrentHourIndicator from 'components/CurrentHourIndicator/CurrentHourIndicator';
import { ViewType } from 'screens/OrganizationEvents/OrganizationEvents';
import HolidayCard from '../HolidayCards/HolidayCard';
-import { holidays, hours, months, weekdays } from './constants';
+import { holidays, months, weekdays } from './constants';
import type { InterfaceRecurrenceRule } from 'utils/recurrenceUtils';
import YearlyEventCalender from './YearlyEventCalender';
-
interface InterfaceEventListCardProps {
userRole?: string;
key?: string;
@@ -75,7 +73,6 @@ const Calendar: React.FC = ({
);
const [expanded, setExpanded] = useState(-1);
const [windowWidth, setWindowWidth] = useState(window.screen.width);
-
useEffect(() => {
function handleResize(): void {
setWindowWidth(window.screen.width);
@@ -138,9 +135,21 @@ const Calendar: React.FC = ({
}
};
- /**
- * Moves the calendar view to the next month.
- */
+ const filteredHolidays = useMemo(() => {
+ return Array.isArray(holidays)
+ ? holidays.filter((holiday) => {
+ if (!holiday.date) {
+ if (process.env.NODE_ENV !== 'test') {
+ console.warn(`Holiday "${holiday.name}" has no date specified.`);
+ }
+ return false;
+ }
+ const holidayMonth = dayjs(holiday.date, 'MM-DD', true).month();
+ return holidayMonth === currentMonth;
+ })
+ : [];
+ }, [holidays, currentMonth]);
+
const handleNextMonth = (): void => {
if (currentMonth === 11) {
setCurrentMonth(0);
@@ -149,10 +158,6 @@ const Calendar: React.FC = ({
setCurrentMonth(currentMonth + 1);
}
};
-
- /**
- * Moves the calendar view to the previous date.
- */
const handlePrevDate = (): void => {
if (currentDate > 1) {
setCurrentDate(currentDate - 1);
@@ -193,9 +198,6 @@ const Calendar: React.FC = ({
}
};
- /**
- * Moves the calendar view to today's date.
- */
const handleTodayButton = (): void => {
setCurrentYear(today.getFullYear());
setCurrentMonth(today.getMonth());
@@ -264,6 +266,17 @@ const Calendar: React.FC = ({
);
}) || [];
+ const shouldShowViewMore = useMemo(() => {
+ return (
+ allDayEventsList.length > 2 ||
+ (windowWidth <= 700 && allDayEventsList.length > 0)
+ );
+ }, [allDayEventsList.length, windowWidth]);
+
+ const handleExpandClick: () => void = () => {
+ toggleExpand(-100);
+ };
+
return (
<>
@@ -284,7 +297,6 @@ const Calendar: React.FC
= ({
? styles.expand_list_container
: styles.list_container
}
- style={{ width: 'fit-content' }}
>
= ({
: styles.event_list_hour
}
>
- {expanded === -100
- ? allDayEventsList
- : allDayEventsList?.slice(0, 1)}
+ {Array.isArray(allDayEventsList) &&
+ allDayEventsList.length > 0 ? (
+ expanded === -100 ? (
+ allDayEventsList
+ ) : (
+ allDayEventsList.slice(0, 1)
+ )
+ ) : (
+
+ No events available
+
+ )}
- {(allDayEventsList?.length > 2 ||
- (windowWidth <= 700 && allDayEventsList?.length > 0)) && (
+ {Array.isArray(allDayEventsList) && (
)}
- {hours.map((hour, index) => {
- const timeEventsList: JSX.Element[] =
- events
- ?.filter((datas) => {
- const currDate = new Date(
- currentYear,
- currentMonth,
- currentDate,
- );
-
- if (
- parseInt(datas.startTime?.slice(0, 2) as string).toString() ==
- (index % 24).toString() &&
- datas.startDate == dayjs(currDate).format('YYYY-MM-DD')
- ) {
- return datas;
- }
- })
- .map((datas: InterfaceEventListCardProps) => {
- const attendees: { _id: string }[] = [];
- datas.attendees?.forEach((attendee: { _id: string }) => {
- const r = {
- _id: attendee._id,
- };
-
- attendees.push(r);
- });
-
- return (
-
- );
- }) || [];
- return (
-
-
-
{`${hour}`}
+
+
+
Holidays
+
+ {filteredHolidays.map((holiday, index) => (
+ -
+
+ {months[parseInt(holiday.date.slice(0, 2), 10) - 1]}{' '}
+ {holiday.date.slice(3)}
+
+ {holiday.name}
+
+ ))}
+
+
+
+
+
Events
+
+
+
+ Holidays
-
-
0
- ? styles.event_list_parent_current
- : styles.event_list_parent
- }
- >
- {index % 24 == new Date().getHours() &&
- new Date().getDate() == currentDate && (
-
- )}
-
-
- {}
- {expanded === index
- ? timeEventsList
- : timeEventsList?.slice(0, 1)}
-
- {(timeEventsList?.length > 1 ||
- (windowWidth <= 700 && timeEventsList?.length > 0)) && (
-
- )}
-
+
+
+
+ Events Created by Organization
+
+
+
+
+
+ Events Created by User
+
- );
- })}
+
+
>
);
};
@@ -448,10 +407,10 @@ const Calendar: React.FC
= ({
return days.map((date, index) => {
const className = [
date.getDay() === 0 || date.getDay() === 6 ? styles.day_weekends : '',
- date.toLocaleDateString() === today.toLocaleDateString() //Styling for today day cell
+ date.toLocaleDateString() === today.toLocaleDateString()
? styles.day__today
: '',
- date.getMonth() !== currentMonth ? styles.day__outside : '', //Styling for days outside the current month
+ date.getMonth() !== currentMonth ? styles.day__outside : '',
selectedDate?.getTime() === date.getTime() ? styles.day__selected : '',
styles.day,
].join(' ');
@@ -504,13 +463,12 @@ const Calendar: React.FC = ({
);
}) || [];
- const holidayList: JSX.Element[] = holidays
- .filter((holiday) => {
- if (holiday.date == dayjs(date).format('MM-DD')) return holiday;
- })
+ const holidayList: JSX.Element[] = filteredHolidays
+ .filter((holiday) => holiday.date === dayjs(date).format('MM-DD'))
.map((holiday) => {
return ;
});
+
return (
= ({
)}
{viewType == ViewType.MONTH ? (
-
+ <>
{weekdays.map((weekday, index) => (
@@ -611,18 +569,14 @@ const Calendar: React.FC = ({
))}
{renderDays()}
-
+ >
+ ) : viewType == ViewType.YEAR ? (
+
) : (
- //
-
- {viewType == ViewType.YEAR ? (
-
- ) : (
-
{renderHours()}
- )}
-
+
{renderHours()}
)}
+
{viewType == ViewType.YEAR ? (
diff --git a/src/screens/UserPortal/Posts/Posts.test.tsx b/src/screens/UserPortal/Posts/Posts.test.tsx
index aa5f03fdcf..433e36f94a 100644
--- a/src/screens/UserPortal/Posts/Posts.test.tsx
+++ b/src/screens/UserPortal/Posts/Posts.test.tsx
@@ -1,7 +1,7 @@
import React, { act } from 'react';
import { MockedProvider } from '@apollo/react-testing';
import type { RenderResult } from '@testing-library/react';
-import { render, screen, waitFor, within } from '@testing-library/react';
+import { render, screen, within } from '@testing-library/react';
import { I18nextProvider } from 'react-i18next';
import userEvent from '@testing-library/user-event';
import {
@@ -395,5 +395,8 @@ describe('HomeScreen with invalid orgId', () => {
);
const homeEl = await screen.findByTestId('homeEl');
expect(homeEl).toBeInTheDocument();
+
+ const postCardContainers = screen.queryAllByTestId('postCardContainer');
+ expect(postCardContainers).toHaveLength(0);
});
});
diff --git a/src/setupTests.ts b/src/setupTests.ts
index f0b48b39d0..d204b3ddc9 100644
--- a/src/setupTests.ts
+++ b/src/setupTests.ts
@@ -32,4 +32,4 @@ jestPreviewConfigure({
autoPreview: true,
});
-jest.setTimeout(17000);
+jest.setTimeout(18000);
From fd0fe5caf89ab653976e2f9be5f3ea4d0d2b0987 Mon Sep 17 00:00:00 2001
From: prathmesh703 <146568950+prathmesh703@users.noreply.github.com>
Date: Mon, 23 Dec 2024 07:56:57 +0530
Subject: [PATCH 051/133] Refactor: src/screens/OrganizationFunds from Jest to
Vitest (#2685)
---
...{FundModal.test.tsx => FundModal.spec.tsx} | 47 ++++++++++++++++---
src/screens/OrganizationFunds/FundModal.tsx | 8 ++--
...ds.test.tsx => OrganizationFunds.spec.tsx} | 41 +++++++++++-----
3 files changed, 72 insertions(+), 24 deletions(-)
rename src/screens/OrganizationFunds/{FundModal.test.tsx => FundModal.spec.tsx} (85%)
rename src/screens/OrganizationFunds/{OrganizationFunds.test.tsx => OrganizationFunds.spec.tsx} (85%)
diff --git a/src/screens/OrganizationFunds/FundModal.test.tsx b/src/screens/OrganizationFunds/FundModal.spec.tsx
similarity index 85%
rename from src/screens/OrganizationFunds/FundModal.test.tsx
rename to src/screens/OrganizationFunds/FundModal.spec.tsx
index c74b0434c3..7296f31661 100644
--- a/src/screens/OrganizationFunds/FundModal.test.tsx
+++ b/src/screens/OrganizationFunds/FundModal.spec.tsx
@@ -21,11 +21,12 @@ import { toast } from 'react-toastify';
import { MOCKS, MOCKS_ERROR } from './OrganizationFundsMocks';
import type { InterfaceFundModal } from './FundModal';
import FundModal from './FundModal';
+import { vi } from 'vitest';
-jest.mock('react-toastify', () => ({
+vi.mock('react-toastify', () => ({
toast: {
- success: jest.fn(),
- error: jest.fn(),
+ success: vi.fn(),
+ error: vi.fn(),
},
}));
@@ -38,7 +39,7 @@ const translations = JSON.parse(
const fundProps: InterfaceFundModal[] = [
{
isOpen: true,
- hide: jest.fn(),
+ hide: vi.fn(),
fund: {
_id: 'fundId',
name: 'Fund 1',
@@ -54,13 +55,13 @@ const fundProps: InterfaceFundModal[] = [
lastName: 'Doe',
},
},
- refetchFunds: jest.fn(),
+ refetchFunds: vi.fn(),
orgId: 'orgId',
mode: 'create',
},
{
isOpen: true,
- hide: jest.fn(),
+ hide: vi.fn(),
fund: {
_id: 'fundId',
name: 'Fund 1',
@@ -76,7 +77,7 @@ const fundProps: InterfaceFundModal[] = [
lastName: 'Doe',
},
},
- refetchFunds: jest.fn(),
+ refetchFunds: vi.fn(),
orgId: 'orgId',
mode: 'edit',
},
@@ -104,6 +105,7 @@ const renderFundModal = (
describe('PledgeModal', () => {
afterEach(() => {
cleanup();
+ vi.clearAllMocks();
});
it('should populate form fields with correct values in edit mode', async () => {
@@ -184,6 +186,37 @@ describe('PledgeModal', () => {
});
});
+ it('should not update the fund when no fields are changed', async () => {
+ renderFundModal(link1, fundProps[1]);
+
+ // Simulate no change to the fields
+ const fundNameInput = screen.getByLabelText(translations.fundName);
+ fireEvent.change(fundNameInput, { target: { value: 'Fund 1' } });
+
+ const fundIdInput = screen.getByLabelText(translations.fundId);
+ fireEvent.change(fundIdInput, { target: { value: '1111' } });
+
+ const taxDeductibleSwitch = screen.getByTestId('setTaxDeductibleSwitch');
+ fireEvent.click(taxDeductibleSwitch);
+ fireEvent.click(taxDeductibleSwitch);
+
+ const defaultSwitch = screen.getByTestId('setDefaultSwitch');
+ fireEvent.click(defaultSwitch);
+ fireEvent.click(defaultSwitch);
+
+ const archivedSwitch = screen.getByTestId('archivedSwitch');
+ fireEvent.click(archivedSwitch);
+ fireEvent.click(archivedSwitch);
+
+ fireEvent.click(screen.getByTestId('createFundFormSubmitBtn'));
+
+ await waitFor(() => {
+ expect(toast.success).not.toHaveBeenCalled();
+ expect(fundProps[1].refetchFunds).not.toHaveBeenCalled();
+ expect(fundProps[1].hide).not.toHaveBeenCalled();
+ });
+ });
+
it('should update fund', async () => {
renderFundModal(link1, fundProps[1]);
diff --git a/src/screens/OrganizationFunds/FundModal.tsx b/src/screens/OrganizationFunds/FundModal.tsx
index de4329e55c..b33270b30f 100644
--- a/src/screens/OrganizationFunds/FundModal.tsx
+++ b/src/screens/OrganizationFunds/FundModal.tsx
@@ -139,7 +139,9 @@ const FundModal: React.FC
= ({
if (isDefault != fund?.isDefault) {
updatedFields.isDefault = isDefault;
}
-
+ if (Object.keys(updatedFields).length === 0) {
+ return;
+ }
await updateFund({
variables: {
id: fund?._id,
@@ -157,9 +159,7 @@ const FundModal: React.FC = ({
hide();
toast.success(t('fundUpdated') as string);
} catch (error: unknown) {
- if (error instanceof Error) {
- toast.error(error.message);
- }
+ toast.error((error as Error).message);
}
};
diff --git a/src/screens/OrganizationFunds/OrganizationFunds.test.tsx b/src/screens/OrganizationFunds/OrganizationFunds.spec.tsx
similarity index 85%
rename from src/screens/OrganizationFunds/OrganizationFunds.test.tsx
rename to src/screens/OrganizationFunds/OrganizationFunds.spec.tsx
index c6983e1d6d..b259b7da65 100644
--- a/src/screens/OrganizationFunds/OrganizationFunds.test.tsx
+++ b/src/screens/OrganizationFunds/OrganizationFunds.spec.tsx
@@ -11,7 +11,7 @@ import {
import userEvent from '@testing-library/user-event';
import { I18nextProvider } from 'react-i18next';
import { Provider } from 'react-redux';
-import { MemoryRouter, Route, Routes } from 'react-router-dom';
+import { MemoryRouter, Route, Routes, useParams } from 'react-router-dom';
import { store } from 'state/store';
import { StaticMockLink } from 'utils/StaticMockLink';
import i18nForTest from 'utils/i18nForTest';
@@ -20,11 +20,12 @@ import { MOCKS, MOCKS_ERROR, NO_FUNDS } from './OrganizationFundsMocks';
import type { ApolloLink } from '@apollo/client';
import { LocalizationProvider } from '@mui/x-date-pickers';
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
+import { vi } from 'vitest';
-jest.mock('react-toastify', () => ({
+vi.mock('react-toastify', () => ({
toast: {
- success: jest.fn(),
- error: jest.fn(),
+ success: vi.fn(),
+ error: vi.fn(),
},
}));
@@ -67,21 +68,22 @@ const renderOrganizationFunds = (link: ApolloLink): RenderResult => {
describe('OrganizationFunds Screen =>', () => {
beforeEach(() => {
- jest.mock('react-router-dom', () => ({
- ...jest.requireActual('react-router-dom'),
- useParams: () => ({ orgId: 'orgId' }),
- }));
- });
-
- afterEach(() => {
- jest.clearAllMocks();
+ vi.mock('react-router-dom', async () => {
+ const actual = await vi.importActual('react-router-dom');
+ return {
+ ...actual,
+ useParams: vi.fn(),
+ };
+ });
});
afterEach(() => {
+ vi.clearAllMocks();
cleanup();
});
it('should render the Campaign Pledge screen', async () => {
+ vi.mocked(useParams).mockReturnValue({ orgId: 'orgId' });
renderOrganizationFunds(link1);
await waitFor(() => {
expect(screen.getByTestId('searchByName')).toBeInTheDocument();
@@ -89,29 +91,34 @@ describe('OrganizationFunds Screen =>', () => {
});
it('should redirect to fallback URL if URL params are undefined', async () => {
+ vi.mocked(useParams).mockReturnValue({});
render(
- } />
}
/>
+
} />
,
);
+ await waitFor(() => {
+ expect(window.location.pathname).toBe('/');
+ });
await waitFor(() => {
expect(screen.getByTestId('paramsError')).toBeInTheDocument();
});
});
it('open and close Create Fund modal', async () => {
+ vi.mocked(useParams).mockReturnValue({ orgId: 'orgId' });
renderOrganizationFunds(link1);
const createFundBtn = await screen.findByTestId('createFundBtn');
@@ -128,6 +135,7 @@ describe('OrganizationFunds Screen =>', () => {
});
it('open and close update fund modal', async () => {
+ vi.mocked(useParams).mockReturnValue({ orgId: 'orgId' });
renderOrganizationFunds(link1);
await waitFor(() => {
@@ -150,6 +158,7 @@ describe('OrganizationFunds Screen =>', () => {
});
it('Search the Funds list by name', async () => {
+ vi.mocked(useParams).mockReturnValue({ orgId: 'orgId' });
renderOrganizationFunds(link1);
const searchField = await screen.findByTestId('searchByName');
fireEvent.change(searchField, {
@@ -163,6 +172,7 @@ describe('OrganizationFunds Screen =>', () => {
});
it('should render the Fund screen with error', async () => {
+ vi.mocked(useParams).mockReturnValue({ orgId: 'orgId' });
renderOrganizationFunds(link2);
await waitFor(() => {
expect(screen.getByTestId('errorMsg')).toBeInTheDocument();
@@ -170,6 +180,7 @@ describe('OrganizationFunds Screen =>', () => {
});
it('renders the empty fund component', async () => {
+ vi.mocked(useParams).mockReturnValue({ orgId: 'orgId' });
renderOrganizationFunds(link3);
await waitFor(() =>
expect(screen.getByText(translations.noFundsFound)).toBeInTheDocument(),
@@ -177,6 +188,7 @@ describe('OrganizationFunds Screen =>', () => {
});
it('Sort the Pledges list by Latest created Date', async () => {
+ vi.mocked(useParams).mockReturnValue({ orgId: 'orgId' });
renderOrganizationFunds(link1);
const sortBtn = await screen.findByTestId('filter');
@@ -198,6 +210,7 @@ describe('OrganizationFunds Screen =>', () => {
});
it('Sort the Pledges list by Earliest created Date', async () => {
+ vi.mocked(useParams).mockReturnValue({ orgId: 'orgId' });
renderOrganizationFunds(link1);
const sortBtn = await screen.findByTestId('filter');
@@ -219,6 +232,7 @@ describe('OrganizationFunds Screen =>', () => {
});
it('Click on Fund Name', async () => {
+ vi.mocked(useParams).mockReturnValue({ orgId: 'orgId' });
renderOrganizationFunds(link1);
const fundName = await screen.findAllByTestId('fundName');
@@ -231,6 +245,7 @@ describe('OrganizationFunds Screen =>', () => {
});
it('Click on View Campaign', async () => {
+ vi.mocked(useParams).mockReturnValue({ orgId: 'orgId' });
renderOrganizationFunds(link1);
const viewBtn = await screen.findAllByTestId('viewBtn');
From ea264ce6a2c8dc3e2f997c9f3a041018fab57955 Mon Sep 17 00:00:00 2001
From: Shiva <148421597+shivasankaran18@users.noreply.github.com>
Date: Mon, 23 Dec 2024 22:38:31 +0530
Subject: [PATCH 052/133] Refactor : Vitest to SidePanel Component (#2735)
* refactor:vitest to Sidepanel
* ts-doc comments
---
.../SidePanel/{SidePanel.test.tsx => SidePanel.spec.tsx} | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
rename src/components/AddOn/support/components/SidePanel/{SidePanel.test.tsx => SidePanel.spec.tsx} (82%)
diff --git a/src/components/AddOn/support/components/SidePanel/SidePanel.test.tsx b/src/components/AddOn/support/components/SidePanel/SidePanel.spec.tsx
similarity index 82%
rename from src/components/AddOn/support/components/SidePanel/SidePanel.test.tsx
rename to src/components/AddOn/support/components/SidePanel/SidePanel.spec.tsx
index d929278d0e..4a5f4e5692 100644
--- a/src/components/AddOn/support/components/SidePanel/SidePanel.test.tsx
+++ b/src/components/AddOn/support/components/SidePanel/SidePanel.spec.tsx
@@ -11,11 +11,16 @@ const client: ApolloClient
= new ApolloClient({
});
describe('Testing Contribution Stats', () => {
+ /**
+ * Props to be passed to the `SidePanel` component during the test.
+ */
const props = {
collapse: true,
children: '234',
};
-
+ /**
+ * Verifies that the `SidePanel` component renders correctly with given props.
+ */
test('should render props and text elements test for the SidePanel component', () => {
render(
From 23a5f6300ab5e6403ab8347b52347d8c917b2ea9 Mon Sep 17 00:00:00 2001
From: Shiva <148421597+shivasankaran18@users.noreply.github.com>
Date: Mon, 23 Dec 2024 22:42:45 +0530
Subject: [PATCH 053/133] refactor:vitest to checkInModal (#2734)
---
.../{CheckInModal.test.tsx => CheckInModal.spec.tsx} | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
rename src/components/CheckIn/{CheckInModal.test.tsx => CheckInModal.spec.tsx} (89%)
diff --git a/src/components/CheckIn/CheckInModal.test.tsx b/src/components/CheckIn/CheckInModal.spec.tsx
similarity index 89%
rename from src/components/CheckIn/CheckInModal.test.tsx
rename to src/components/CheckIn/CheckInModal.spec.tsx
index 1660c7c4bb..4f5a05328e 100644
--- a/src/components/CheckIn/CheckInModal.test.tsx
+++ b/src/components/CheckIn/CheckInModal.spec.tsx
@@ -12,6 +12,7 @@ import { LocalizationProvider } from '@mui/x-date-pickers';
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
import { checkInQueryMock } from './mocks';
import { StaticMockLink } from 'utils/StaticMockLink';
+import { vi } from 'vitest';
const link = new StaticMockLink(checkInQueryMock, true);
@@ -19,9 +20,14 @@ describe('Testing Check In Attendees Modal', () => {
const props = {
show: true,
eventId: 'event123',
- handleClose: jest.fn(),
+ handleClose: vi.fn(),
};
+ /**
+ * Test case for rendering the CheckInModal component and verifying functionality.
+ * It checks that the modal renders fetched users and verifies the filtering mechanism.
+ */
+
test('The modal should be rendered, and all the fetched users should be shown properly and user filtering should work', async () => {
const { queryByText, queryByLabelText } = render(
From 86d59c211a7d914120f54051f2e9e9708b1a46dc Mon Sep 17 00:00:00 2001
From: MANDEEP N H <146331633+mandeepnh5@users.noreply.github.com>
Date: Mon, 23 Dec 2024 22:54:52 +0530
Subject: [PATCH 054/133] Refactoring CSS files: merged FundCompaignPledge
styles into global app.module.css (#2706)
* Update fundcomapignpledge
* deleted fundcompaignpledge local css file
* Fix linting issues
* fixed type check
* Update src/style/app.module.css
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
* fixed some coderabbit issue
* Fixed testing issue
* Update src/style/app.module.css
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
* Fix coderabbit suggestion
---------
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
---
.../FundCampaignPledge.module.css | 273 ------------------
.../FundCampaignPledge/FundCampaignPledge.tsx | 28 +-
.../FundCampaignPledge/PledgeDeleteModal.tsx | 2 +-
.../FundCampaignPledge/PledgeModal.tsx | 12 +-
src/style/app.module.css | 223 ++++++++++++++
5 files changed, 244 insertions(+), 294 deletions(-)
delete mode 100644 src/screens/FundCampaignPledge/FundCampaignPledge.module.css
diff --git a/src/screens/FundCampaignPledge/FundCampaignPledge.module.css b/src/screens/FundCampaignPledge/FundCampaignPledge.module.css
deleted file mode 100644
index cdf4476267..0000000000
--- a/src/screens/FundCampaignPledge/FundCampaignPledge.module.css
+++ /dev/null
@@ -1,273 +0,0 @@
-.pledgeContainer {
- margin: 0.6rem 0;
-}
-
-.container {
- min-height: 100vh;
-}
-
-.pledgeModal {
- max-width: 80vw;
- margin-top: 2vh;
- margin-left: 13vw;
-}
-
-.titlemodal {
- color: #707070;
- font-weight: 600;
- font-size: 32px;
- width: 65%;
- margin-bottom: 0px;
-}
-
-.modalCloseBtn {
- width: 40px;
- height: 40px;
- padding: 1rem;
- display: flex;
- justify-content: center;
- align-items: center;
-}
-
-.greenregbtn {
- margin: 1rem 0 0;
- margin-top: 15px;
- border: 1px solid #e8e5e5;
- box-shadow: 0 2px 2px #e8e5e5;
- padding: 10px 10px;
- border-radius: 5px;
- background-color: #31bb6b;
- width: 100%;
- font-size: 16px;
- color: white;
- outline: none;
- font-weight: 600;
- cursor: pointer;
- transition:
- transform 0.2s,
- box-shadow 0.2s;
- width: 100%;
-}
-.message {
- margin-top: 25%;
- display: flex;
- justify-content: center;
- align-items: center;
- flex-direction: column;
-}
-
-.errorIcon {
- transform: scale(1.5);
- color: var(--bs-danger);
- margin-bottom: 1rem;
-}
-
-.btnsContainer {
- display: flex;
- gap: 0.8rem;
- margin: 2.2rem 0 0.8rem 0;
-}
-
-.btnsContainer .input {
- flex: 1;
- min-width: 18rem;
- position: relative;
-}
-
-.btnsContainer input {
- outline: 1px solid var(--bs-gray-400);
-}
-
-.btnsContainer .input button {
- width: 52px;
-}
-
-.inputField {
- background-color: white;
- box-shadow: 0 1px 1px #31bb6b;
-}
-
-.dropdown {
- background-color: white;
- border: 1px solid #31bb6b;
- position: relative;
- display: inline-block;
- color: #31bb6b;
-}
-
-.tableHeader {
- background-color: var(--bs-primary);
- color: var(--bs-white);
- font-size: 1rem;
-}
-
-.rowBackground {
- background-color: var(--bs-white);
- max-height: 120px;
-}
-
-.TableImage {
- object-fit: cover;
- width: 25px !important;
- height: 25px !important;
- border-radius: 100% !important;
-}
-
-.avatarContainer {
- width: 28px;
- height: 26px;
-}
-
-.imageContainer {
- display: flex;
- align-items: center;
- justify-content: center;
-}
-
-.pledgerContainer {
- display: flex;
- align-items: center;
- justify-content: center;
- margin: 0.1rem 0.25rem;
- gap: 0.25rem;
- padding: 0.25rem 0.45rem;
- border-radius: 0.35rem;
- background-color: #31bb6b33;
- height: 2.2rem;
- margin-top: 0.75rem;
-}
-
-.noOutline input {
- outline: none;
-}
-
-.overviewContainer {
- display: flex;
- gap: 7rem;
- width: 100%;
- justify-content: space-between;
- margin: 1.5rem 0 0 0;
- padding: 1.25rem 2rem;
- background-color: rgba(255, 255, 255, 0.591);
-
- box-shadow: rgba(0, 0, 0, 0.16) 0px 1px 4px;
- border-radius: 0.5rem;
-}
-
-.titleContainer {
- display: flex;
- flex-direction: column;
- gap: 0.6rem;
-}
-
-.titleContainer h3 {
- font-size: 1.75rem;
- font-weight: 750;
- color: #5e5e5e;
- margin-top: 0.2rem;
-}
-
-.titleContainer span {
- font-size: 0.9rem;
- margin-left: 0.5rem;
- font-weight: lighter;
- color: #707070;
-}
-
-.raisedAmount {
- display: flex;
- justify-content: center;
- align-items: center;
- font-size: 1.25rem;
- font-weight: 750;
- color: #5e5e5e;
-}
-
-.progressContainer {
- display: flex;
- flex-direction: column;
- gap: 0.5rem;
- flex-grow: 1;
-}
-
-.progress {
- margin-top: 0.2rem;
- display: flex;
- flex-direction: column;
- gap: 0.3rem;
-}
-
-.endpoints {
- display: flex;
- position: relative;
- font-size: 0.85rem;
-}
-
-.start {
- position: absolute;
- top: 0px;
-}
-
-.end {
- position: absolute;
- top: 0px;
- right: 0px;
-}
-
-.moreContainer {
- display: flex;
- align-items: center;
-}
-
-.moreContainer:hover {
- text-decoration: underline;
- cursor: pointer;
-}
-
-.popup {
- z-index: 50;
- border-radius: 0.5rem;
- font-family: sans-serif;
- font-weight: 500;
- font-size: 0.875rem;
- margin-top: 0.5rem;
- padding: 0.75rem;
- border: 1px solid #e2e8f0;
- background-color: white;
- color: #1e293b;
- box-shadow: 0 0.5rem 1rem rgb(0 0 0 / 0.15);
- display: flex;
- flex-direction: column;
- gap: 0.5rem;
-}
-
-.popupExtra {
- max-height: 15rem;
- overflow-y: auto;
-}
-
-.toggleGroup {
- width: 50%;
- min-width: 27.75rem;
- margin: 0.5rem 0rem;
-}
-
-.toggleBtn {
- padding: 0rem;
- height: 30px;
- display: flex;
- justify-content: center;
- align-items: center;
-}
-
-.toggleBtn:hover {
- color: #31bb6b !important;
-}
-
-input[type='radio']:checked + label {
- background-color: #31bb6a50 !important;
-}
-
-input[type='radio']:checked + label:hover {
- color: black !important;
-}
diff --git a/src/screens/FundCampaignPledge/FundCampaignPledge.tsx b/src/screens/FundCampaignPledge/FundCampaignPledge.tsx
index d14ee9de06..8942265eea 100644
--- a/src/screens/FundCampaignPledge/FundCampaignPledge.tsx
+++ b/src/screens/FundCampaignPledge/FundCampaignPledge.tsx
@@ -9,7 +9,7 @@ import { Button, Dropdown, Form } from 'react-bootstrap';
import { useTranslation } from 'react-i18next';
import { Navigate, useParams } from 'react-router-dom';
import { currencySymbols } from 'utils/currency';
-import styles from './FundCampaignPledge.module.css';
+import styles from '../../style/app.module.css';
import PledgeDeleteModal from './PledgeDeleteModal';
import PledgeModal from './PledgeModal';
import { Breadcrumbs, Link, Stack, Typography } from '@mui/material';
@@ -233,14 +233,14 @@ const fundCampaignPledge = (): JSX.Element => {
src={user.image}
alt="pledge"
data-testid={`image${index + 1}`}
- className={styles.TableImage}
+ className={styles.TableImagePledge}
/>
) : (
-
-
+
+
setSearchTerm(e.target.value)}
data-testid="searchPledger"
@@ -557,7 +557,7 @@ const fundCampaignPledge = (): JSX.Element => {
),
}}
sx={dataGridStyle}
- getRowClassName={() => `${styles.rowBackground}`}
+ getRowClassName={() => `${styles.rowBackgroundPledge}`}
autoHeight
rowHeight={65}
rows={pledges.map((pledge) => ({
@@ -607,14 +607,14 @@ const fundCampaignPledge = (): JSX.Element => {
src={user.image}
alt="pledger"
data-testid={`extraImage${index + 1}`}
- className={styles.TableImage}
+ className={styles.TableImagePledge}
/>
) : (
= ({
= ({
format="DD/MM/YYYY"
label={tCommon('startDate')}
value={dayjs(pledgeStartDate)}
- className={styles.noOutline}
+ className={styles.noOutlinePledge}
onChange={(date: Dayjs | null): void => {
if (date) {
setFormState({
@@ -280,7 +280,7 @@ const PledgeModal: React.FC = ({
{
if (date) {
@@ -327,7 +327,7 @@ const PledgeModal: React.FC = ({
{
if (parseInt(e.target.value) > 0) {
@@ -343,7 +343,7 @@ const PledgeModal: React.FC = ({
{/* Button to submit the pledge form */}
@@ -469,7 +471,7 @@ function ManageTag(): JSX.Element {
hasMore={
userTagAssignedMembersData?.getAssignedUsers
.usersAssignedTo.pageInfo.hasNextPage ??
- /* istanbul ignore next */ false
+ /* istanbul ignore next -- @preserve */ false
}
loader={}
scrollableTarget="manageTagScrollableDiv"
@@ -480,15 +482,16 @@ function ManageTag(): JSX.Element {
hideFooter={true}
getRowId={(row) => row.id}
slots={{
- noRowsOverlay: /* istanbul ignore next */ () => (
-
- {t('noAssignedMembersFound')}
-
- ),
+ noRowsOverlay:
+ /* istanbul ignore next -- @preserve */ () => (
+
+ {t('noAssignedMembersFound')}
+
+ ),
}}
sx={dataGridStyle}
getRowClassName={() => `${styles.rowBackground}`}
From e1b49d244a0c3fa76d41ad2387cac9c3a92db11d Mon Sep 17 00:00:00 2001
From: MANDEEP N H <146331633+mandeepnh5@users.noreply.github.com>
Date: Tue, 24 Dec 2024 13:33:21 +0530
Subject: [PATCH 060/133] Refactoring CSS files: merged CommunityProfile styles
into global app.module.css (#2738)
* Refactor Community Profile css
* Fix linting issues
* Fix explicit lint issue
---
.../CommunityProfile.module.css | 41 ------------------
.../CommunityProfile/CommunityProfile.tsx | 5 ++-
src/style/app.module.css | 42 +++++++++++++++++++
3 files changed, 45 insertions(+), 43 deletions(-)
delete mode 100644 src/screens/CommunityProfile/CommunityProfile.module.css
diff --git a/src/screens/CommunityProfile/CommunityProfile.module.css b/src/screens/CommunityProfile/CommunityProfile.module.css
deleted file mode 100644
index 1e6eac2bae..0000000000
--- a/src/screens/CommunityProfile/CommunityProfile.module.css
+++ /dev/null
@@ -1,41 +0,0 @@
-.card {
- width: fit-content;
-}
-
-.cardHeader {
- padding: 1.25rem 1rem 1rem 1rem;
- border-bottom: 1px solid var(--bs-gray-200);
- display: flex;
- justify-content: space-between;
- align-items: center;
-}
-
-.cardHeader .cardTitle {
- font-size: 1.5rem;
-}
-
-.formLabel {
- font-weight: normal;
- padding-bottom: 0;
- font-size: 1rem;
- color: black;
-}
-.cardBody {
- min-height: 180px;
-}
-
-.cardBody .textBox {
- margin: 0 0 3rem 0;
- color: var(--bs-secondary);
-}
-
-.socialInput {
- height: 2.5rem;
-}
-
-@media (max-width: 520px) {
- .btn {
- flex-direction: column;
- justify-content: center;
- }
-}
diff --git a/src/screens/CommunityProfile/CommunityProfile.tsx b/src/screens/CommunityProfile/CommunityProfile.tsx
index d96c923eb3..05f328ced0 100644
--- a/src/screens/CommunityProfile/CommunityProfile.tsx
+++ b/src/screens/CommunityProfile/CommunityProfile.tsx
@@ -18,7 +18,7 @@ import {
SlackLogo,
} from 'assets/svgs/social-icons';
import convertToBase64 from 'utils/convertToBase64';
-import styles from './CommunityProfile.module.css';
+import styles from '../../style/app.module.css';
import { errorHandler } from 'utils/errorHandler';
import UpdateSession from '../../components/UpdateSession/UpdateSession';
@@ -90,7 +90,7 @@ const CommunityProfile = (): JSX.Element => {
React.useEffect(() => {
const preLoginData: PreLoginImageryDataType | undefined =
data?.getCommunityData;
- preLoginData &&
+ if (preLoginData) {
setProfileVariable({
name: preLoginData.name ?? '',
websiteLink: preLoginData.websiteLink ?? '',
@@ -104,6 +104,7 @@ const CommunityProfile = (): JSX.Element => {
reddit: preLoginData.socialMediaUrls.reddit ?? '',
slack: preLoginData.socialMediaUrls.slack ?? '',
});
+ }
}, [data]);
/**
diff --git a/src/style/app.module.css b/src/style/app.module.css
index 6d6413aa86..3d161b52b1 100644
--- a/src/style/app.module.css
+++ b/src/style/app.module.css
@@ -831,6 +831,48 @@ hr {
color: #31bb6b !important;
}
+.card {
+ width: fit-content;
+}
+
+.cardHeader {
+ padding: 1.25rem 1rem 1rem 1rem;
+ border-bottom: 1px solid var(--bs-gray-200);
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+}
+
+.cardHeader .cardTitle {
+ font-size: 1.5rem;
+}
+
+.formLabel {
+ font-weight: normal;
+ padding-bottom: 0;
+ font-size: 1rem;
+ color: black;
+}
+.cardBody {
+ min-height: 180px;
+}
+
+.cardBody .textBox {
+ margin: 0 0 3rem 0;
+ color: var(--bs-secondary);
+}
+
+.socialInput {
+ height: 2.5rem;
+}
+
+@media (max-width: 520px) {
+ .btn {
+ flex-direction: column;
+ justify-content: center;
+ }
+}
+
@media (max-width: 1024px) {
.pageNotFound h1.head {
font-size: 200px;
From 3b681362d935e222373555c35959801c19d18aba Mon Sep 17 00:00:00 2001
From: Gurram Karthik <167804249+gurramkarthiknetha@users.noreply.github.com>
Date: Tue, 24 Dec 2024 14:46:43 +0530
Subject: [PATCH 061/133] fixed : #2516 Refactor CSS files in
src/screens/OrganizationFunds (#2743)
* issue-2516-fixed
* test
* removed commented lines
* deleted file
---
.../OrganizationFunds.module.css | 142 ------------------
.../OrganizationFunds/OrganizationFunds.tsx | 20 +--
src/style/app.module.css | 131 ++++++----------
3 files changed, 56 insertions(+), 237 deletions(-)
delete mode 100644 src/screens/OrganizationFunds/OrganizationFunds.module.css
diff --git a/src/screens/OrganizationFunds/OrganizationFunds.module.css b/src/screens/OrganizationFunds/OrganizationFunds.module.css
deleted file mode 100644
index aa9d89dfb1..0000000000
--- a/src/screens/OrganizationFunds/OrganizationFunds.module.css
+++ /dev/null
@@ -1,142 +0,0 @@
-.list_box {
- height: auto;
- overflow-y: auto;
- width: 100%;
-}
-
-.inputField {
- margin-top: 10px;
- margin-bottom: 10px;
- background-color: white;
- box-shadow: 0 1px 1px #31bb6b;
-}
-
-.inputField > button {
- padding-top: 10px;
- padding-bottom: 10px;
-}
-
-.dropdown {
- background-color: white;
- border: 1px solid #31bb6b;
- position: relative;
- display: inline-block;
- color: #31bb6b;
-}
-
-.fundName {
- font-weight: 600;
- cursor: pointer;
-}
-
-.modalHeader {
- border: none;
- padding-bottom: 0;
-}
-
-.label {
- color: var(--bs-emphasis-color);
-}
-
-.fundModal {
- max-width: 80vw;
- margin-top: 2vh;
- margin-left: 13vw;
-}
-
-.titlemodal {
- color: #707070;
- font-weight: 600;
- font-size: 32px;
- width: 65%;
- margin-bottom: 0px;
-}
-
-.noOutline input {
- outline: none;
-}
-
-.modalCloseBtn {
- width: 40px;
- height: 40px;
- padding: 1rem;
- display: flex;
- justify-content: center;
- align-items: center;
-}
-
-.greenregbtn {
- margin: 1rem 0 0;
- margin-top: 15px;
- border: 1px solid #e8e5e5;
- box-shadow: 0 2px 2px #e8e5e5;
- padding: 10px 10px;
- border-radius: 5px;
- background-color: #31bb6b;
- width: 100%;
- font-size: 16px;
- color: white;
- outline: none;
- font-weight: 600;
- cursor: pointer;
- transition:
- transform 0.2s,
- box-shadow 0.2s;
- width: 100%;
-}
-
-.manageBtn {
- margin: 1rem 0 0;
- margin-top: 15px;
- border: 1px solid #e8e5e5;
- box-shadow: 0 2px 2px #e8e5e5;
- padding: 10px 10px;
- border-radius: 5px;
- font-size: 16px;
- color: white;
- outline: none;
- font-weight: 600;
- cursor: pointer;
- width: 45%;
- transition:
- transform 0.2s,
- box-shadow 0.2s;
-}
-
-.btnsContainer {
- display: flex;
- margin: 2rem 0 2.5rem 0;
-}
-
-.btnsContainer .input {
- flex: 1;
- min-width: 18rem;
- position: relative;
-}
-
-.btnsContainer input {
- outline: 1px solid var(--bs-gray-400);
-}
-
-.btnsContainer .input button {
- width: 52px;
-}
-
-.mainpageright > hr {
- margin-top: 20px;
- width: 100%;
- margin-left: -15px;
- margin-right: -15px;
- margin-bottom: 20px;
-}
-
-.rowBackground {
- background-color: var(--bs-white);
- max-height: 120px;
-}
-
-.tableHeader {
- background-color: var(--bs-primary);
- color: var(--bs-white);
- font-size: 1rem;
-}
diff --git a/src/screens/OrganizationFunds/OrganizationFunds.tsx b/src/screens/OrganizationFunds/OrganizationFunds.tsx
index 2c352c1693..ec9409fbe0 100644
--- a/src/screens/OrganizationFunds/OrganizationFunds.tsx
+++ b/src/screens/OrganizationFunds/OrganizationFunds.tsx
@@ -160,7 +160,7 @@ const organizationFunds = (): JSX.Element => {
minWidth: 100,
align: 'center',
headerAlign: 'center',
- headerClassName: `${styles.tableHeader}`,
+ headerClassName: `${styles.tableHeaders}`,
sortable: false,
renderCell: (params: GridCellParams) => {
return {params.row.id}
;
@@ -174,7 +174,7 @@ const organizationFunds = (): JSX.Element => {
minWidth: 100,
headerAlign: 'center',
sortable: false,
- headerClassName: `${styles.tableHeader}`,
+ headerClassName: `${styles.tableHeaders}`,
renderCell: (params: GridCellParams) => {
return (
{
minWidth: 100,
headerAlign: 'center',
sortable: false,
- headerClassName: `${styles.tableHeader}`,
+ headerClassName: `${styles.tableHeaders}`,
renderCell: (params: GridCellParams) => {
return params.row.creator.firstName + ' ' + params.row.creator.lastName;
},
@@ -207,7 +207,7 @@ const organizationFunds = (): JSX.Element => {
minWidth: 100,
headerAlign: 'center',
sortable: false,
- headerClassName: `${styles.tableHeader}`,
+ headerClassName: `${styles.tableHeaders}`,
flex: 2,
renderCell: (params: GridCellParams) => {
return (
@@ -225,7 +225,7 @@ const organizationFunds = (): JSX.Element => {
minWidth: 100,
headerAlign: 'center',
sortable: false,
- headerClassName: `${styles.tableHeader}`,
+ headerClassName: `${styles.tableHeaders}`,
renderCell: (params: GridCellParams) => {
return params.row.isArchived ? 'Archived' : 'Active';
},
@@ -238,7 +238,7 @@ const organizationFunds = (): JSX.Element => {
minWidth: 100,
headerAlign: 'center',
sortable: false,
- headerClassName: `${styles.tableHeader}`,
+ headerClassName: `${styles.tableHeaders}`,
renderCell: (params: GridCellParams) => {
return (
<>
@@ -266,7 +266,7 @@ const organizationFunds = (): JSX.Element => {
minWidth: 100,
headerAlign: 'center',
sortable: false,
- headerClassName: `${styles.tableHeader}`,
+ headerClassName: `${styles.tableHeaders}`,
renderCell: (params: GridCellParams) => {
return (
{
placeholder={tCommon('searchByName')}
autoComplete="off"
required
- className={styles.inputField}
+ className={styles.inputFields}
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
data-testid="searchByName"
@@ -312,7 +312,7 @@ const organizationFunds = (): JSX.Element => {
@@ -362,7 +362,7 @@ const organizationFunds = (): JSX.Element => {
),
}}
sx={dataGridStyle}
- getRowClassName={() => `${styles.rowBackground}`}
+ getRowClassName={() => `${styles.rowBackgrounds}`}
autoHeight
rowHeight={65}
rows={funds.map((fund, index) => ({
diff --git a/src/style/app.module.css b/src/style/app.module.css
index 3d161b52b1..ae6daace2f 100644
--- a/src/style/app.module.css
+++ b/src/style/app.module.css
@@ -434,11 +434,6 @@
visibility: visible;
}
-.tagsBreadCrumbs {
- color: var(--bs-gray);
- cursor: pointer;
-}
-
.manageTagScrollableDiv {
scrollbar-width: thin;
scrollbar-color: var(--bs-gray-400) var(--bs-white);
@@ -462,15 +457,6 @@
position: sticky;
}
-/* .checkboxButton{
- background-color: transparent;
-}
-
-.checkboxButton:checked{
- background-color: var(--subtle-blue-grey);
- color:white
-} */
-
input[type='checkbox']:checked + label {
background-color: var(--subtle-blue-grey) !important;
}
@@ -1015,67 +1001,41 @@ hr {
}
}
-.btnsContainer .btnsBlock button {
- margin-left: 1rem;
- display: flex;
- justify-content: center;
- align-items: center;
+.list_box {
+ height: auto;
+ overflow-y: auto;
+ width: 100%;
}
-.btnsContainer input {
- outline: 1px solid var(--bs-gray-400);
+.inputFields {
+ box-shadow: 0 1px 1px #31bb6b;
}
-.btnsContainer .input button {
- width: 52px;
+.fundName {
+ font-weight: 600;
+ cursor: pointer;
}
-@media (max-width: 1020px) {
- .btnsContainer {
- flex-direction: column;
- margin: 1.5rem 0;
- }
-
- .btnsContainer .btnsBlock {
- margin: 1.5rem 0 0 0;
- justify-content: space-between;
- }
-
- .btnsContainer .btnsBlock button {
- margin: 0;
- }
-
- .btnsContainer .btnsBlock div button {
- margin-right: 1.5rem;
- }
+.modalHeader {
+ border: none;
+ padding-bottom: 0;
}
-/* For mobile devices */
-
-@media (max-width: 520px) {
- .btnsContainer {
- margin-bottom: 0;
- }
-
- .btnsContainer .btnsBlock {
- display: block;
- margin-top: 1rem;
- margin-right: 0;
- }
-
- .btnsContainer .btnsBlock div {
- flex: 1;
- }
+.label {
+ color: var(--bs-emphasis-color);
+}
- .btnsContainer .btnsBlock div[title='Sort organizations'] {
- margin-right: 0.5rem;
- }
+.fundModal {
+ max-width: 80vw;
+ margin-top: 2vh;
+ margin-left: 13vw;
+}
- .btnsContainer .btnsBlock button {
- margin-bottom: 1rem;
- margin-right: 0;
- width: 100%;
- }
+.btnsContainer .btnsBlock button {
+ margin-left: 1rem;
+ display: flex;
+ justify-content: center;
+ align-items: center;
}
.errorMessage {
@@ -1086,7 +1046,7 @@ hr {
flex-direction: column;
}
-.tableHeader {
+.tableHeaders {
background-color: var(--bs-primary-text-emphasis);
color: var(--bs-white);
font-size: 1rem;
@@ -1107,10 +1067,6 @@ hr {
}
}
-.subTagsLink i {
- visibility: hidden;
-}
-
.tagsBreadCrumbs {
color: var(--bs-gray);
cursor: pointer;
@@ -1176,6 +1132,25 @@ input[type='radio']:checked + label {
transition:
transform 0.2s,
box-shadow 0.2s;
+ width: 100%;
+}
+
+.manageBtn {
+ margin: 1rem 0 0;
+ margin-top: 15px;
+ border: 1px solid #e8e5e5;
+ box-shadow: 0 2px 2px #e8e5e5;
+ padding: 10px 10px;
+ border-radius: 5px;
+ font-size: 16px;
+ color: white;
+ outline: none;
+ font-weight: 600;
+ cursor: pointer;
+ width: 45%;
+ transition:
+ transform 0.2s,
+ box-shadow 0.2s;
}
.removeFilterIcon {
@@ -1222,18 +1197,10 @@ input[type='radio']:checked + label {
opacity: 1;
}
-.inputField {
- margin-top: 10px;
- margin-bottom: 10px;
- background-color: white;
+.inputFields {
box-shadow: 0 1px 1px var(--brand-primary);
}
-.inputField > button {
- padding-top: 10px;
- padding-bottom: 10px;
-}
-
.dropdowns {
background-color: white;
border: 1px solid #31bb6b;
@@ -1248,12 +1215,6 @@ input[type='radio']:checked + label {
max-height: 120px;
}
-.tableHeaders {
- background-color: var(--bs-primary);
- color: var(--bs-white);
- font-size: 1rem;
-}
-
.chipIcon {
height: 0.9rem !important;
}
From 22b267a8ae69986105abd70267fbb9137e4dbad1 Mon Sep 17 00:00:00 2001
From: Abhishek Raj <113784630+abbi4code@users.noreply.github.com>
Date: Tue, 24 Dec 2024 14:58:01 +0530
Subject: [PATCH 062/133] UserPortal/People component test migrated jest to
vitest (#2766)
---
.../{People.test.tsx => People.spec.tsx} | 44 +++++++++++++------
1 file changed, 30 insertions(+), 14 deletions(-)
rename src/screens/UserPortal/People/{People.test.tsx => People.spec.tsx} (82%)
diff --git a/src/screens/UserPortal/People/People.test.tsx b/src/screens/UserPortal/People/People.spec.tsx
similarity index 82%
rename from src/screens/UserPortal/People/People.test.tsx
rename to src/screens/UserPortal/People/People.spec.tsx
index c978a0a5a3..11051538db 100644
--- a/src/screens/UserPortal/People/People.test.tsx
+++ b/src/screens/UserPortal/People/People.spec.tsx
@@ -13,6 +13,19 @@ import i18nForTest from 'utils/i18nForTest';
import { StaticMockLink } from 'utils/StaticMockLink';
import People from './People';
import userEvent from '@testing-library/user-event';
+import { vi } from 'vitest';
+
+/**
+ * This file contains unit tests for the People component.
+ *
+ * The tests cover:
+ * - Proper rendering of the People screen and its elements.
+ * - Functionality of the search input and search button.
+ * - Correct behavior when switching between member and admin modes.
+ * - Integration with mocked GraphQL queries for testing data fetching.
+ *
+ * These tests use Vitest for test execution, MockedProvider for mocking GraphQL queries, and react-testing-library for rendering and interactions.
+ */
const MOCKS = [
{
@@ -113,27 +126,30 @@ async function wait(ms = 100): Promise {
});
}
-jest.mock('react-router-dom', () => ({
- ...jest.requireActual('react-router-dom'),
- useParams: () => ({ orgId: '' }),
-}));
+vi.mock('react-router-dom', async () => {
+ const actual = await vi.importActual('react-router-dom');
+ return {
+ ...actual,
+ useParams: () => ({ orgId: '' }),
+ };
+});
describe('Testing People Screen [User Portal]', () => {
Object.defineProperty(window, 'matchMedia', {
writable: true,
- value: jest.fn().mockImplementation((query) => ({
+ value: vi.fn().mockImplementation((query) => ({
matches: false,
media: query,
onchange: null,
- addListener: jest.fn(), // Deprecated
- removeListener: jest.fn(), // Deprecated
- addEventListener: jest.fn(),
- removeEventListener: jest.fn(),
- dispatchEvent: jest.fn(),
+ addListener: vi.fn(), // Deprecated
+ removeListener: vi.fn(), // Deprecated
+ addEventListener: vi.fn(),
+ removeEventListener: vi.fn(),
+ dispatchEvent: vi.fn(),
})),
});
- test('Screen should be rendered properly', async () => {
+ it('Screen should be rendered properly', async () => {
render(
@@ -151,7 +167,7 @@ describe('Testing People Screen [User Portal]', () => {
expect(screen.queryAllByText('Noble Mittal')).not.toBe([]);
});
- test('Search works properly by pressing enter', async () => {
+ it('Search works properly by pressing enter', async () => {
render(
@@ -173,7 +189,7 @@ describe('Testing People Screen [User Portal]', () => {
expect(screen.queryByText('Noble Mittal')).not.toBeInTheDocument();
});
- test('Search works properly by clicking search Btn', async () => {
+ it('Search works properly by clicking search Btn', async () => {
render(
@@ -199,7 +215,7 @@ describe('Testing People Screen [User Portal]', () => {
expect(screen.queryByText('Noble Mittal')).not.toBeInTheDocument();
});
- test('Mode is changed to Admins', async () => {
+ it('Mode is changed to Admins', async () => {
render(
From 70253609f1e17b00a5159e0eb4ab7af15a572b08 Mon Sep 17 00:00:00 2001
From: Ramneet Singh <144323012+Ramneet04@users.noreply.github.com>
Date: Tue, 24 Dec 2024 15:31:53 +0530
Subject: [PATCH 063/133] Refactor : src/setup/checkConnection/checkConnection
from Jest to Vitest #2751 (#2767)
* file name changed
* prettier check
---
...eckConnection.test.ts => checkConnection.spec.ts} | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
rename src/setup/checkConnection/{checkConnection.test.ts => checkConnection.spec.ts} (84%)
diff --git a/src/setup/checkConnection/checkConnection.test.ts b/src/setup/checkConnection/checkConnection.spec.ts
similarity index 84%
rename from src/setup/checkConnection/checkConnection.test.ts
rename to src/setup/checkConnection/checkConnection.spec.ts
index c6f5251bdf..724f1a49dd 100644
--- a/src/setup/checkConnection/checkConnection.test.ts
+++ b/src/setup/checkConnection/checkConnection.spec.ts
@@ -1,8 +1,8 @@
import { checkConnection } from './checkConnection';
+import { vi, describe, beforeEach, it, expect } from 'vitest';
+vi.mock('node-fetch');
-jest.mock('node-fetch');
-
-global.fetch = jest.fn((url) => {
+global.fetch = vi.fn((url) => {
if (url === 'http://example.com/graphql/') {
const responseInit: ResponseInit = {
status: 200,
@@ -22,11 +22,11 @@ global.fetch = jest.fn((url) => {
describe('checkConnection', () => {
beforeEach(() => {
- jest.clearAllMocks();
+ vi.clearAllMocks();
});
test('should return true and log success message if the connection is successful', async () => {
- jest.spyOn(console, 'log').mockImplementation((string) => string);
+ vi.spyOn(console, 'log').mockImplementation((string) => string);
const result = await checkConnection('http://example.com/graphql/');
expect(result).toBe(true);
@@ -39,7 +39,7 @@ describe('checkConnection', () => {
});
it('should return false and log error message if the connection fails', async () => {
- jest.spyOn(console, 'log').mockImplementation((string) => string);
+ vi.spyOn(console, 'log').mockImplementation((string) => string);
const result = await checkConnection(
'http://example_not_working.com/graphql/',
);
From a374f1d6bafb2b575774884ebfd3dbc3ef11be58 Mon Sep 17 00:00:00 2001
From: Gurram Karthik <167804249+gurramkarthiknetha@users.noreply.github.com>
Date: Tue, 24 Dec 2024 16:30:19 +0530
Subject: [PATCH 064/133] fixed:#2510 Refactor CSS files in
src/screens/ManageTag (#2769)
* issue-2510-fixed
* changed in css
* changed acc to coderabbin
---
src/screens/ManageTag/ManageTag.tsx | 8 +--
src/style/app.module.css | 105 ++++++++++++++--------------
2 files changed, 55 insertions(+), 58 deletions(-)
diff --git a/src/screens/ManageTag/ManageTag.tsx b/src/screens/ManageTag/ManageTag.tsx
index 6afec3f130..7eb6a3221d 100644
--- a/src/screens/ManageTag/ManageTag.tsx
+++ b/src/screens/ManageTag/ManageTag.tsx
@@ -292,7 +292,7 @@ function ManageTag(): JSX.Element {
minWidth: 100,
align: 'center',
headerAlign: 'center',
- headerClassName: `${styles.tableHeader}`,
+ headerClassName: `${styles.tableHeaders}`,
sortable: false,
renderCell: (params: GridCellParams) => {
return {params.row.id}
;
@@ -304,7 +304,7 @@ function ManageTag(): JSX.Element {
flex: 2,
minWidth: 100,
sortable: false,
- headerClassName: `${styles.tableHeader}`,
+ headerClassName: `${styles.tableHeaders}`,
renderCell: (params: GridCellParams) => {
return (
@@ -321,7 +321,7 @@ function ManageTag(): JSX.Element {
minWidth: 100,
headerAlign: 'center',
sortable: false,
- headerClassName: `${styles.tableHeader}`,
+ headerClassName: `${styles.tableHeaders}`,
renderCell: (params: GridCellParams) => {
return (
@@ -494,7 +494,7 @@ function ManageTag(): JSX.Element {
),
}}
sx={dataGridStyle}
- getRowClassName={() => `${styles.rowBackground}`}
+ getRowClassName={() => `${styles.rowBackgrounds}`}
autoHeight
rowHeight={65}
rows={userTagAssignedMembers?.map(
diff --git a/src/style/app.module.css b/src/style/app.module.css
index ae6daace2f..1903c7b323 100644
--- a/src/style/app.module.css
+++ b/src/style/app.module.css
@@ -12,10 +12,14 @@
--search-button-bg: #a8c7fa;
--search-button-border: #555555;
--table-image-size: 50px;
+ --bs-primary: #0056b3;
+ --bs-white: #fff;
+ --table-head-bg: var(--bs-primary, blue);
--table-head-bg: var(
--bs-primary,
blue
); /* Assuming var(--bs-primary) is defined elsewhere */
+
--table-head-color: white;
--table-header-color: var(--bs-greyish-black, black);
--table-head-radius: 20px;
@@ -87,6 +91,7 @@
border-bottom: 3px solid #31bb6b;
width: 15%;
}
+
.searchtitle {
color: #707070;
font-weight: 600;
@@ -101,6 +106,7 @@
display: flex;
justify-content: space-between;
}
+
.admindetails > p {
margin-top: -12px;
margin-right: 30px;
@@ -113,10 +119,12 @@
margin-right: -15px;
margin-bottom: 20px;
}
+
.justifysp {
display: flex;
justify-content: space-between;
}
+
@media screen and (max-width: 575.5px) {
.justifysp {
padding-left: 55px;
@@ -204,13 +212,11 @@
.input {
flex: 1;
-
position: relative;
}
.btnsContainer {
display: flex;
- /* Adjust spacing between items */
margin: 2.5rem 0;
align-items: center;
gap: 10px;
@@ -221,21 +227,33 @@
width: max-content;
}
-.btnsContainer .btnsBlock button {
+.btnsContainerBlockAndUnblock {
+ display: flex;
+ margin: 2.5rem 0 2.5rem 0;
+}
+
+.btnsContainerBlockAndUnblock .btnsBlockBlockAndUnblock {
+ display: flex;
+}
+
+.btnsContainerBlockAndUnblock .btnsBlockBlockAndUnblock button {
margin-left: 1rem;
display: flex;
justify-content: center;
align-items: center;
}
-.btnsContainer .input {
+.btnsContainerBlockAndUnblock .inputContainerBlockAndUnblock {
flex: 1;
position: relative;
- max-width: 60%;
- justify-content: space-between;
}
-.btnsContainer input {
+.btnsContainerBlockAndUnblock .inputBlockAndUnblock {
+ width: 70%;
+ position: relative;
+}
+
+.btnsContainerBlockAndUnblock input {
outline: 1px solid var(--bs-gray-400);
}
@@ -380,27 +398,10 @@
font-size: var(--font-size-header);
}
-.orgUserTagsScrollableDiv {
- scrollbar-width: auto;
- scrollbar-color: var(--bs-gray-400) var(--bs-white);
-
- max-height: calc(100vh - 18rem);
- overflow: auto;
- position: sticky;
-}
-
.errorContainer {
min-height: 100vh;
}
-.errorMessage {
- margin-top: 25%;
- display: flex;
- justify-content: center;
- align-items: center;
- flex-direction: column;
-}
-
.errorIcon {
transform: scale(1.5);
color: var(--bs-danger);
@@ -412,12 +413,6 @@
}
}
-.subTagsLink {
- color: var(--subtle-blue-grey);
- font-weight: 500;
- cursor: pointer;
-}
-
.subTagsLink i {
visibility: hidden;
}
@@ -437,7 +432,6 @@
.manageTagScrollableDiv {
scrollbar-width: thin;
scrollbar-color: var(--bs-gray-400) var(--bs-white);
-
max-height: calc(100vh - 18rem);
overflow: auto;
}
@@ -504,6 +498,7 @@ hr {
display: flex;
justify-content: flex-end;
}
+
.icon {
margin: 1px;
}
@@ -544,10 +539,6 @@ hr {
align-items: center;
}
-.toggleBtn:hover {
- color: var(--bs-primary) !important;
-}
-
.pageNotFound {
position: relative;
bottom: 20px;
@@ -563,10 +554,12 @@ hr {
margin-top: 50px;
font-size: 40px;
}
+
.pageNotFound .brand h3 {
font-weight: 300;
margin: 10px 0 0 0;
}
+
.pageNotFound h1.head {
font-size: 250px;
font-weight: 900;
@@ -574,6 +567,7 @@ hr {
letter-spacing: 25px;
margin: 10px 0 0 0;
}
+
.pageNotFound h1.head span {
position: relative;
display: inline-block;
@@ -590,6 +584,7 @@ hr {
.pageNotFound h1.head span:before {
left: -55%;
}
+
.pageNotFound h1.head span:after {
right: -55%;
}
@@ -839,6 +834,7 @@ hr {
font-size: 1rem;
color: black;
}
+
.cardBody {
min-height: 180px;
}
@@ -852,13 +848,6 @@ hr {
height: 2.5rem;
}
-@media (max-width: 520px) {
- .btn {
- flex-direction: column;
- justify-content: center;
- }
-}
-
@media (max-width: 1024px) {
.pageNotFound h1.head {
font-size: 200px;
@@ -922,12 +911,15 @@ hr {
right: -30%;
}
}
-
@media (max-width: 520px) {
.btnsContainer {
margin-bottom: 0;
}
+ .btn {
+ flex-direction: column;
+ justify-content: center;
+ }
.btnsContainer .btnsBlock {
display: block;
margin-top: 1rem;
@@ -1000,6 +992,16 @@ hr {
transform: rotate(360deg);
}
}
+.btnsContainer .input {
+ flex: 1;
+ position: relative;
+ max-width: 60%;
+ justify-content: space-between;
+}
+
+.btnsContainer input {
+ outline: 1px solid var(--bs-gray-400);
+}
.list_box {
height: auto;
@@ -1007,10 +1009,6 @@ hr {
width: 100%;
}
-.inputFields {
- box-shadow: 0 1px 1px #31bb6b;
-}
-
.fundName {
font-weight: 600;
cursor: pointer;
@@ -1052,6 +1050,12 @@ hr {
font-size: 1rem;
}
+.rowBackgrounds {
+ background-color: var(--bs-white);
+ max-height: 120px;
+ overflow-y: auto; /* Handle content overflow */
+}
+
.subTagsLink {
color: var(--bs-blue);
font-weight: 500;
@@ -1091,7 +1095,6 @@ hr {
.subTagsScrollableDiv {
scrollbar-width: auto;
scrollbar-color: var(--bs-gray-400) var(--bs-white);
-
max-height: calc(100vh - 18rem);
overflow: auto;
}
@@ -1209,12 +1212,6 @@ input[type='radio']:checked + label {
color: #31bb6b;
}
-/* Action Items Data Grid */
-.rowBackgrounds {
- background-color: var(--bs-white);
- max-height: 120px;
-}
-
.chipIcon {
height: 0.9rem !important;
}
From c14708f1d694bb3772de3b1c2dc54c449196d0d9 Mon Sep 17 00:00:00 2001
From: Abhishek Raj <113784630+abbi4code@users.noreply.github.com>
Date: Tue, 24 Dec 2024 16:54:16 +0530
Subject: [PATCH 065/133] Refactor CSS files in src/screens/OrgList (#2764)
* orgList ui bug fixed
* refactor organizationModal css into a single global css file
* fixed className conflicts with global css file
* Consolidating .sampleOrgSection classes int o one
* Removed comments & duplicates
* removed unnecessary code & used css variable to maintain consistency
---
src/screens/OrgList/OrgList.module.css | 324 ----------------------
src/screens/OrgList/OrgList.tsx | 25 +-
src/screens/OrgList/OrganizationModal.tsx | 2 +-
src/style/app.module.css | 313 +++++++++++++++++++++
4 files changed, 327 insertions(+), 337 deletions(-)
delete mode 100644 src/screens/OrgList/OrgList.module.css
diff --git a/src/screens/OrgList/OrgList.module.css b/src/screens/OrgList/OrgList.module.css
deleted file mode 100644
index 6aa245983e..0000000000
--- a/src/screens/OrgList/OrgList.module.css
+++ /dev/null
@@ -1,324 +0,0 @@
-.btnsContainer {
- display: flex;
- margin: 2.5rem 0 2.5rem 0;
-}
-
-.btnsContainer .btnsBlock {
- display: flex;
-}
-
-.orgCreationBtn {
- width: 100%;
- border: None;
-}
-
-.enableEverythingBtn {
- width: 100%;
- border: None;
-}
-
-.pluginStoreBtn {
- width: 100%;
- background-color: white;
- color: #555555;
- border: 0.5px solid #555555;
-}
-
-.pluginStoreBtn:hover,
-.pluginStoreBtn:focus {
- background-color: #dfe1e2 !important;
- color: #555555 !important;
- border-color: #555555 !important;
-}
-
-.line::before {
- content: '';
- display: inline-block;
- width: 100px;
- border-top: 1px solid #000;
- margin: 0 10px;
-}
-
-.line::before {
- left: 0;
-}
-
-.line::after {
- right: 0;
-}
-
-.flexContainer {
- display: flex;
- justify-content: center;
- align-items: center;
- width: 100%;
-}
-
-.orText {
- display: block;
- position: absolute;
- top: calc(-0.7rem + 0.5rem);
- left: calc(50% - 2.6rem);
- margin: 0 auto;
- padding: 0.5rem 2rem;
- z-index: 100;
- background: var(--bs-white);
- color: var(--bs-secondary);
-}
-
-.sampleOrgSection {
- display: grid;
- grid-template-columns: repeat(1, 1fr);
- row-gap: 1em;
-}
-
-.sampleOrgCreationBtn {
- width: 100%;
- background-color: transparent;
- color: #707070;
- border-color: #707070;
- display: flex;
- justify-content: center;
- align-items: center;
-}
-
-.sampleHover:hover {
- border-color: grey;
- color: grey;
-}
-
-.sampleOrgSection {
- font-family: Arial, Helvetica, sans-serif;
- width: 100%;
- display: grid;
- grid-auto-columns: repeat(1, 1fr);
- justify-content: center;
- flex-direction: column;
- align-items: center;
-}
-
-.sampleModalTitle {
- background-color: green;
-}
-
-.btnsContainer .btnsBlock button {
- margin-left: 1rem;
- display: flex;
- justify-content: center;
- align-items: center;
-}
-
-.btnsContainer .input {
- flex: 1;
- position: relative;
-}
-
-.btnsContainer input {
- outline: 1px solid var(--bs-gray-400);
-}
-
-.btnsContainer .input button {
- width: 52px;
-}
-
-.listBox {
- display: flex;
- flex-wrap: wrap;
- overflow: unset !important;
-}
-
-.listBox .itemCard {
- width: 50%;
-}
-
-.notFound {
- flex: 1;
- display: flex;
- justify-content: center;
- align-items: center;
- flex-direction: column;
-}
-
-@media (max-width: 1440px) {
- .contract {
- padding-left: calc(250px + 2rem + 1.5rem);
- }
-
- .listBox .itemCard {
- width: 100%;
- }
-}
-
-@media (max-width: 1020px) {
- .btnsContainer {
- flex-direction: column;
- margin: 1.5rem 0;
- }
-
- .btnsContainer .btnsBlock {
- margin: 1.5rem 0 0 0;
- justify-content: space-between;
- }
-
- .btnsContainer .btnsBlock button {
- margin: 0;
- }
-
- .btnsContainer .btnsBlock div button {
- margin-right: 1.5rem;
- }
-}
-
-/* For mobile devices */
-
-@media (max-width: 520px) {
- .btnsContainer {
- margin-bottom: 0;
- }
-
- .btnsContainer .btnsBlock {
- display: block;
- margin-top: 1rem;
- margin-right: 0;
- }
-
- .btnsContainer .btnsBlock div {
- flex: 1;
- }
-
- .btnsContainer .btnsBlock div[title='Sort organizations'] {
- margin-right: 0.5rem;
- }
-
- .btnsContainer .btnsBlock button {
- margin-bottom: 1rem;
- margin-right: 0;
- width: 100%;
- }
-}
-
-/* Loading OrgList CSS */
-.itemCard .loadingWrapper {
- background-color: var(--bs-white);
- margin: 0.5rem;
- height: calc(120px + 2rem);
- padding: 1rem;
- border-radius: 8px;
- outline: 1px solid var(--bs-gray-200);
- position: relative;
-}
-
-.itemCard .loadingWrapper .innerContainer {
- display: flex;
-}
-
-.itemCard .loadingWrapper .innerContainer .orgImgContainer {
- width: 120px;
- height: 120px;
- border-radius: 4px;
-}
-
-.itemCard .loadingWrapper .innerContainer .content {
- flex: 1;
- display: flex;
- flex-direction: column;
- margin-left: 1rem;
-}
-
-.titlemodaldialog {
- color: #707070;
- font-size: 20px;
- margin-bottom: 20px;
- padding-bottom: 5px;
-}
-
-form label {
- font-weight: bold;
- padding-bottom: 1px;
- font-size: 14px;
- color: #707070;
-}
-
-form > input {
- display: block;
- margin-bottom: 20px;
- border: 1px solid #e8e5e5;
- box-shadow: 2px 1px #e8e5e5;
- padding: 10px 20px;
- border-radius: 5px;
- background: none;
- width: 100%;
- transition: all 0.3s ease-in-out;
- -webkit-transition: all 0.3s ease-in-out;
- -moz-transition: all 0.3s ease-in-out;
- -ms-transition: all 0.3s ease-in-out;
- -o-transition: all 0.3s ease-in-out;
-}
-
-.itemCard .loadingWrapper .innerContainer .content h5 {
- height: 24px;
- width: 60%;
- margin-bottom: 0.8rem;
-}
-
-.modalbody {
- width: 50px;
-}
-
-.pluginStoreBtnContainer {
- display: flex;
- gap: 1rem;
-}
-
-.itemCard .loadingWrapper .innerContainer .content h6[title='Location'] {
- display: block;
- width: 45%;
- height: 18px;
-}
-
-.itemCard .loadingWrapper .innerContainer .content h6 {
- display: block;
- width: 30%;
- height: 16px;
- margin-bottom: 0.8rem;
-}
-
-.itemCard .loadingWrapper .button {
- position: absolute;
- height: 48px;
- width: 92px;
- bottom: 1rem;
- right: 1rem;
- z-index: 1;
-}
-
-@media (max-width: 450px) {
- .itemCard .loadingWrapper {
- height: unset;
- margin: 0.5rem 0;
- padding: 1.25rem 1.5rem;
- }
-
- .itemCard .loadingWrapper .innerContainer {
- flex-direction: column;
- }
-
- .itemCard .loadingWrapper .innerContainer .orgImgContainer {
- height: 200px;
- width: 100%;
- margin-bottom: 0.8rem;
- }
-
- .itemCard .loadingWrapper .innerContainer .content {
- margin-left: 0;
- }
-
- .itemCard .loadingWrapper .button {
- bottom: 0;
- right: 0;
- border-radius: 0.5rem;
- position: relative;
- margin-left: auto;
- display: block;
- }
-}
diff --git a/src/screens/OrgList/OrgList.tsx b/src/screens/OrgList/OrgList.tsx
index baafb17ffd..37a4276982 100644
--- a/src/screens/OrgList/OrgList.tsx
+++ b/src/screens/OrgList/OrgList.tsx
@@ -27,6 +27,7 @@ import type {
InterfaceUserType,
} from 'utils/interfaces';
import useLocalStorage from 'utils/useLocalstorage';
+// import styles from '../../style/app.module.css';
import styles from '../../style/app.module.css';
import OrganizationModal from './OrganizationModal';
@@ -38,7 +39,6 @@ function orgList(): JSX.Element {
function openDialogModal(redirectOrgId: string): void {
setDialogRedirectOrgId(redirectOrgId);
- // console.log(redirectOrgId, dialogRedirectOrgId);
setdialogModalIsOpen(true);
}
@@ -330,7 +330,7 @@ function orgList(): JSX.Element {
return (
<>
{/* Buttons Container */}
-
+
-
+
{[...Array(perPageResult)].map((_, index) => (
-
+
}
hasMore={hasMore}
- className={styles.listBox}
+ className={styles.listBoxOrgList}
data-testid="organizations-list"
endMessage={
@@ -454,7 +455,7 @@ function orgList(): JSX.Element {
? orgsData?.organizationsConnection.map(
(item: InterfaceOrgConnectionInfoType) => {
return (
-
+
);
@@ -466,7 +467,7 @@ function orgList(): JSX.Element {
(item: InterfaceOrgConnectionInfoType) => {
if (isAdminForCurrentOrg(item)) {
return (
-
+
);
@@ -477,7 +478,7 @@ function orgList(): JSX.Element {
{isLoading && (
<>
{[...Array(perPageResult)].map((_, index) => (
-
+
@@ -543,7 +544,7 @@ function orgList(): JSX.Element {
diff --git a/src/screens/OrgList/OrganizationModal.tsx b/src/screens/OrgList/OrganizationModal.tsx
index 8a44d2b851..fb3589d1e5 100644
--- a/src/screens/OrgList/OrganizationModal.tsx
+++ b/src/screens/OrgList/OrganizationModal.tsx
@@ -2,7 +2,7 @@ import React from 'react';
import { Modal, Form, Row, Col, Button } from 'react-bootstrap';
import convertToBase64 from 'utils/convertToBase64';
import type { ChangeEvent } from 'react';
-import styles from './OrgList.module.css';
+import styles from '../../style/app.module.css';
import type { InterfaceAddress } from 'utils/interfaces';
import { countryOptions } from 'utils/formEnumFields';
import useLocalStorage from 'utils/useLocalstorage';
diff --git a/src/style/app.module.css b/src/style/app.module.css
index 1903c7b323..4acd2c72be 100644
--- a/src/style/app.module.css
+++ b/src/style/app.module.css
@@ -1279,3 +1279,316 @@ input[type='radio']:checked + label {
max-height: 220px;
overflow-y: auto;
}
+
+/* * Refortoring css for OrgList */
+
+.btnsContainerOrgList {
+ display: flex;
+ margin: 2.5rem 0 2.5rem 0;
+}
+
+.btnsContainerOrgList .btnsBlockOrgList {
+ display: flex;
+}
+
+.orgCreationBtn {
+ width: 100%;
+ border: None;
+}
+
+.enableEverythingBtn {
+ width: 100%;
+ border: None;
+}
+
+.pluginStoreBtn {
+ width: 100%;
+ background-color: white;
+ color: var(--brown-color);
+ border: 0.5px solid var(--brown-color);
+}
+.searchButtonOrgList {
+ position: absolute;
+ z-index: 10;
+ bottom: 0;
+ inset-inline-end: 0px;
+ height: 100%;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+}
+
+.pluginStoreBtn:hover,
+.pluginStoreBtn:focus {
+ background-color: var(--dropdown-hover-color) !important;
+ color: var(--brown-color) !important;
+ border-color: var(--brown-color) !important;
+}
+
+.flexContainer {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ width: 100%;
+}
+
+.orText {
+ display: block;
+ position: absolute;
+ top: -0.2rem;
+ left: calc(50% - 2.6rem);
+ margin: 0 auto;
+ padding: 0.5rem 2rem;
+ z-index: 100;
+ background: var(--bs-white);
+ color: var(--bs-secondary);
+}
+
+.sampleOrgSection {
+ display: grid;
+ grid-template-columns: repeat(1, 1fr);
+ row-gap: 1em;
+ width: 100%;
+}
+
+.sampleOrgCreationBtn {
+ width: 100%;
+ background-color: transparent;
+ color: #707070;
+ border-color: #707070;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+}
+
+.sampleHover:hover {
+ border-color: grey;
+ color: grey;
+}
+
+.sampleModalTitle {
+ background-color: var(--bs-primary);
+}
+
+.btnsContainerOrgList .btnsBlockOrgList button {
+ margin-left: 1rem;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+}
+
+.btnsContainerOrgList .inputOrgList {
+ flex: 1;
+ position: relative;
+}
+
+.btnsContainerOrgList input {
+ outline: 1px solid var(--bs-gray-400);
+}
+
+.btnsContainerOrgList .inputOrgList button {
+ width: 52px;
+}
+
+.listBoxOrgList {
+ display: flex;
+ flex-wrap: wrap;
+ overflow: unset !important;
+}
+
+.listBoxOrgList .itemCardOrgList {
+ width: 50%;
+}
+
+.notFound {
+ flex: 1;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ flex-direction: column;
+}
+
+@media (max-width: 1440px) {
+ .contractOrgList {
+ padding-left: calc(250px + 2rem + 1.5rem);
+ }
+
+ .listBoxOrgList .itemCardOrgList {
+ width: 100%;
+ }
+}
+
+@media (max-width: 1020px) {
+ .btnsContainerOrgList {
+ flex-direction: column;
+ margin: 1.5rem 0;
+ }
+
+ .btnsContainerOrgList .btnsBlockOrgList {
+ margin: 1.5rem 0 0 0;
+ justify-content: space-between;
+ }
+
+ .btnsContainerOrgList .btnsBlockOrgList button {
+ margin: 0;
+ }
+
+ .btnsContainerOrgList .btnsBlockOrgList div button {
+ margin-right: 1.5rem;
+ }
+}
+
+/* For mobile devices */
+
+@media (max-width: 520px) {
+ .btnsContainerOrgList {
+ margin-bottom: 0;
+ }
+
+ .btnsContainerOrgList .btnsBlockOrgList {
+ display: block;
+ margin-top: 1rem;
+ margin-right: 0;
+ }
+
+ .btnsContainerOrgList .btnsBlockOrgList div {
+ flex: 1;
+ }
+
+ .btnsContainerOrgList .btnsBlockOrgList div[title='Sort organizations'] {
+ margin-right: 0.5rem;
+ }
+
+ .btnsContainerOrgList .btnsBlockOrgList button {
+ margin-bottom: 1rem;
+ margin-right: 0;
+ width: 100%;
+ }
+}
+
+/* Loading OrgList CSS */
+
+.itemCardOrgList .loadingWrapper {
+ background-color: var(--bs-white);
+ margin: 0.5rem;
+ height: calc(120px + 2rem);
+ padding: 1rem;
+ border-radius: 8px;
+ outline: 1px solid var(--bs-gray-200);
+ position: relative;
+}
+
+.itemCardOrgList .loadingWrapper .innerContainer {
+ display: flex;
+}
+
+.itemCardOrgList .loadingWrapper .innerContainer .orgImgContainer {
+ width: 120px;
+ height: 120px;
+ border-radius: 4px;
+}
+
+.itemCardOrgList .loadingWrapper .innerContainer .content {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ margin-left: 1rem;
+}
+
+.titlemodaldialog {
+ color: #707070;
+ font-size: 20px;
+ margin-bottom: 20px;
+ padding-bottom: 5px;
+}
+
+form label {
+ font-weight: bold;
+ padding-bottom: 1px;
+ font-size: 14px;
+ color: #707070;
+}
+
+form > input {
+ display: block;
+ margin-bottom: 20px;
+ border: 1px solid #e8e5e5;
+ box-shadow: 2px 1px #e8e5e5;
+ padding: 10px 20px;
+ border-radius: 5px;
+ background: none;
+ width: 100%;
+ transition: all 0.3s ease-in-out;
+ -webkit-transition: all 0.3s ease-in-out;
+ -moz-transition: all 0.3s ease-in-out;
+ -ms-transition: all 0.3s ease-in-out;
+ -o-transition: all 0.3s ease-in-out;
+}
+
+.itemCardOrgList .loadingWrapper .innerContainer .content h5 {
+ height: 24px;
+ width: 60%;
+ margin-bottom: 0.8rem;
+}
+
+.modalbody {
+ width: 50px;
+}
+
+.pluginStoreBtnContainer {
+ display: flex;
+ gap: 1rem;
+}
+
+.itemCardOrgList .loadingWrapper .innerContainer .content h6[title='Location'] {
+ display: block;
+ width: 45%;
+ height: 18px;
+}
+
+.itemCardOrgList .loadingWrapper .innerContainer .content h6 {
+ display: block;
+ width: 30%;
+ height: 16px;
+ margin-bottom: 0.8rem;
+}
+
+.itemCardOrgList .loadingWrapper .button {
+ position: absolute;
+ height: 48px;
+ width: 92px;
+ bottom: 1rem;
+ right: 1rem;
+ z-index: 1;
+}
+
+@media (max-width: 450px) {
+ .itemCardOrgList .loadingWrapper {
+ height: unset;
+ margin: 0.5rem 0;
+ padding: 1.25rem 1.5rem;
+ }
+
+ .itemCardOrgList .loadingWrapper .innerContainer {
+ flex-direction: column;
+ }
+
+ .itemCardOrgList .loadingWrapper .innerContainer .orgImgContainer {
+ height: 200px;
+ width: 100%;
+ margin-bottom: 0.8rem;
+ }
+
+ .itemCardOrgList .loadingWrapper .innerContainer .content {
+ margin-left: 0;
+ }
+
+ .itemCardOrgList .loadingWrapper .button {
+ bottom: 0;
+ right: 0;
+ border-radius: 0.5rem;
+ position: relative;
+ margin-left: auto;
+ display: block;
+ }
+}
From 8ec66eafa20ef0d3325d7da6b6a01cf92d2e55b6 Mon Sep 17 00:00:00 2001
From: Bandhan Majumder <133476557+bandhan-majumder@users.noreply.github.com>
Date: Tue, 24 Dec 2024 19:56:30 +0530
Subject: [PATCH 066/133] refactor: jest to vitest of OrganizationActionItems :
fixes #2557 (#2773)
* added missed mocks
Not all the params were being mocked properly. As a result of not getting the expected response, useQuery was returning error in actionItemsError. This is fixed now
* Delete src/screens/OrganizationActionItems/OrganizationActionItems.test.tsx
* Create OrganizationActionItems.spec.tsx
Migrated to vitest with functionalities
* Update OrganizationActionItems.spec.tsx
---
.../OrganizationActionItem.mocks.ts | 10 +
.../OrganizationActionItems.spec.tsx | 663 ++++++++++++++++++
.../OrganizationActionItems.test.tsx | 359 ----------
3 files changed, 673 insertions(+), 359 deletions(-)
create mode 100644 src/screens/OrganizationActionItems/OrganizationActionItems.spec.tsx
delete mode 100644 src/screens/OrganizationActionItems/OrganizationActionItems.test.tsx
diff --git a/src/screens/OrganizationActionItems/OrganizationActionItem.mocks.ts b/src/screens/OrganizationActionItems/OrganizationActionItem.mocks.ts
index d7d661fc9d..88f4ed3eef 100644
--- a/src/screens/OrganizationActionItems/OrganizationActionItem.mocks.ts
+++ b/src/screens/OrganizationActionItems/OrganizationActionItem.mocks.ts
@@ -24,6 +24,7 @@ export const MOCKS = [
query: ACTION_ITEM_LIST,
variables: {
organizationId: 'orgId',
+ eventId: 'eventId',
orderBy: null,
where: {
assigneeName: '',
@@ -47,6 +48,7 @@ export const MOCKS = [
query: ACTION_ITEM_LIST,
variables: {
organizationId: 'orgId',
+ eventId: 'eventId',
orderBy: null,
where: {
categoryName: '',
@@ -64,6 +66,7 @@ export const MOCKS = [
query: ACTION_ITEM_LIST,
variables: {
organizationId: 'orgId',
+ eventId: 'eventId',
orderBy: 'dueDate_ASC',
where: {
assigneeName: '',
@@ -81,6 +84,7 @@ export const MOCKS = [
query: ACTION_ITEM_LIST,
variables: {
organizationId: 'orgId',
+ eventId: 'eventId',
orderBy: 'dueDate_DESC',
where: {
assigneeName: '',
@@ -98,6 +102,7 @@ export const MOCKS = [
query: ACTION_ITEM_LIST,
variables: {
organizationId: 'orgId',
+ eventId: 'eventId',
orderBy: null,
where: {
assigneeName: '',
@@ -116,6 +121,7 @@ export const MOCKS = [
query: ACTION_ITEM_LIST,
variables: {
organizationId: 'orgId',
+ eventId: 'eventId',
orderBy: null,
where: {
assigneeName: '',
@@ -134,6 +140,7 @@ export const MOCKS = [
query: ACTION_ITEM_LIST,
variables: {
organizationId: 'orgId',
+ eventId: 'eventId',
orderBy: null,
where: {
assigneeName: 'John',
@@ -151,6 +158,7 @@ export const MOCKS = [
query: ACTION_ITEM_LIST,
variables: {
organizationId: 'orgId',
+ eventId: 'eventId',
orderBy: null,
where: {
categoryName: 'Category 1',
@@ -407,6 +415,7 @@ export const MOCKS_ERROR = [
query: ACTION_ITEM_LIST,
variables: {
organizationId: 'orgId',
+ eventId: 'eventId',
orderBy: null,
where: {
assigneeName: '',
@@ -474,6 +483,7 @@ export const MOCKS_EMPTY = [
query: ACTION_ITEM_LIST,
variables: {
organizationId: 'orgId',
+ eventId: 'eventId',
orderBy: null,
where: {
assigneeName: '',
diff --git a/src/screens/OrganizationActionItems/OrganizationActionItems.spec.tsx b/src/screens/OrganizationActionItems/OrganizationActionItems.spec.tsx
new file mode 100644
index 0000000000..7ae0fc58eb
--- /dev/null
+++ b/src/screens/OrganizationActionItems/OrganizationActionItems.spec.tsx
@@ -0,0 +1,663 @@
+import React, { act } from 'react';
+import { MockedProvider } from '@apollo/react-testing';
+import { LocalizationProvider } from '@mui/x-date-pickers';
+import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
+import { fireEvent, render, screen, waitFor } from '@testing-library/react';
+import userEvent from '@testing-library/user-event';
+import { I18nextProvider } from 'react-i18next';
+import { Provider } from 'react-redux';
+import { MemoryRouter, Route, Routes } from 'react-router-dom';
+import { store } from 'state/store';
+import { StaticMockLink } from 'utils/StaticMockLink';
+import i18n from 'utils/i18nForTest';
+import OrganizationActionItems from 'screens/OrganizationActionItems/OrganizationActionItems';
+
+import {
+ MOCKS,
+ MOCKS_EMPTY,
+ MOCKS_ERROR,
+} from './OrganizationActionItem.mocks';
+import { vi } from 'vitest';
+
+vi.mock('react-toastify', () => ({
+ toast: {
+ success: vi.fn(),
+ error: vi.fn(),
+ },
+}));
+
+vi.mock('@mui/x-date-pickers/DateTimePicker', async () => {
+ return {
+ DateTimePicker: (
+ await vi.importActual('@mui/x-date-pickers/DesktopDateTimePicker')
+ ).DesktopDateTimePicker,
+ };
+});
+
+const link1 = new StaticMockLink(MOCKS);
+const link2 = new StaticMockLink(MOCKS_ERROR);
+const link3 = new StaticMockLink(MOCKS_EMPTY);
+const t = {
+ ...JSON.parse(
+ JSON.stringify(
+ i18n.getDataByLanguage('en')?.translation.organizationActionItems ?? {},
+ ),
+ ),
+ ...JSON.parse(JSON.stringify(i18n.getDataByLanguage('en')?.common ?? {})),
+ ...JSON.parse(JSON.stringify(i18n.getDataByLanguage('en')?.errors ?? {})),
+};
+
+const debounceWait = async (ms = 300): Promise
=> {
+ await act(() => {
+ return new Promise((resolve) => {
+ setTimeout(resolve, ms);
+ });
+ });
+};
+
+describe('Testing Organization Action Items Screen', () => {
+ beforeAll(() => {
+ vi.mock('react-router-dom', async () => ({
+ ...(await vi.importActual('react-router-dom')),
+ useParams: () => ({ orgId: 'orgId', eventId: 'eventId' }),
+ }));
+ });
+
+ afterAll(() => {
+ vi.clearAllMocks();
+ vi.clearAllTimers();
+ });
+
+ it('should redirect to fallback URL if URL params are undefined', async () => {
+ render(
+
+
+
+
+
+
+ }
+ />
+ }
+ />
+
+
+
+
+
+ ,
+ );
+
+ await waitFor(() => {
+ expect(window.location.pathname).toBe('/');
+ });
+ });
+
+ it('should render Organization Action Items screen', async () => {
+ render(
+
+
+
+
+
+
+ }
+ />
+ }
+ />
+
+
+
+
+
+ ,
+ );
+
+ await waitFor(() => {
+ expect(screen.queryByTestId('searchBy')).toBeInTheDocument();
+ expect(screen.queryAllByText('John Doe')).toHaveLength(2);
+ expect(screen.queryAllByText('Jane Doe')).toHaveLength(2);
+ });
+ });
+
+ it('Sort Action Items descending by dueDate', async () => {
+ render(
+
+
+
+
+
+
+ }
+ />
+ }
+ />
+
+
+
+
+
+ ,
+ );
+
+ const sortBtn = await screen.findByTestId('sort');
+ expect(sortBtn).toBeInTheDocument();
+
+ await act(() => {
+ fireEvent.click(sortBtn);
+ });
+
+ await waitFor(() => {
+ expect(screen.getByTestId('dueDate_DESC')).toBeInTheDocument();
+ });
+
+ await act(() => {
+ fireEvent.click(screen.getByTestId('dueDate_DESC'));
+ });
+
+ await waitFor(() => {
+ expect(screen.getAllByTestId('categoryName')[0]).toHaveTextContent(
+ 'Category 2',
+ );
+ });
+ });
+
+ it('Sort Action Items ascending by dueDate', async () => {
+ render(
+
+
+
+
+
+
+ }
+ />
+ }
+ />
+
+
+
+
+
+ ,
+ );
+
+ const sortBtn = await screen.findByTestId('sort');
+ expect(sortBtn).toBeInTheDocument();
+
+ await act(() => {
+ fireEvent.click(sortBtn);
+ });
+
+ await waitFor(() => {
+ expect(screen.getByTestId('dueDate_ASC')).toBeInTheDocument();
+ });
+
+ await act(() => {
+ fireEvent.click(screen.getByTestId('dueDate_ASC'));
+ });
+
+ await waitFor(() => {
+ expect(screen.getAllByTestId('categoryName')[0]).toHaveTextContent(
+ 'Category 1',
+ );
+ });
+ });
+
+ it('Filter Action Items by status (All/Pending)', async () => {
+ render(
+
+
+
+
+
+
+ }
+ />
+ }
+ />
+
+
+
+
+
+ ,
+ );
+
+ const filterBtn = await screen.findByTestId('filter');
+ expect(filterBtn).toBeInTheDocument();
+
+ await act(() => {
+ fireEvent.click(filterBtn);
+ });
+
+ await waitFor(() => {
+ expect(screen.getByTestId('statusAll')).toBeInTheDocument();
+ });
+
+ await act(() => {
+ fireEvent.click(screen.getByTestId('statusAll'));
+ });
+
+ await waitFor(() => {
+ expect(screen.getAllByText('Category 1')).toHaveLength(3);
+ expect(screen.getAllByText('Category 2')).toHaveLength(2);
+ });
+
+ await act(() => {
+ fireEvent.click(filterBtn);
+ });
+
+ await waitFor(() => {
+ expect(screen.getByTestId('statusPending')).toBeInTheDocument();
+ });
+
+ await act(() => {
+ fireEvent.click(screen.getByTestId('statusPending'));
+ });
+
+ await waitFor(() => {
+ expect(screen.queryByText('Category 1')).toBeNull();
+ expect(screen.getByText('Category 2')).toBeInTheDocument();
+ });
+ });
+
+ it('Filter Action Items by status (Completed)', async () => {
+ render(
+
+
+
+
+
+
+ }
+ />
+ }
+ />
+
+
+
+
+
+ ,
+ );
+
+ const filterBtn = await screen.findByTestId('filter');
+ expect(filterBtn).toBeInTheDocument();
+
+ await act(() => {
+ fireEvent.click(filterBtn);
+ });
+
+ await waitFor(() => {
+ expect(screen.getByTestId('statusCompleted')).toBeInTheDocument();
+ });
+
+ await act(() => {
+ fireEvent.click(screen.getByTestId('statusCompleted'));
+ });
+
+ await waitFor(() => {
+ expect(screen.getByText('Category 1')).toBeInTheDocument();
+ expect(screen.queryByText('Category 2')).toBeNull();
+ });
+ });
+
+ it('open and close Item modal (create)', async () => {
+ render(
+
+
+
+
+
+
+ }
+ />
+ }
+ />
+
+
+
+
+
+ ,
+ );
+
+ const addItemBtn = await screen.findByTestId('createActionItemBtn');
+ expect(addItemBtn).toBeInTheDocument();
+ userEvent.click(addItemBtn);
+
+ await waitFor(() =>
+ expect(screen.getAllByText(t.createActionItem)).toHaveLength(2),
+ );
+ userEvent.click(screen.getByTestId('modalCloseBtn'));
+ await waitFor(() =>
+ expect(screen.queryByTestId('modalCloseBtn')).toBeNull(),
+ );
+ });
+
+ it('open and close Item modal (view)', async () => {
+ render(
+
+
+
+
+
+
+ }
+ />
+ }
+ />
+
+
+
+
+
+ ,
+ );
+
+ const viewItemBtn = await screen.findByTestId('viewItemBtn1');
+ expect(viewItemBtn).toBeInTheDocument();
+ userEvent.click(viewItemBtn);
+
+ await waitFor(() =>
+ expect(screen.getByText(t.actionItemDetails)).toBeInTheDocument(),
+ );
+ userEvent.click(screen.getByTestId('modalCloseBtn'));
+ await waitFor(() =>
+ expect(screen.queryByTestId('modalCloseBtn')).toBeNull(),
+ );
+ });
+
+ it('open and closes Item modal (edit)', async () => {
+ render(
+
+
+
+
+
+
+ }
+ />
+ }
+ />
+
+
+
+
+
+ ,
+ );
+
+ const editItemBtn = await screen.findByTestId('editItemBtn1');
+ await waitFor(() => expect(editItemBtn).toBeInTheDocument());
+ userEvent.click(editItemBtn);
+
+ await waitFor(() =>
+ expect(screen.getAllByText(t.updateActionItem)).toHaveLength(2),
+ );
+ userEvent.click(screen.getByTestId('modalCloseBtn'));
+ await waitFor(() =>
+ expect(screen.queryByTestId('modalCloseBtn')).toBeNull(),
+ );
+ });
+
+ it('open and closes Item modal (delete)', async () => {
+ render(
+
+
+
+
+
+
+ }
+ />
+ }
+ />
+
+
+
+
+
+ ,
+ );
+
+ const deleteItemBtn = await screen.findByTestId('deleteItemBtn1');
+ expect(deleteItemBtn).toBeInTheDocument();
+ userEvent.click(deleteItemBtn);
+
+ await waitFor(() =>
+ expect(screen.getByText(t.deleteActionItem)).toBeInTheDocument(),
+ );
+ userEvent.click(screen.getByTestId('modalCloseBtn'));
+ await waitFor(() =>
+ expect(screen.queryByTestId('modalCloseBtn')).toBeNull(),
+ );
+ });
+
+ it('open and closes Item modal (update status)', async () => {
+ render(
+
+
+
+
+
+
+ }
+ />
+ }
+ />
+
+
+
+
+
+ ,
+ );
+
+ const statusCheckbox = await screen.findByTestId('statusCheckbox1');
+ expect(statusCheckbox).toBeInTheDocument();
+ userEvent.click(statusCheckbox);
+
+ await waitFor(() =>
+ expect(screen.getByText(t.actionItemStatus)).toBeInTheDocument(),
+ );
+ userEvent.click(screen.getByTestId('modalCloseBtn'));
+ await waitFor(() =>
+ expect(screen.queryByTestId('modalCloseBtn')).toBeNull(),
+ );
+ });
+
+ it('Search action items by assignee', async () => {
+ render(
+
+
+
+
+
+
+ }
+ />
+ }
+ />
+
+
+
+
+
+ ,
+ );
+
+ const searchByToggle = await screen.findByTestId('searchByToggle');
+ expect(searchByToggle).toBeInTheDocument();
+
+ userEvent.click(searchByToggle);
+ await waitFor(() => {
+ expect(screen.getByTestId('assignee')).toBeInTheDocument();
+ });
+
+ userEvent.click(screen.getByTestId('assignee'));
+
+ const searchInput = await screen.findByTestId('searchBy');
+ expect(searchInput).toBeInTheDocument();
+
+ userEvent.type(searchInput, 'John');
+ await debounceWait();
+
+ await waitFor(() => {
+ expect(screen.getByText('Category 1')).toBeInTheDocument();
+ expect(screen.queryByText('Category 2')).toBeNull();
+ });
+ });
+
+ it('Search action items by category', async () => {
+ render(
+
+
+
+
+
+
+ }
+ />
+ }
+ />
+
+
+
+
+
+ ,
+ );
+
+ const searchByToggle = await screen.findByTestId('searchByToggle');
+ expect(searchByToggle).toBeInTheDocument();
+
+ userEvent.click(searchByToggle);
+ await waitFor(() => {
+ expect(screen.getByTestId('category')).toBeInTheDocument();
+ });
+
+ userEvent.click(screen.getByTestId('category'));
+
+ const searchInput = await screen.findByTestId('searchBy');
+ expect(searchInput).toBeInTheDocument();
+
+ userEvent.type(searchInput, 'Category 1');
+ await debounceWait();
+
+ await waitFor(() => {
+ expect(screen.getByText('Category 1')).toBeInTheDocument();
+ expect(screen.queryByText('Category 2')).toBeNull();
+ });
+ });
+
+ it('should render Empty Action Item Categories Screen', async () => {
+ render(
+
+
+
+
+
+
+ }
+ />
+ }
+ />
+
+
+
+
+
+ ,
+ );
+ await waitFor(() => {
+ expect(screen.getByTestId('searchBy')).toBeInTheDocument();
+ expect(screen.getByText(t.noActionItems)).toBeInTheDocument();
+ });
+ });
+
+ it('should render the Action Item Categories Screen with error', async () => {
+ render(
+
+
+
+
+
+
+ }
+ />
+ }
+ />
+
+
+
+
+
+ ,
+ );
+ await waitFor(() => {
+ expect(screen.getByTestId('errorMsg')).toBeInTheDocument();
+ });
+ });
+});
diff --git a/src/screens/OrganizationActionItems/OrganizationActionItems.test.tsx b/src/screens/OrganizationActionItems/OrganizationActionItems.test.tsx
deleted file mode 100644
index 44e11baa35..0000000000
--- a/src/screens/OrganizationActionItems/OrganizationActionItems.test.tsx
+++ /dev/null
@@ -1,359 +0,0 @@
-import React, { act } from 'react';
-import { MockedProvider } from '@apollo/react-testing';
-import { LocalizationProvider } from '@mui/x-date-pickers';
-import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
-import type { RenderResult } from '@testing-library/react';
-import { fireEvent, render, screen, waitFor } from '@testing-library/react';
-import userEvent from '@testing-library/user-event';
-import { I18nextProvider } from 'react-i18next';
-import { Provider } from 'react-redux';
-import { MemoryRouter, Route, Routes } from 'react-router-dom';
-import { store } from 'state/store';
-import { StaticMockLink } from 'utils/StaticMockLink';
-import i18n from 'utils/i18nForTest';
-import OrganizationActionItems from 'screens/OrganizationActionItems/OrganizationActionItems';
-import type { ApolloLink } from '@apollo/client';
-import {
- MOCKS,
- MOCKS_EMPTY,
- MOCKS_ERROR,
-} from './OrganizationActionItem.mocks';
-
-jest.mock('react-toastify', () => ({
- toast: {
- success: jest.fn(),
- error: jest.fn(),
- },
-}));
-
-jest.mock('@mui/x-date-pickers/DateTimePicker', () => {
- return {
- DateTimePicker: jest.requireActual(
- '@mui/x-date-pickers/DesktopDateTimePicker',
- ).DesktopDateTimePicker,
- };
-});
-
-const link1 = new StaticMockLink(MOCKS);
-const link2 = new StaticMockLink(MOCKS_ERROR);
-const link3 = new StaticMockLink(MOCKS_EMPTY);
-const t = {
- ...JSON.parse(
- JSON.stringify(
- i18n.getDataByLanguage('en')?.translation.organizationActionItems ?? {},
- ),
- ),
- ...JSON.parse(JSON.stringify(i18n.getDataByLanguage('en')?.common ?? {})),
- ...JSON.parse(JSON.stringify(i18n.getDataByLanguage('en')?.errors ?? {})),
-};
-
-const debounceWait = async (ms = 300): Promise
=> {
- await act(() => {
- return new Promise((resolve) => {
- setTimeout(resolve, ms);
- });
- });
-};
-
-const renderOrganizationActionItems = (link: ApolloLink): RenderResult => {
- return render(
-
-
-
-
-
-
- }
- />
- }
- />
-
-
-
-
-
- ,
- );
-};
-
-describe('Testing Organization Action Items Screen', () => {
- beforeAll(() => {
- jest.mock('react-router-dom', () => ({
- ...jest.requireActual('react-router-dom'),
- useParams: () => ({ orgId: 'orgId', eventId: 'eventId' }),
- }));
- });
-
- afterAll(() => {
- jest.clearAllMocks();
- });
-
- it('should redirect to fallback URL if URL params are undefined', async () => {
- render(
-
-
-
-
-
- }
- />
- }
- />
-
-
-
-
- ,
- );
- await waitFor(() => {
- expect(screen.getByTestId('paramsError')).toBeInTheDocument();
- });
- });
-
- it('should render Organization Action Items screen', async () => {
- renderOrganizationActionItems(link1);
- await waitFor(() => {
- expect(screen.getByTestId('searchBy')).toBeInTheDocument();
- expect(screen.getAllByText('John Doe')).toHaveLength(2);
- expect(screen.getAllByText('Jane Doe')).toHaveLength(2);
- });
- });
-
- it('Sort Action Items descending by dueDate', async () => {
- renderOrganizationActionItems(link1);
-
- const sortBtn = await screen.findByTestId('sort');
- expect(sortBtn).toBeInTheDocument();
-
- // Sort by dueDate_DESC
- fireEvent.click(sortBtn);
- await waitFor(() => {
- expect(screen.getByTestId('dueDate_DESC')).toBeInTheDocument();
- });
- fireEvent.click(screen.getByTestId('dueDate_DESC'));
- await waitFor(() => {
- expect(screen.getAllByTestId('categoryName')[0]).toHaveTextContent(
- 'Category 2',
- );
- });
- });
-
- it('Sort Action Items ascending by dueDate', async () => {
- renderOrganizationActionItems(link1);
-
- const sortBtn = await screen.findByTestId('sort');
- expect(sortBtn).toBeInTheDocument();
-
- // Sort by dueDate_ASC
- fireEvent.click(sortBtn);
- await waitFor(() => {
- expect(screen.getByTestId('dueDate_ASC')).toBeInTheDocument();
- });
- fireEvent.click(screen.getByTestId('dueDate_ASC'));
- await waitFor(() => {
- expect(screen.getAllByTestId('categoryName')[0]).toHaveTextContent(
- 'Category 1',
- );
- });
- });
-
- it('Filter Action Items by status (All/Pending)', async () => {
- renderOrganizationActionItems(link1);
-
- const filterBtn = await screen.findByTestId('filter');
- expect(filterBtn).toBeInTheDocument();
-
- // Filter by All
- fireEvent.click(filterBtn);
- await waitFor(() => {
- expect(screen.getByTestId('statusAll')).toBeInTheDocument();
- });
- fireEvent.click(screen.getByTestId('statusAll'));
-
- await waitFor(() => {
- expect(screen.getAllByText('Category 1')).toHaveLength(3);
- expect(screen.getAllByText('Category 2')).toHaveLength(2);
- });
-
- // Filter by Pending
- fireEvent.click(filterBtn);
- await waitFor(() => {
- expect(screen.getByTestId('statusPending')).toBeInTheDocument();
- });
- fireEvent.click(screen.getByTestId('statusPending'));
- await waitFor(() => {
- expect(screen.queryByText('Category 1')).toBeNull();
- expect(screen.getByText('Category 2')).toBeInTheDocument();
- });
- });
-
- it('Filter Action Items by status (Completed)', async () => {
- renderOrganizationActionItems(link1);
-
- const filterBtn = await screen.findByTestId('filter');
- expect(filterBtn).toBeInTheDocument();
-
- fireEvent.click(filterBtn);
- await waitFor(() => {
- expect(screen.getByTestId('statusCompleted')).toBeInTheDocument();
- });
- fireEvent.click(screen.getByTestId('statusCompleted'));
- await waitFor(() => {
- expect(screen.getByText('Category 1')).toBeInTheDocument();
- expect(screen.queryByText('Category 2')).toBeNull();
- });
- });
-
- it('open and close Item modal (create)', async () => {
- renderOrganizationActionItems(link1);
-
- const addItemBtn = await screen.findByTestId('createActionItemBtn');
- expect(addItemBtn).toBeInTheDocument();
- userEvent.click(addItemBtn);
-
- await waitFor(() =>
- expect(screen.getAllByText(t.createActionItem)).toHaveLength(2),
- );
- userEvent.click(screen.getByTestId('modalCloseBtn'));
- await waitFor(() =>
- expect(screen.queryByTestId('modalCloseBtn')).toBeNull(),
- );
- });
-
- it('open and close Item modal (view)', async () => {
- renderOrganizationActionItems(link1);
-
- const viewItemBtn = await screen.findByTestId('viewItemBtn1');
- expect(viewItemBtn).toBeInTheDocument();
- userEvent.click(viewItemBtn);
-
- await waitFor(() =>
- expect(screen.getByText(t.actionItemDetails)).toBeInTheDocument(),
- );
- userEvent.click(screen.getByTestId('modalCloseBtn'));
- await waitFor(() =>
- expect(screen.queryByTestId('modalCloseBtn')).toBeNull(),
- );
- });
-
- it('open and closes Item modal (edit)', async () => {
- renderOrganizationActionItems(link1);
-
- const editItemBtn = await screen.findByTestId('editItemBtn1');
- await waitFor(() => expect(editItemBtn).toBeInTheDocument());
- userEvent.click(editItemBtn);
-
- await waitFor(() =>
- expect(screen.getAllByText(t.updateActionItem)).toHaveLength(2),
- );
- userEvent.click(screen.getByTestId('modalCloseBtn'));
- await waitFor(() =>
- expect(screen.queryByTestId('modalCloseBtn')).toBeNull(),
- );
- });
-
- it('open and closes Item modal (delete)', async () => {
- renderOrganizationActionItems(link1);
-
- const deleteItemBtn = await screen.findByTestId('deleteItemBtn1');
- expect(deleteItemBtn).toBeInTheDocument();
- userEvent.click(deleteItemBtn);
-
- await waitFor(() =>
- expect(screen.getByText(t.deleteActionItem)).toBeInTheDocument(),
- );
- userEvent.click(screen.getByTestId('modalCloseBtn'));
- await waitFor(() =>
- expect(screen.queryByTestId('modalCloseBtn')).toBeNull(),
- );
- });
-
- it('open and closes Item modal (update status)', async () => {
- renderOrganizationActionItems(link1);
-
- const statusCheckbox = await screen.findByTestId('statusCheckbox1');
- expect(statusCheckbox).toBeInTheDocument();
- userEvent.click(statusCheckbox);
-
- await waitFor(() =>
- expect(screen.getByText(t.actionItemStatus)).toBeInTheDocument(),
- );
- userEvent.click(screen.getByTestId('modalCloseBtn'));
- await waitFor(() =>
- expect(screen.queryByTestId('modalCloseBtn')).toBeNull(),
- );
- });
-
- it('Search action items by assignee', async () => {
- renderOrganizationActionItems(link1);
-
- const searchByToggle = await screen.findByTestId('searchByToggle');
- expect(searchByToggle).toBeInTheDocument();
-
- userEvent.click(searchByToggle);
- await waitFor(() => {
- expect(screen.getByTestId('assignee')).toBeInTheDocument();
- });
-
- userEvent.click(screen.getByTestId('assignee'));
-
- const searchInput = await screen.findByTestId('searchBy');
- expect(searchInput).toBeInTheDocument();
-
- userEvent.type(searchInput, 'John');
- await debounceWait();
-
- await waitFor(() => {
- expect(screen.getByText('Category 1')).toBeInTheDocument();
- expect(screen.queryByText('Category 2')).toBeNull();
- });
- });
-
- it('Search action items by category', async () => {
- renderOrganizationActionItems(link1);
-
- const searchByToggle = await screen.findByTestId('searchByToggle');
- expect(searchByToggle).toBeInTheDocument();
-
- userEvent.click(searchByToggle);
- await waitFor(() => {
- expect(screen.getByTestId('category')).toBeInTheDocument();
- });
-
- userEvent.click(screen.getByTestId('category'));
-
- const searchInput = await screen.findByTestId('searchBy');
- expect(searchInput).toBeInTheDocument();
-
- userEvent.type(searchInput, 'Category 1');
- await debounceWait();
-
- await waitFor(() => {
- expect(screen.getByText('Category 1')).toBeInTheDocument();
- expect(screen.queryByText('Category 2')).toBeNull();
- });
- });
-
- it('should render Empty Action Item Categories Screen', async () => {
- renderOrganizationActionItems(link3);
- await waitFor(() => {
- expect(screen.getByTestId('searchBy')).toBeInTheDocument();
- expect(screen.getByText(t.noActionItems)).toBeInTheDocument();
- });
- });
-
- it('should render the Action Item Categories Screen with error', async () => {
- renderOrganizationActionItems(link2);
- await waitFor(() => {
- expect(screen.getByTestId('errorMsg')).toBeInTheDocument();
- });
- });
-});
From 7755890a13519d451ffcfdee0e3cb14f63291fe5 Mon Sep 17 00:00:00 2001
From: Nikhil Raj <125121367+hustlernik@users.noreply.github.com>
Date: Tue, 24 Dec 2024 20:12:51 +0530
Subject: [PATCH 067/133] [CHORES] Refactor CSS for Org Post (#2774)
* refactor: org-post css
* Fix duplicate properties and class definitions
* Remove duplicate keyframe definitions and optimize loader styles
---
src/screens/OrgPost/OrgPost.module.css | 325 -------------------------
src/screens/OrgPost/OrgPost.tsx | 16 +-
src/style/app.module.css | 187 +++++++++++++-
3 files changed, 194 insertions(+), 334 deletions(-)
delete mode 100644 src/screens/OrgPost/OrgPost.module.css
diff --git a/src/screens/OrgPost/OrgPost.module.css b/src/screens/OrgPost/OrgPost.module.css
deleted file mode 100644
index e674efbc7a..0000000000
--- a/src/screens/OrgPost/OrgPost.module.css
+++ /dev/null
@@ -1,325 +0,0 @@
-.mainpage {
- display: flex;
- flex-direction: row;
-}
-.btnsContainer {
- display: flex;
- margin: 2.5rem 0 2.5rem 0;
-}
-
-.btnsContainer .btnsBlock {
- display: flex;
-}
-
-.btnsContainer .btnsBlock button {
- margin-left: 1rem;
- display: flex;
- justify-content: center;
- align-items: center;
-}
-
-.btnsContainer .input {
- flex: 1;
- position: relative;
-}
-
-.btnsContainer input {
- outline: 1px solid var(--bs-gray-400);
-}
-
-.btnsContainer .input button {
- width: 52px;
-}
-
-.preview {
- display: flex;
- position: relative;
- width: 100%;
- margin-top: 10px;
- justify-content: center;
-}
-.preview img {
- width: 400px;
- height: auto;
-}
-.preview video {
- width: 400px;
- height: auto;
-}
-.logintitle {
- color: #707070;
- font-weight: 600;
- font-size: 20px;
- margin-bottom: 30px;
- padding-bottom: 5px;
- border-bottom: 3px solid #31bb6b;
- width: 15%;
-}
-.logintitleadmin {
- color: #707070;
- font-weight: 600;
- font-size: 18px;
- margin-top: 50px;
- margin-bottom: 40px;
- padding-bottom: 5px;
- border-bottom: 3px solid #31bb6b;
- width: 30%;
-}
-.admindetails {
- display: flex;
- justify-content: space-between;
-}
-.admindetails > p {
- margin-top: -12px;
- margin-right: 30px;
-}
-
-.mainpageright > hr {
- margin-top: 20px;
- width: 100%;
- margin-left: -15px;
- margin-right: -15px;
- margin-bottom: 20px;
-}
-.justifysp {
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin-bottom: 3rem;
-}
-
-@media (max-width: 1120px) {
- .contract {
- padding-left: calc(250px + 2rem + 1.5rem);
- }
-
- .listBox .itemCard {
- width: 100%;
- }
-}
-
-@media (max-width: 1020px) {
- .btnsContainer {
- flex-direction: column;
- margin: 1.5rem 0;
- }
-
- .btnsContainer .btnsBlock {
- margin: 1.5rem 0 0 0;
- justify-content: space-between;
- }
-
- .btnsContainer .btnsBlock button {
- margin: 0;
- }
-
- .btnsContainer .btnsBlock div button {
- margin-right: 1.5rem;
- }
-}
-
-/* For mobile devices */
-
-@media (max-width: 520px) {
- .btnsContainer {
- margin-bottom: 0;
- }
-
- .btnsContainer .btnsBlock {
- display: block;
- margin-top: 1rem;
- margin-right: 0;
- }
-
- .btnsContainer .btnsBlock div {
- flex: 1;
- }
-
- .btnsContainer .btnsBlock div[title='Sort organizations'] {
- margin-right: 0.5rem;
- }
-
- .btnsContainer .btnsBlock button {
- margin-bottom: 1rem;
- margin-right: 0;
- width: 100%;
- }
-}
-@media screen and (max-width: 575.5px) {
- .justifysp {
- display: flex;
- justify-content: space-between;
- width: 100%;
- }
-
- .mainpageright {
- width: 98%;
- }
-}
-.addbtn {
- border: 1px solid #e8e5e5;
- box-shadow: 0 2px 2px #e8e5e5;
- border-radius: 5px;
- font-size: 16px;
- height: 60%;
- width: 60%;
- color: white;
- outline: none;
- font-weight: 600;
- cursor: pointer;
- transition:
- transform 0.2s,
- box-shadow 0.2s;
-}
-.flexdir {
- display: flex;
- flex-direction: row;
- justify-content: space-between;
- border: none;
-}
-.form_wrapper {
- margin-top: 27px;
- top: 50%;
- left: 50%;
- transform: translate(-50%, -50%);
- position: absolute;
- display: flex;
- flex-direction: column;
- padding: 20px 30px;
- background: #ffffff;
- border-color: #e8e5e5;
- border-width: 5px;
- border-radius: 10px;
-}
-
-.form_wrapper form {
- display: flex;
- align-items: left;
- justify-content: left;
- flex-direction: column;
-}
-.logintitleinvite {
- color: #707070;
- font-weight: 600;
- font-size: 20px;
- margin-bottom: 20px;
- padding-bottom: 5px;
- border-bottom: 3px solid #31bb6b;
- width: 40%;
-}
-.postinfo {
- height: 80px;
-}
-
-.postinfo {
- height: 80px;
- margin-bottom: 20px;
-}
-.titlemodal {
- color: #707070;
- font-weight: 600;
- font-size: 20px;
- margin-bottom: 20px;
- padding-bottom: 5px;
- border-bottom: 3px solid #31bb6b;
- width: 65%;
-}
-.cancel > i {
- margin-top: 5px;
- transform: scale(1.2);
- cursor: pointer;
- color: #707070;
-}
-.modalbody {
- width: 50px;
-}
-
-.closeButton {
- position: absolute;
- top: 0px;
- right: 0px;
- background: transparent;
- transform: scale(1.2);
- cursor: pointer;
- border: none;
- color: #707070;
- font-weight: 600;
- font-size: 16px;
- cursor: pointer;
-}
-.sidebarsticky > input {
- text-decoration: none;
- margin-bottom: 50px;
- border: solid 1.5px #d3d3d3;
- border-radius: 5px;
- width: 80%;
- border-radius: 7px;
- padding-top: 5px;
- padding-bottom: 5px;
- padding-right: 10px;
- padding-left: 10px;
- text-decoration: none;
- box-shadow: none;
-}
-
-.sidebarsticky > input:focus {
- border-color: #fff;
- box-shadow: 0 0 5pt 0.5pt #d3d3d3;
- outline: none;
-}
-button[data-testid='createPostBtn'] {
- display: block;
-}
-.loader,
-.loader:after {
- border-radius: 50%;
- width: 10em;
- height: 10em;
-}
-.loader {
- margin: 60px auto;
- margin-top: 35vh !important;
- font-size: 10px;
- position: relative;
- text-indent: -9999em;
- border-top: 1.1em solid rgba(255, 255, 255, 0.2);
- border-right: 1.1em solid rgba(255, 255, 255, 0.2);
- border-bottom: 1.1em solid rgba(255, 255, 255, 0.2);
- border-left: 1.1em solid #febc59;
- -webkit-transform: translateZ(0);
- -ms-transform: translateZ(0);
- transform: translateZ(0);
- -webkit-animation: load8 1.1s infinite linear;
- animation: load8 1.1s infinite linear;
-}
-@-webkit-keyframes load8 {
- 0% {
- -webkit-transform: rotate(0deg);
- transform: rotate(0deg);
- }
- 100% {
- -webkit-transform: rotate(360deg);
- transform: rotate(360deg);
- }
-}
-@keyframes load8 {
- 0% {
- -webkit-transform: rotate(0deg);
- transform: rotate(0deg);
- }
- 100% {
- -webkit-transform: rotate(360deg);
- transform: rotate(360deg);
- }
-}
-.list_box {
- height: 70vh;
- overflow-y: auto;
- width: auto;
-}
-@media only screen and (max-width: 600px) {
- .form_wrapper {
- width: 90%;
- top: 45%;
- }
-}
diff --git a/src/screens/OrgPost/OrgPost.tsx b/src/screens/OrgPost/OrgPost.tsx
index e2c388d7b0..e9cb4d4ca2 100644
--- a/src/screens/OrgPost/OrgPost.tsx
+++ b/src/screens/OrgPost/OrgPost.tsx
@@ -284,9 +284,9 @@ function orgPost(): JSX.Element {
return (
<>
-
-
-
+
+
+
-
+
{postformState.addMedia && file && (
-
+
{/* Display preview for both image and video */}
{file.type.startsWith('image') ? (
)}
{
setPostFormState({
...postformState,
@@ -551,7 +551,7 @@ function orgPost(): JSX.Element {
hideInviteModal()}
data-testid="closeOrganizationModal"
>
@@ -561,7 +561,7 @@ function orgPost(): JSX.Element {
type="submit"
value="invite"
data-testid="createPostBtn"
- className={`${styles.addButton} mt-2`}
+ className={`${styles.addButtonOrgPost} mt-2`}
>
{t('addPost')}
diff --git a/src/style/app.module.css b/src/style/app.module.css
index 4acd2c72be..af2469c6e8 100644
--- a/src/style/app.module.css
+++ b/src/style/app.module.css
@@ -17,7 +17,8 @@
--table-head-bg: var(--bs-primary, blue);
--table-head-bg: var(
--bs-primary,
- blue
+ blue --loader-size: 10em; --loader-border-width: 1.1em; --loader-color:
+ #febc59;
); /* Assuming var(--bs-primary) is defined elsewhere */
--table-head-color: white;
@@ -1592,3 +1593,187 @@ form > input {
display: block;
}
}
+
+/* CSS Refactor for OrgPost */
+
+.btnsContainerOrgPost {
+ display: flex;
+ margin: 2.5rem 0 2.5rem 0;
+}
+
+.btnsContainerOrgPost .btnsBlockOrgPost {
+ display: flex;
+}
+
+.btnsContainerOrgPost .btnsBlockOrgPost button {
+ margin-left: 1rem;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+}
+
+.btnsContainerOrgPost .inputOrgPost {
+ flex: 1;
+ position: relative;
+}
+
+.btnsContainerOrgPost input {
+ outline: 1px solid var(--bs-gray-400);
+}
+
+.btnsContainerOrgPost .inputOrgPost button {
+ width: 52px;
+}
+
+.previewOrgPost {
+ display: flex;
+ position: relative;
+ width: 100%;
+ margin-top: 10px;
+ justify-content: center;
+}
+.previewOrgPost img {
+ width: 400px;
+ height: auto;
+}
+.previewOrgPost video {
+ width: 400px;
+ height: auto;
+}
+.mainpagerightOrgPost > hr {
+ margin-top: 20px;
+ width: 100%;
+ margin-left: -15px;
+ margin-right: -15px;
+ margin-bottom: 20px;
+}
+
+@media (max-width: 1020px) {
+ .btnsContainerOrgPost {
+ flex-direction: column;
+ margin: 1.5rem 0;
+ }
+
+ .btnsContainerOrgPost .btnsBlockOrgPost {
+ margin: 1.5rem 0 0 0;
+ justify-content: space-between;
+ }
+
+ .btnsContainerOrgPost .btnsBlockOrgPost button {
+ margin: 0;
+ }
+
+ .btnsContainerOrgPost .btnsBlockOrgPost div button {
+ margin-right: 1.5rem;
+ }
+}
+
+/* For mobile devices */
+
+@media (max-width: 520px) {
+ .btnsContainerOrgPost {
+ margin-bottom: 0;
+ }
+
+ .btnsContainerOrgPost .btnsBlockOrgPost {
+ display: block;
+ margin-top: 1rem;
+ margin-right: 0;
+ }
+
+ .btnsContainerOrgPost .btnsBlockOrgPost div {
+ flex: 1;
+ }
+
+ .btnsContainerOrgPost .btnsBlockOrgPost div[title='Sort organizations'] {
+ margin-right: 0.5rem;
+ }
+
+ .btnsContainerOrgPost .btnsBlockOrgPost button {
+ margin-bottom: 1rem;
+ margin-right: 0;
+ width: 100%;
+ }
+}
+@media screen and (max-width: 575.5px) {
+ .mainpagerightOrgPost {
+ width: 98%;
+ }
+}
+.addbtnOrgPost {
+ border: 1px solid #e8e5e5;
+ box-shadow: 0 2px 2px #e8e5e5;
+ border-radius: 5px;
+ font-size: 16px;
+ height: 60%;
+ width: 60%;
+ color: white;
+ outline: none;
+ font-weight: 600;
+ cursor: pointer;
+ transition:
+ transform 0.2s,
+ box-shadow 0.2s;
+}
+.postinfo {
+ height: 80px;
+ margin-bottom: 20px;
+}
+.closeButtonOrgPost {
+ position: absolute;
+ top: 0px;
+ right: 0px;
+ background: transparent;
+ transform: scale(1.2);
+ cursor: pointer;
+ border: none;
+ color: #707070;
+ font-weight: 600;
+ font-size: 16px;
+}
+button[data-testid='createPostBtn'] {
+ display: block;
+}
+.loader,
+.loader:after {
+ border-radius: 50%;
+ width: var(--loader-size);
+ height: var(--loader-size);
+}
+.loader {
+ margin: 60px auto;
+ margin-top: 35vh !important;
+ font-size: 10px;
+ position: relative;
+ text-indent: -9999em;
+ border-top: 1.1em solid rgba(255, 255, 255, 0.2);
+ border-right: 1.1em solid rgba(255, 255, 255, 0.2);
+ border-bottom: 1.1em solid rgba(255, 255, 255, 0.2);
+ border-left: 1.1em solid #febc59;
+ -webkit-transform: translateZ(0);
+ -ms-transform: translateZ(0);
+ transform: translateZ(0);
+ -webkit-animation: load8 1.1s infinite linear;
+ animation: load8 1.1s infinite linear;
+}
+@keyframes load8 {
+ 0% {
+ -webkit-transform: rotate(0deg);
+ transform: rotate(0deg);
+ }
+ 100% {
+ -webkit-transform: rotate(360deg);
+ transform: rotate(360deg);
+ }
+}
+.list_box {
+ height: 70vh;
+ overflow-y: auto;
+ width: auto;
+}
+@media only screen and (max-width: 600px) {
+ .form_wrapper {
+ width: 90%;
+ top: 45%;
+ }
+}
From d25a79508b5e6236f611cddcf6bf22d45fb17f4e Mon Sep 17 00:00:00 2001
From: Pranav Nathe <93403830+pranavnathe@users.noreply.github.com>
Date: Tue, 24 Dec 2024 21:39:23 +0530
Subject: [PATCH 068/133] fix: #2508 Refactor CSS files in
src/screens/Leaderboard (#2776)
* fix: Refactor CSS files in src/screens/Leaderboard #2508
* fix: resolve syntax error caused by missing closing brace
---
src/screens/Leaderboard/Leaderboard.tsx | 4 ++--
src/style/app.module.css | 21 +++++++++++++++++++++
2 files changed, 23 insertions(+), 2 deletions(-)
diff --git a/src/screens/Leaderboard/Leaderboard.tsx b/src/screens/Leaderboard/Leaderboard.tsx
index c5ad7a2efe..e0ea513e9c 100644
--- a/src/screens/Leaderboard/Leaderboard.tsx
+++ b/src/screens/Leaderboard/Leaderboard.tsx
@@ -14,7 +14,7 @@ import silver from 'assets/images/silver.png';
import bronze from 'assets/images/bronze.png';
import type { InterfaceVolunteerRank } from 'utils/interfaces';
-import styles from '../OrganizationActionItems/OrganizationActionItems.module.css';
+import styles from '../../style/app.module.css';
import Loader from 'components/Loader/Loader';
import {
DataGrid,
@@ -200,7 +200,7 @@ function leaderboard(): JSX.Element {
diff --git a/src/style/app.module.css b/src/style/app.module.css
index af2469c6e8..02a014ea83 100644
--- a/src/style/app.module.css
+++ b/src/style/app.module.css
@@ -12,6 +12,7 @@
--search-button-bg: #a8c7fa;
--search-button-border: #555555;
--table-image-size: 50px;
+ --table-image-small-size: 25px;
--bs-primary: #0056b3;
--bs-white: #fff;
--table-head-bg: var(--bs-primary, blue);
@@ -1594,6 +1595,26 @@ form > input {
}
}
+/* * Refortoring css for Leaderboard */
+
+.TableImageSmall {
+ object-fit: cover;
+ width: var(--table-image-small-size);
+ height: var(--table-image-small-size);
+ border-radius: 100%;
+}
+
+.avatarContainer {
+ width: 28px;
+ height: 26px;
+}
+
+.imageContainer {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ margin-right: 0.5rem;
+}
/* CSS Refactor for OrgPost */
.btnsContainerOrgPost {
From dbe3387aac68b19104cc4cfa8bdd048095ac91ac Mon Sep 17 00:00:00 2001
From: Gurram Karthik <167804249+gurramkarthiknetha@users.noreply.github.com>
Date: Tue, 24 Dec 2024 21:40:48 +0530
Subject: [PATCH 069/133] fixed-2750 (#2779)
---
...est.ts => setupTalawaWebSocketUrl.spec.ts} | 23 +++++++++++--------
1 file changed, 14 insertions(+), 9 deletions(-)
rename src/setup/askForTalawaApiUrl/{setupTalawaWebSocketUrl.test.ts => setupTalawaWebSocketUrl.spec.ts} (69%)
diff --git a/src/setup/askForTalawaApiUrl/setupTalawaWebSocketUrl.test.ts b/src/setup/askForTalawaApiUrl/setupTalawaWebSocketUrl.spec.ts
similarity index 69%
rename from src/setup/askForTalawaApiUrl/setupTalawaWebSocketUrl.test.ts
rename to src/setup/askForTalawaApiUrl/setupTalawaWebSocketUrl.spec.ts
index 3fa612bd25..926444d8a6 100644
--- a/src/setup/askForTalawaApiUrl/setupTalawaWebSocketUrl.test.ts
+++ b/src/setup/askForTalawaApiUrl/setupTalawaWebSocketUrl.spec.ts
@@ -1,15 +1,20 @@
import fs from 'fs';
+import { vi } from 'vitest';
import inquirer from 'inquirer';
import { askForTalawaApiUrl } from './askForTalawaApiUrl';
-jest.mock('fs');
-jest.mock('inquirer', () => ({
- prompt: jest.fn(),
-}));
+vi.mock('fs');
+vi.mock('inquirer', async () => {
+ const actual = await vi.importActual('inquirer');
+ return {
+ ...actual,
+ prompt: vi.fn(),
+ };
+});
describe('WebSocket URL Configuration', () => {
beforeEach(() => {
- jest.resetAllMocks();
+ vi.clearAllMocks();
});
test('should convert http URL to ws WebSocket URL', async () => {
@@ -27,12 +32,12 @@ describe('WebSocket URL Configuration', () => {
});
test('should retain default WebSocket URL if no new endpoint is provided', async () => {
- jest
- .spyOn(inquirer, 'prompt')
- .mockResolvedValueOnce({ endpoint: 'http://localhost:4000/graphql/' });
+ vi.spyOn(inquirer, 'prompt').mockResolvedValueOnce({
+ endpoint: 'http://localhost:4000/graphql/',
+ });
await askForTalawaApiUrl();
- const writeFileSyncSpy = jest.spyOn(fs, 'writeFileSync');
+ const writeFileSyncSpy = vi.spyOn(fs, 'writeFileSync');
expect(writeFileSyncSpy).not.toHaveBeenCalled();
});
});
From 9e5d64e14a37dd4354b709e9439f9936e88aa6e1 Mon Sep 17 00:00:00 2001
From: khushi santosh patil
<143253539+khushipatil1523@users.noreply.github.com>
Date: Tue, 24 Dec 2024 22:17:46 +0530
Subject: [PATCH 070/133] Refactor/jest vitest 2486 (#2782)
* convert from jest to vitest
* changes done
* changes done
* changes done
---
...ments.test.tsx => Advertisements.spec.tsx} | 41 +++++++++++--------
1 file changed, 24 insertions(+), 17 deletions(-)
rename src/components/Advertisements/{Advertisements.test.tsx => Advertisements.spec.tsx} (96%)
diff --git a/src/components/Advertisements/Advertisements.test.tsx b/src/components/Advertisements/Advertisements.spec.tsx
similarity index 96%
rename from src/components/Advertisements/Advertisements.test.tsx
rename to src/components/Advertisements/Advertisements.spec.tsx
index 88bbb1255c..1e2d92b392 100644
--- a/src/components/Advertisements/Advertisements.test.tsx
+++ b/src/components/Advertisements/Advertisements.spec.tsx
@@ -1,4 +1,6 @@
import React, { act } from 'react';
+import { describe, test, expect, vi } from 'vitest';
+
import {
ApolloClient,
ApolloLink,
@@ -7,25 +9,28 @@ import {
InMemoryCache,
} from '@apollo/client';
import { MockedProvider } from '@apollo/client/testing';
+
import { fireEvent, render, screen } from '@testing-library/react';
-import 'jest-location-mock';
import type { DocumentNode, NormalizedCacheObject } from '@apollo/client';
import userEvent from '@testing-library/user-event';
import { BACKEND_URL } from 'Constant/constant';
-import { ADD_ADVERTISEMENT_MUTATION } from 'GraphQl/Mutations/mutations';
+
+import { ADD_ADVERTISEMENT_MUTATION } from '../../GraphQl/Mutations/mutations';
import {
ORGANIZATIONS_LIST,
ORGANIZATION_ADVERTISEMENT_LIST,
PLUGIN_GET,
-} from 'GraphQl/Queries/Queries';
+} from '../../GraphQl/Queries/Queries';
+
import { I18nextProvider } from 'react-i18next';
+
import { Provider } from 'react-redux';
import { BrowserRouter } from 'react-router-dom';
import { ToastContainer } from 'react-toastify';
-import { store } from 'state/store';
-import i18nForTest from 'utils/i18nForTest';
-import useLocalStorage from 'utils/useLocalstorage';
+import { store } from '../../state/store';
+import i18nForTest from '../../utils/i18nForTest';
+import useLocalStorage from '../../utils/useLocalstorage';
import Advertisement from './Advertisements';
const { getItem } = useLocalStorage();
@@ -50,18 +55,22 @@ const client: ApolloClient = new ApolloClient({
link: ApolloLink.from([httpLink]),
});
-jest.mock('components/AddOn/support/services/Plugin.helper', () => ({
+vi.mock('components/AddOn/support/services/Plugin.helper', () => ({
__esModule: true,
- default: jest.fn().mockImplementation(() => ({
- fetchInstalled: jest.fn().mockResolvedValue([]),
- fetchStore: jest.fn().mockResolvedValue([]),
+ default: vi.fn().mockImplementation(() => ({
+ fetchInstalled: vi.fn().mockResolvedValue([]),
+ fetchStore: vi.fn().mockResolvedValue([]),
})),
}));
let mockID: string | undefined = '1';
-jest.mock('react-router-dom', () => ({
- ...jest.requireActual('react-router-dom'),
- useParams: () => ({ orgId: mockID }),
-}));
+
+vi.mock('react-router-dom', async () => {
+ const actual = await vi.importActual('react-router-dom');
+ return {
+ ...actual,
+ useParams: () => ({ orgId: mockID }),
+ };
+});
const today = new Date();
const tomorrow = today;
@@ -466,18 +475,16 @@ describe('Testing Advertisement Component', () => {
/\b(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)\s+(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s+(\d{1,2})\s+(\d{4})\b/,
);
let dateObject = new Date();
-
if (dateMatch) {
const monthName = dateMatch[1];
const day = parseInt(dateMatch[2], 10);
const year = parseInt(dateMatch[3], 10);
-
const monthIndex =
'JanFebMarAprMayJunJulAugSepOctNovDec'.indexOf(monthName) / 3;
dateObject = new Date(year, monthIndex, day);
}
-
+ console.log(dateObject);
expect(dateObject.getTime()).toBeLessThan(new Date().getTime());
});
From 9848bae8df7c810aa9481b2b076a353bbe8088b7 Mon Sep 17 00:00:00 2001
From: Shiva <148421597+shivasankaran18@users.noreply.github.com>
Date: Tue, 24 Dec 2024 22:28:05 +0530
Subject: [PATCH 071/133] refactor:vitest to CheckIn/TableRow (#2785)
---
.../{TableRow.test.tsx => TableRow.spec.tsx} | 25 +++++++++++--------
1 file changed, 15 insertions(+), 10 deletions(-)
rename src/components/CheckIn/{TableRow.test.tsx => TableRow.spec.tsx} (91%)
diff --git a/src/components/CheckIn/TableRow.test.tsx b/src/components/CheckIn/TableRow.spec.tsx
similarity index 91%
rename from src/components/CheckIn/TableRow.test.tsx
rename to src/components/CheckIn/TableRow.spec.tsx
index 1a08f40a3d..4e11302fe7 100644
--- a/src/components/CheckIn/TableRow.test.tsx
+++ b/src/components/CheckIn/TableRow.spec.tsx
@@ -11,10 +11,15 @@ import { LocalizationProvider } from '@mui/x-date-pickers';
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
import { MockedProvider } from '@apollo/react-testing';
import { checkInMutationSuccess, checkInMutationUnsuccess } from './mocks';
+import { vi } from 'vitest';
+
+/**
+ * Test suite for the `TableRow` component, focusing on the CheckIn table functionality.
+ */
describe('Testing Table Row for CheckIn Table', () => {
beforeEach(() => {
- jest.clearAllMocks();
+ vi.clearAllMocks();
});
test('If the user is not checked in, button to check in should be displayed, and the user should be able to check in successfully', async () => {
@@ -26,7 +31,7 @@ describe('Testing Table Row for CheckIn Table', () => {
checkIn: null,
eventId: `event123`,
},
- refetch: jest.fn(),
+ refetch: vi.fn(),
};
const { findByText } = render(
@@ -63,7 +68,7 @@ describe('Testing Table Row for CheckIn Table', () => {
},
eventId: 'event123',
},
- refetch: jest.fn(),
+ refetch: vi.fn(),
};
const { findByText } = render(
@@ -81,8 +86,8 @@ describe('Testing Table Row for CheckIn Table', () => {
,
);
- global.URL.createObjectURL = jest.fn(() => 'mockURL');
- global.window.open = jest.fn();
+ global.URL.createObjectURL = vi.fn(() => 'mockURL');
+ global.window.open = vi.fn();
expect(await findByText('Checked In')).toBeInTheDocument();
expect(await findByText('Download Tag')).toBeInTheDocument();
@@ -93,7 +98,7 @@ describe('Testing Table Row for CheckIn Table', () => {
expect(await findByText('PDF generated successfully!')).toBeInTheDocument();
// Cleanup mocks
- jest.clearAllMocks();
+ vi.clearAllMocks();
});
test('Upon failing of check in mutation, the appropriate error message should be shown', async () => {
@@ -105,7 +110,7 @@ describe('Testing Table Row for CheckIn Table', () => {
checkIn: null,
eventId: `event123`,
},
- refetch: jest.fn(),
+ refetch: vi.fn(),
};
const { findByText } = render(
@@ -143,7 +148,7 @@ describe('Testing Table Row for CheckIn Table', () => {
},
eventId: `event123`,
},
- refetch: jest.fn(),
+ refetch: vi.fn(),
};
const { findByText } = render(
@@ -162,8 +167,8 @@ describe('Testing Table Row for CheckIn Table', () => {
);
// Mocking the PDF generation function to throw an error
- global.URL.createObjectURL = jest.fn(() => 'mockURL');
- global.window.open = jest.fn();
+ global.URL.createObjectURL = vi.fn(() => 'mockURL');
+ global.window.open = vi.fn();
fireEvent.click(await findByText('Download Tag'));
From aff65c9875b19865198dc4c4657a056d5e938d28 Mon Sep 17 00:00:00 2001
From: Shiva <148421597+shivasankaran18@users.noreply.github.com>
Date: Tue, 24 Dec 2024 22:34:49 +0530
Subject: [PATCH 072/133] refactor:vitest to UserPortal/Organizations (#2783)
* refactor:vitest to UserPortal/Organizations
* fix:coderabbit sugg
---
...ations.test.tsx => Organizations.spec.tsx} | 32 +++++++++++++++++++
1 file changed, 32 insertions(+)
rename src/screens/UserPortal/Organizations/{Organizations.test.tsx => Organizations.spec.tsx} (95%)
diff --git a/src/screens/UserPortal/Organizations/Organizations.test.tsx b/src/screens/UserPortal/Organizations/Organizations.spec.tsx
similarity index 95%
rename from src/screens/UserPortal/Organizations/Organizations.test.tsx
rename to src/screens/UserPortal/Organizations/Organizations.spec.tsx
index f8a6fc06a5..0aafba3b55 100644
--- a/src/screens/UserPortal/Organizations/Organizations.test.tsx
+++ b/src/screens/UserPortal/Organizations/Organizations.spec.tsx
@@ -18,6 +18,10 @@ import Organizations from './Organizations';
import React, { act } from 'react';
const { getItem } = useLocalStorage();
+/**
+ * Mock data for GraphQL queries.
+ */
+
const MOCKS = [
{
request: {
@@ -317,6 +321,10 @@ const MOCKS = [
},
];
+/**
+ * Custom Mock Link for handling static GraphQL mocks.
+ */
+
const link = new StaticMockLink(MOCKS, true);
async function wait(ms = 100): Promise {
@@ -333,6 +341,9 @@ const resizeWindow = (width: number): void => {
};
describe('Testing Organizations Screen [User Portal]', () => {
+ /**
+ * Test to ensure the screen is rendered properly.
+ */
test('Screen should be rendered properly', async () => {
render(
@@ -347,8 +358,13 @@ describe('Testing Organizations Screen [User Portal]', () => {
);
await wait();
+ expect(screen.getByText('My Organizations')).toBeInTheDocument();
});
+ /**
+ * Test to check if the search functionality works as expected.
+ */
+
test('Search works properly', async () => {
render(
@@ -374,6 +390,10 @@ describe('Testing Organizations Screen [User Portal]', () => {
await wait();
});
+ /**
+ * Test to verify the mode change to joined organizations.
+ */
+
test('Mode is changed to joined organizations', async () => {
render(
@@ -397,6 +417,10 @@ describe('Testing Organizations Screen [User Portal]', () => {
expect(screen.queryAllByText('joinedOrganization')).not.toBe([]);
});
+ /**
+ * Test case to ensure the mode can be changed to display created organizations.
+ */
+
test('Mode is changed to created organizations', async () => {
render(
@@ -420,6 +444,10 @@ describe('Testing Organizations Screen [User Portal]', () => {
expect(screen.queryAllByText('createdOrganization')).not.toBe([]);
});
+ /**
+ * Test case to check if the "Join Now" button renders correctly on the page.
+ */
+
test('Join Now button render correctly', async () => {
render(
@@ -463,6 +491,10 @@ describe('Testing Organizations Screen [User Portal]', () => {
expect(screen.queryAllByText('createdOrganization')).not.toBe([]);
});
+ /**
+ * Test case to ensure the sidebar is functional, including opening and closing actions.
+ */
+
test('Testing Sidebar', async () => {
render(
From 45d18b6540876a0955aa3c086132c0aec85c8004 Mon Sep 17 00:00:00 2001
From: Mehul Aggarwal <88583647+AceHunterr@users.noreply.github.com>
Date: Wed, 25 Dec 2024 00:07:57 +0530
Subject: [PATCH 073/133] Refactored src/utils/convertToBase64.test.ts from
Jest to Vitest (#2802)
---
.../{convertToBase64.test.ts => convertToBase64.spec.ts} | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
rename src/utils/{convertToBase64.test.ts => convertToBase64.spec.ts} (90%)
diff --git a/src/utils/convertToBase64.test.ts b/src/utils/convertToBase64.spec.ts
similarity index 90%
rename from src/utils/convertToBase64.test.ts
rename to src/utils/convertToBase64.spec.ts
index 51198ccc29..85b97ac31a 100644
--- a/src/utils/convertToBase64.test.ts
+++ b/src/utils/convertToBase64.spec.ts
@@ -1,3 +1,4 @@
+import { describe, it, expect, vi } from 'vitest';
import convertToBase64 from './convertToBase64';
describe('convertToBase64', () => {
@@ -16,7 +17,7 @@ describe('convertToBase64', () => {
it('should handle errors thrown by FileReader', async () => {
// Arrange
const file = new File(['hello'], 'hello.txt', { type: 'text/plain' });
- const mockFileReader = jest
+ const mockFileReader = vi
.spyOn(global, 'FileReader')
.mockImplementationOnce(() => {
throw new Error('Test error');
@@ -29,5 +30,6 @@ describe('convertToBase64', () => {
expect(mockFileReader).toHaveBeenCalledTimes(1);
expect(mockFileReader).toHaveBeenCalledWith();
expect(result).toBe('');
+ mockFileReader.mockRestore();
});
});
From 0b384757e8d11641b55fa7cf7d48a75a1c2fbfe7 Mon Sep 17 00:00:00 2001
From: Rahul Chougule <87270395+rahulch07@users.noreply.github.com>
Date: Wed, 25 Dec 2024 03:41:19 +0530
Subject: [PATCH 074/133] refactored css (#2841)
Co-authored-by: Rahul Chougule
---
.../Dashboard/EventDashboard.module.css | 101 ------
.../Dashboard/EventDashboard.tsx | 2 +-
.../EventAgendaItems.module.css | 22 --
.../EventAgendaItems/EventAgendaItems.tsx | 2 +-
.../EventAttendance/EventAttendance.tsx | 2 +-
.../EventsAttendance.module.css | 35 ---
.../ItemDeleteModal.tsx | 2 +-
.../OrganizationActionItems/ItemViewModal.tsx | 2 +-
.../OrganizationActionItems.module.css | 291 ------------------
.../OrganizationActionItems.tsx | 4 +-
.../UserPortal/Volunteer/Actions/Actions.tsx | 2 +-
src/style/app.module.css | 153 +++++++++
12 files changed, 161 insertions(+), 457 deletions(-)
delete mode 100644 src/components/EventManagement/Dashboard/EventDashboard.module.css
delete mode 100644 src/components/EventManagement/EventAgendaItems/EventAgendaItems.module.css
delete mode 100644 src/components/EventManagement/EventAttendance/EventsAttendance.module.css
delete mode 100644 src/screens/OrganizationActionItems/OrganizationActionItems.module.css
diff --git a/src/components/EventManagement/Dashboard/EventDashboard.module.css b/src/components/EventManagement/Dashboard/EventDashboard.module.css
deleted file mode 100644
index 37336002bb..0000000000
--- a/src/components/EventManagement/Dashboard/EventDashboard.module.css
+++ /dev/null
@@ -1,101 +0,0 @@
-.eventContainer {
- display: flex;
- align-items: start;
-}
-
-.eventDetailsBox {
- position: relative;
- box-sizing: border-box;
- background: #ffffff;
- width: 66%;
- padding: 0.3rem;
- box-shadow: 0 3px 8px rgba(0, 0, 0, 0.1);
- border-radius: 20px;
- margin-bottom: 0;
- margin-top: 20px;
-}
-.ctacards {
- padding: 20px;
- width: 100%;
- display: flex;
- background-color: #ffffff;
- margin: 0 4px;
- justify-content: space-between;
- box-shadow: 0 3px 8px rgba(0, 0, 0, 0.1);
- align-items: center;
- border-radius: 20px;
-}
-.ctacards span {
- color: rgb(181, 181, 181);
- font-size: small;
-}
-/* .eventDetailsBox::before {
- content: '';
- position: absolute;
- top: 0;
- height: 100%;
- width: 6px;
- background-color: #31bb6b;
- border-radius: 20px;
-} */
-
-.time {
- display: flex;
- justify-content: space-between;
- padding: 15px;
- padding-bottom: 0px;
- width: 33%;
-
- box-sizing: border-box;
- background: #ffffff;
- box-shadow: 0 3px 8px rgba(0, 0, 0, 0.1);
- border-radius: 20px;
- margin-bottom: 0;
- margin-top: 20px;
- margin-left: 10px;
-}
-
-.startTime,
-.endTime {
- display: flex;
- font-size: 20px;
-}
-
-.to {
- padding-right: 10px;
-}
-
-.startDate,
-.endDate {
- color: #808080;
- font-size: 14px;
-}
-
-.titlename {
- font-weight: 600;
- font-size: 25px;
- padding: 15px;
- padding-bottom: 0px;
- width: 50%;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-
-.description {
- color: #737373;
- font-weight: 300;
- font-size: 14px;
- word-wrap: break-word;
- padding: 15px;
- padding-bottom: 0px;
-}
-
-.toporgloc {
- font-size: 16px;
- padding: 0.5rem;
-}
-
-.toporgloc span {
- color: #737373;
-}
diff --git a/src/components/EventManagement/Dashboard/EventDashboard.tsx b/src/components/EventManagement/Dashboard/EventDashboard.tsx
index d3552702c6..1995a640c9 100644
--- a/src/components/EventManagement/Dashboard/EventDashboard.tsx
+++ b/src/components/EventManagement/Dashboard/EventDashboard.tsx
@@ -1,6 +1,6 @@
import React, { useState } from 'react';
import { Col, Row } from 'react-bootstrap';
-import styles from './EventDashboard.module.css';
+import styles from '../../../style/app.module.css';
import { useTranslation } from 'react-i18next';
import { EVENT_DETAILS } from 'GraphQl/Queries/Queries';
import { useQuery } from '@apollo/client';
diff --git a/src/components/EventManagement/EventAgendaItems/EventAgendaItems.module.css b/src/components/EventManagement/EventAgendaItems/EventAgendaItems.module.css
deleted file mode 100644
index 9d1c32b766..0000000000
--- a/src/components/EventManagement/EventAgendaItems/EventAgendaItems.module.css
+++ /dev/null
@@ -1,22 +0,0 @@
-.eventAgendaItemContainer h2 {
- margin: 0.6rem 0;
-}
-
-.btnsContainer {
- display: flex;
- gap: 10px;
-}
-
-@media (max-width: 768px) {
- .btnsContainer {
- margin-bottom: 0;
- display: flex;
- flex-direction: column;
- }
-
- .createAgendaItemButton {
- position: absolute;
- top: 1rem;
- right: 2rem;
- }
-}
diff --git a/src/components/EventManagement/EventAgendaItems/EventAgendaItems.tsx b/src/components/EventManagement/EventAgendaItems/EventAgendaItems.tsx
index b49ade4626..9b758a555a 100644
--- a/src/components/EventManagement/EventAgendaItems/EventAgendaItems.tsx
+++ b/src/components/EventManagement/EventAgendaItems/EventAgendaItems.tsx
@@ -20,7 +20,7 @@ import type {
import AgendaItemsContainer from 'components/AgendaItems/AgendaItemsContainer';
import AgendaItemsCreateModal from 'components/AgendaItems/AgendaItemsCreateModal';
-import styles from './EventAgendaItems.module.css';
+import styles from '../../../style/app.module.css';
import Loader from 'components/Loader/Loader';
/**
diff --git a/src/components/EventManagement/EventAttendance/EventAttendance.tsx b/src/components/EventManagement/EventAttendance/EventAttendance.tsx
index 17f063f6b5..06b047a973 100644
--- a/src/components/EventManagement/EventAttendance/EventAttendance.tsx
+++ b/src/components/EventManagement/EventAttendance/EventAttendance.tsx
@@ -16,7 +16,7 @@ import {
Table,
FormControl,
} from 'react-bootstrap';
-import styles from './EventsAttendance.module.css';
+import styles from '../../../style/app.module.css';
import { useLazyQuery } from '@apollo/client';
import { EVENT_ATTENDEES } from 'GraphQl/Queries/Queries';
import { useParams, Link } from 'react-router-dom';
diff --git a/src/components/EventManagement/EventAttendance/EventsAttendance.module.css b/src/components/EventManagement/EventAttendance/EventsAttendance.module.css
deleted file mode 100644
index 2ee236a4da..0000000000
--- a/src/components/EventManagement/EventAttendance/EventsAttendance.module.css
+++ /dev/null
@@ -1,35 +0,0 @@
-.input {
- display: flex;
- width: 100%;
- position: relative;
-}
-.customcell {
- background-color: #31bb6b !important;
- color: white !important;
- font-size: medium !important;
- font-weight: 500 !important;
- padding-top: 10px !important;
- padding-bottom: 10px !important;
-}
-
-.eventsAttended,
-.membername {
- color: blue;
-}
-.actionBtn {
- /* color:#39a440 !important; */
- background-color: #ffffff !important;
-}
-.actionBtn:hover,
-.actionBtn:focus,
-.actionBtn:active {
- color: #39a440 !important;
-}
-
-.table-body > .table-row {
- background-color: #fff !important;
-}
-
-.table-body > .table-row:nth-child(2n) {
- background: #afffe8 !important;
-}
diff --git a/src/screens/OrganizationActionItems/ItemDeleteModal.tsx b/src/screens/OrganizationActionItems/ItemDeleteModal.tsx
index 2526486993..499601e4fd 100644
--- a/src/screens/OrganizationActionItems/ItemDeleteModal.tsx
+++ b/src/screens/OrganizationActionItems/ItemDeleteModal.tsx
@@ -1,6 +1,6 @@
import React from 'react';
import { Modal, Button } from 'react-bootstrap';
-import styles from './OrganizationActionItems.module.css';
+import styles from '../../style/app.module.css';
import { useMutation } from '@apollo/client';
import { DELETE_ACTION_ITEM_MUTATION } from 'GraphQl/Mutations/ActionItemMutations';
import { toast } from 'react-toastify';
diff --git a/src/screens/OrganizationActionItems/ItemViewModal.tsx b/src/screens/OrganizationActionItems/ItemViewModal.tsx
index 5a78ac8a91..98f2f6fd7f 100644
--- a/src/screens/OrganizationActionItems/ItemViewModal.tsx
+++ b/src/screens/OrganizationActionItems/ItemViewModal.tsx
@@ -4,7 +4,7 @@ import dayjs from 'dayjs';
import type { FC } from 'react';
import { Button, Form, Modal } from 'react-bootstrap';
import type { InterfaceActionItemInfo } from 'utils/interfaces';
-import styles from './OrganizationActionItems.module.css';
+import styles from '../../style/app.module.css';
import { useTranslation } from 'react-i18next';
import { FormControl, TextField } from '@mui/material';
import { TaskAlt, HistoryToggleOff } from '@mui/icons-material';
diff --git a/src/screens/OrganizationActionItems/OrganizationActionItems.module.css b/src/screens/OrganizationActionItems/OrganizationActionItems.module.css
deleted file mode 100644
index ac86e19f3f..0000000000
--- a/src/screens/OrganizationActionItems/OrganizationActionItems.module.css
+++ /dev/null
@@ -1,291 +0,0 @@
-actionItemsContainer {
- height: 90vh;
-}
-
-.actionItemModal {
- max-width: 80vw;
- margin-top: 2vh;
- margin-left: 13vw;
-}
-
-.datediv {
- display: flex;
- flex-direction: row;
-}
-
-.datebox {
- width: 90%;
- border-radius: 7px;
- outline: none;
- box-shadow: none;
- padding-top: 2px;
- padding-bottom: 2px;
- padding-right: 5px;
- padding-left: 5px;
- margin-right: 5px;
- margin-left: 5px;
-}
-
-.dropdownToggle {
- margin-bottom: 0;
- display: flex;
-}
-
-.dropdownModalToggle {
- width: 50%;
-}
-
-.errorIcon {
- transform: scale(1.5);
- color: var(--bs-danger);
- margin-bottom: 1rem;
-}
-
-.greenregbtn {
- margin: 1rem 0 0;
- margin-top: 15px;
- border: 1px solid var(--bs-gray-300);
- box-shadow: 0 2px 2px var(--bs-gray-300);
- padding: 10px 10px;
- border-radius: 5px;
- background-color: var(--bs-primary);
- width: 100%;
- font-size: 16px;
- color: var(--bs-white);
- outline: none;
- font-weight: 600;
- cursor: pointer;
- transition:
- transform 0.2s,
- box-shadow 0.2s;
- width: 100%;
-}
-
-hr {
- border: none;
- height: 1px;
- background-color: var(--bs-gray-500);
- margin: 1rem;
-}
-
-.iconContainer {
- display: flex;
- justify-content: flex-end;
-}
-.icon {
- margin: 1px;
-}
-
-.message {
- margin-top: 25%;
- display: flex;
- justify-content: center;
- align-items: center;
- flex-direction: column;
-}
-
-.preview {
- display: flex;
- flex-direction: row;
- font-weight: 900;
- font-size: 16px;
- color: rgb(80, 80, 80);
-}
-
-.removeFilterIcon {
- cursor: pointer;
-}
-
-.searchForm {
- display: inline;
-}
-
-.view {
- margin-left: 2%;
- font-weight: 600;
- font-size: 16px;
- color: var(--bs-gray-600);
-}
-
-/* header (search, filter, dropdown) */
-.btnsContainer {
- display: flex;
- margin: 0.5rem 0 1.5rem 0;
-}
-
-.btnsContainer .input {
- flex: 1;
- min-width: 18rem;
- position: relative;
-}
-
-.btnsContainer input {
- outline: 1px solid var(--bs-gray-400);
-}
-
-.btnsContainer .input button {
- width: 52px;
-}
-
-.noOutline input {
- outline: none;
-}
-
-.noOutline input:disabled {
- -webkit-text-fill-color: black !important;
-}
-
-.noOutline textarea:disabled {
- -webkit-text-fill-color: black !important;
-}
-
-.inputField {
- margin-top: 10px;
- margin-bottom: 10px;
- background-color: white;
- box-shadow: 0 1px 1px #31bb6b;
-}
-
-.inputField > button {
- padding-top: 10px;
- padding-bottom: 10px;
-}
-
-.dropdown {
- background-color: white;
- border: 1px solid #31bb6b;
- position: relative;
- display: inline-block;
- color: #31bb6b;
-}
-
-/* Action Items Data Grid */
-.rowBackground {
- background-color: var(--bs-white);
- max-height: 120px;
-}
-
-.tableHeader {
- background-color: var(--bs-primary);
- color: var(--bs-white);
- font-size: 1rem;
-}
-
-.chipIcon {
- height: 0.9rem !important;
-}
-
-.chip {
- height: 1.5rem !important;
-}
-
-.active {
- background-color: #31bb6a50 !important;
-}
-
-.pending {
- background-color: #ffd76950 !important;
- color: #bb952bd0 !important;
- border-color: #bb952bd0 !important;
-}
-
-/* Modals */
-.itemModal {
- max-width: 80vw;
- margin-top: 2vh;
- margin-left: 13vw;
-}
-
-.titlemodal {
- color: #707070;
- font-weight: 600;
- font-size: 32px;
- width: 65%;
- margin-bottom: 0px;
-}
-
-.modalCloseBtn {
- width: 40px;
- height: 40px;
- padding: 1rem;
- display: flex;
- justify-content: center;
- align-items: center;
-}
-
-.imageContainer {
- display: flex;
- align-items: center;
- justify-content: center;
- margin-right: 0.5rem;
-}
-
-.TableImage {
- object-fit: cover;
- width: 25px !important;
- height: 25px !important;
- border-radius: 100% !important;
-}
-
-.avatarContainer {
- width: 28px;
- height: 26px;
-}
-
-/* Toggle Btn */
-.toggleGroup {
- width: 50%;
- min-width: 20rem;
- margin: 0.5rem 0rem;
-}
-
-.toggleBtn {
- padding: 0rem;
- height: 2rem;
- display: flex;
- justify-content: center;
- align-items: center;
-}
-
-.toggleBtn:hover {
- color: #31bb6b !important;
-}
-
-input[type='radio']:checked + label {
- background-color: #31bb6a50 !important;
-}
-
-input[type='radio']:checked + label:hover {
- color: black !important;
-} /* Toggle Btn */
-.toggleGroup {
- width: 50%;
- min-width: 20rem;
- margin: 0.5rem 0rem;
-}
-
-.toggleBtn {
- padding: 0rem;
- height: 2rem;
- display: flex;
- justify-content: center;
- align-items: center;
-}
-
-.toggleBtn:hover {
- color: #31bb6b !important;
-}
-
-input[type='radio']:checked + label {
- background-color: #31bb6a50 !important;
-}
-
-input[type='radio']:checked + label:hover {
- color: black !important;
-}
-
-.rankings {
- aspect-ratio: 1;
- border-radius: 50%;
- width: 50px;
-}
diff --git a/src/screens/OrganizationActionItems/OrganizationActionItems.tsx b/src/screens/OrganizationActionItems/OrganizationActionItems.tsx
index 3fde2911b1..6061ba7e7d 100644
--- a/src/screens/OrganizationActionItems/OrganizationActionItems.tsx
+++ b/src/screens/OrganizationActionItems/OrganizationActionItems.tsx
@@ -366,7 +366,7 @@ function organizationActionItems(): JSX.Element {
return (
{/* Header with search, filter and Create Button */}
-
+
-
+
.table-row {
+ background-color: #fff !important;
+}
+
+.table-body > .table-row:nth-child(2n) {
+ background: #afffe8 !important;
+}
+
@media (max-width: 1024px) {
.pageNotFound h1.head {
font-size: 200px;
@@ -1108,10 +1249,18 @@ hr {
color: var(--brand-primary) !important;
}
+.toggleBtn:hover {
+ color: #31bb6b !important;
+}
+
input[type='radio']:checked + label {
background-color: var(--brand-primary-light) !important;
}
+input[type='radio']:checked + label:hover {
+ color: black !important;
+}
+
.dropdownToggle {
margin-bottom: 0;
display: flex;
@@ -1193,6 +1342,10 @@ input[type='radio']:checked + label {
width: 52px;
}
+.noOutline input {
+ outline: none;
+}
+
.noOutline input:disabled {
-webkit-text-fill-color: black !important;
}
From c2176766ac3b3bf32c2c03dff52d975e41875599 Mon Sep 17 00:00:00 2001
From: Devyanshu Negi <100033611+DevyanshuNegi@users.noreply.github.com>
Date: Wed, 25 Dec 2024 03:42:37 +0530
Subject: [PATCH 075/133] Refactor: test from jest to vitest (#2688)
* refactored code from jest to vitest
* refactored from jest to vitest
* changes suggested by code rabbit
* changes suggested by @palisadoes
---
.../{Groups.test.tsx => Groups.spec.tsx} | 73 +++++++++++++++++--
1 file changed, 66 insertions(+), 7 deletions(-)
rename src/screens/UserPortal/Volunteer/Groups/{Groups.test.tsx => Groups.spec.tsx} (76%)
diff --git a/src/screens/UserPortal/Volunteer/Groups/Groups.test.tsx b/src/screens/UserPortal/Volunteer/Groups/Groups.spec.tsx
similarity index 76%
rename from src/screens/UserPortal/Volunteer/Groups/Groups.test.tsx
rename to src/screens/UserPortal/Volunteer/Groups/Groups.spec.tsx
index bc0a4993b9..b9bf6c29c0 100644
--- a/src/screens/UserPortal/Volunteer/Groups/Groups.test.tsx
+++ b/src/screens/UserPortal/Volunteer/Groups/Groups.spec.tsx
@@ -3,7 +3,13 @@ import { MockedProvider } from '@apollo/react-testing';
import { LocalizationProvider } from '@mui/x-date-pickers';
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
import type { RenderResult } from '@testing-library/react';
-import { fireEvent, render, screen, waitFor } from '@testing-library/react';
+import {
+ cleanup,
+ fireEvent,
+ render,
+ screen,
+ waitFor,
+} from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { I18nextProvider } from 'react-i18next';
import { Provider } from 'react-redux';
@@ -15,6 +21,7 @@ import Groups from './Groups';
import type { ApolloLink } from '@apollo/client';
import { MOCKS, EMPTY_MOCKS, ERROR_MOCKS } from './Groups.mocks';
import useLocalStorage from 'utils/useLocalstorage';
+import { vi } from 'vitest';
const { setItem } = useLocalStorage();
@@ -31,6 +38,13 @@ const t = {
...JSON.parse(JSON.stringify(i18n.getDataByLanguage('en')?.errors ?? {})),
};
+/**
+ * Introduces a delay for the specified duration.
+ * This is primarily used to simulate debounce behavior in tests.
+ * @param ms - The duration to delay in milliseconds. Defaults to 300ms.
+ * @returns A Promise that resolves after the specified duration.
+ */
+
const debounceWait = async (ms = 300): Promise => {
await act(() => {
return new Promise((resolve) => {
@@ -39,6 +53,11 @@ const debounceWait = async (ms = 300): Promise => {
});
};
+/**
+ * Renders the Groups component using a specific Apollo link.
+ * @param link - The ApolloLink instance to use for mocking GraphQL requests.
+ * @returns The rendered component wrapped in test utilities.
+ */
const renderGroups = (link: ApolloLink): RenderResult => {
return render(
@@ -61,22 +80,33 @@ const renderGroups = (link: ApolloLink): RenderResult => {
);
};
+/**
+ * Describes the testing suite for the Groups screen.
+ */
describe('Testing Groups Screen', () => {
beforeAll(() => {
- jest.mock('react-router-dom', () => ({
- ...jest.requireActual('react-router-dom'),
- useParams: () => ({ orgId: 'orgId' }),
- }));
+ vi.mock('react-router-dom', async () => {
+ const actual = await vi.importActual('react-router-dom');
+ return {
+ ...actual,
+ useParams: () => ({ orgId: 'orgId' }),
+ };
+ });
});
beforeEach(() => {
setItem('userId', 'userId');
});
- afterAll(() => {
- jest.clearAllMocks();
+ afterEach(() => {
+ vi.resetAllMocks();
+ cleanup(); // from @testing-library/react
});
+ /**
+ * Tests redirection to the fallback URL when required URL parameters are missing.
+ * Ensures the "paramsError" element is displayed.
+ */
it('should redirect to fallback URL if URL params are undefined', async () => {
setItem('userId', null);
render(
@@ -102,12 +132,23 @@ describe('Testing Groups Screen', () => {
});
});
+ /**
+ * Checks if the Groups screen renders correctly with the expected elements.
+ */
it('should render Groups screen', async () => {
renderGroups(link1);
const searchInput = await screen.findByTestId('searchBy');
expect(searchInput).toBeInTheDocument();
+ // Verify other critical UI elements
+ expect(await screen.findByTestId('sort')).toBeInTheDocument();
+ expect(await screen.findByTestId('searchByToggle')).toBeInTheDocument();
+ const groupElements = await screen.findAllByTestId('groupName');
+ expect(groupElements.length).toBeGreaterThan(0);
});
+ /**
+ * Verifies the sorting functionality of the Groups screen.
+ */
it('Check Sorting Functionality', async () => {
renderGroups(link1);
const searchInput = await screen.findByTestId('searchBy');
@@ -137,6 +178,9 @@ describe('Testing Groups Screen', () => {
expect(groupName[0]).toHaveTextContent('Group 2');
});
+ /**
+ * Verifies the search by group functionality of the Groups screen.
+ */
it('Search by Groups', async () => {
renderGroups(link1);
const searchInput = await screen.findByTestId('searchBy');
@@ -157,6 +201,9 @@ describe('Testing Groups Screen', () => {
expect(groupName[0]).toHaveTextContent('Group 1');
});
+ /**
+ * Verifies the search by leader functionality of the Groups screen.
+ */
it('Search by Leader', async () => {
renderGroups(link1);
const searchInput = await screen.findByTestId('searchBy');
@@ -178,6 +225,9 @@ describe('Testing Groups Screen', () => {
expect(groupName[0]).toHaveTextContent('Group 1');
});
+ /**
+ * Verifies the behavior when there are no groups to display.
+ */
it('should render screen with No Groups', async () => {
renderGroups(link3);
@@ -187,6 +237,9 @@ describe('Testing Groups Screen', () => {
});
});
+ /**
+ * Verifies the error handling when there is an issue fetching groups data.
+ */
it('Error while fetching groups data', async () => {
renderGroups(link2);
@@ -195,6 +248,9 @@ describe('Testing Groups Screen', () => {
});
});
+ /**
+ * Verifies the functionality of opening and closing the ViewModal.
+ */
it('Open and close ViewModal', async () => {
renderGroups(link1);
@@ -205,6 +261,9 @@ describe('Testing Groups Screen', () => {
userEvent.click(await screen.findByTestId('volunteerViewModalCloseBtn'));
});
+ /**
+ * Verifies the functionality of opening and closing the GroupModal.
+ */
it('Open and close GroupModal', async () => {
renderGroups(link1);
From 9fbb2028d351e7effc2c02c0c43507760da01da7 Mon Sep 17 00:00:00 2001
From: Mehul Aggarwal <88583647+AceHunterr@users.noreply.github.com>
Date: Wed, 25 Dec 2024 03:52:24 +0530
Subject: [PATCH 076/133] Refactored .\src\utils\useLocalstorage.test.ts from
Jest to Vitest (#2844)
---
...seLocalstorage.test.ts => useLocalstorage.spec.ts} | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
rename src/utils/{useLocalstorage.test.ts => useLocalstorage.spec.ts} (91%)
diff --git a/src/utils/useLocalstorage.test.ts b/src/utils/useLocalstorage.spec.ts
similarity index 91%
rename from src/utils/useLocalstorage.test.ts
rename to src/utils/useLocalstorage.spec.ts
index 7483da4da2..b84cbd86cf 100644
--- a/src/utils/useLocalstorage.test.ts
+++ b/src/utils/useLocalstorage.spec.ts
@@ -1,3 +1,5 @@
+// SKIP_LOCALSTORAGE_CHECK
+
import {
getStorageKey,
getItem,
@@ -5,6 +7,7 @@ import {
removeItem,
useLocalStorage,
} from './useLocalstorage';
+import { describe, it, expect, beforeEach, vi } from 'vitest';
describe('Storage Helper Functions', () => {
beforeEach(() => {
@@ -95,7 +98,7 @@ describe('Storage Helper Functions', () => {
const storageHelper = useLocalStorage(customPrefix);
const key = 'testKey';
- const spyGetStorageKey = jest.spyOn(storageHelper, 'getStorageKey');
+ const spyGetStorageKey = vi.spyOn(storageHelper, 'getStorageKey');
storageHelper.getStorageKey(key);
expect(spyGetStorageKey).toHaveBeenCalledWith(key);
@@ -106,7 +109,7 @@ describe('Storage Helper Functions', () => {
const storageHelper = useLocalStorage(customPrefix);
const key = 'testKey';
- const spyGetItem = jest.spyOn(storageHelper, 'getItem');
+ const spyGetItem = vi.spyOn(storageHelper, 'getItem');
storageHelper.getItem(key);
expect(spyGetItem).toHaveBeenCalledWith(key);
@@ -118,7 +121,7 @@ describe('Storage Helper Functions', () => {
const key = 'testKey';
const value = 'data';
- const spySetItem = jest.spyOn(storageHelper, 'setItem');
+ const spySetItem = vi.spyOn(storageHelper, 'setItem');
storageHelper.setItem(key, value);
expect(spySetItem).toHaveBeenCalledWith(key, value);
@@ -129,7 +132,7 @@ describe('Storage Helper Functions', () => {
const storageHelper = useLocalStorage(customPrefix);
const key = 'testKey';
- const spyRemoveItem = jest.spyOn(storageHelper, 'removeItem');
+ const spyRemoveItem = vi.spyOn(storageHelper, 'removeItem');
storageHelper.removeItem(key);
expect(spyRemoveItem).toHaveBeenCalledWith(key);
From 92275006e92b1834ad312f67820fe937d5a20595 Mon Sep 17 00:00:00 2001
From: Aaditya Agarwal
Date: Wed, 25 Dec 2024 04:03:41 +0530
Subject: [PATCH 077/133] Added tests for src/screens/Users/Users.tsx (#2745)
* added tests for users.tsx
* shifted to vitest and added some tests
* added loadmoreusers function test
* added test to prevent duplicate users
* moved mock users to test file
* got rid of redundant code
---
src/screens/Users/Users.spec.tsx | 1553 ++++++++++++++++++++++++++++++
src/screens/Users/Users.test.tsx | 778 ---------------
src/screens/Users/Users.tsx | 89 +-
src/screens/Users/UsersMocks.ts | 1 -
4 files changed, 1616 insertions(+), 805 deletions(-)
create mode 100644 src/screens/Users/Users.spec.tsx
delete mode 100644 src/screens/Users/Users.test.tsx
diff --git a/src/screens/Users/Users.spec.tsx b/src/screens/Users/Users.spec.tsx
new file mode 100644
index 0000000000..1457bec5b8
--- /dev/null
+++ b/src/screens/Users/Users.spec.tsx
@@ -0,0 +1,1553 @@
+import React from 'react';
+import { MockedProvider } from '@apollo/react-testing';
+import { act, fireEvent, render, screen } from '@testing-library/react';
+import { I18nextProvider } from 'react-i18next';
+import { Provider } from 'react-redux';
+import { BrowserRouter } from 'react-router-dom';
+import { ToastContainer } from 'react-toastify';
+import userEvent from '@testing-library/user-event';
+import { store } from 'state/store';
+import { StaticMockLink } from 'utils/StaticMockLink';
+import i18nForTest from 'utils/i18nForTest';
+import Users from './Users';
+import { EMPTY_MOCKS, MOCKS, MOCKS2 } from './UsersMocks';
+import useLocalStorage from 'utils/useLocalstorage';
+import { describe, expect, it, beforeEach, afterEach, vi } from 'vitest';
+
+import {
+ USER_LIST,
+ ORGANIZATION_CONNECTION_LIST,
+} from 'GraphQl/Queries/Queries';
+
+const { setItem, removeItem } = useLocalStorage();
+
+const createAddress = {
+ city: 'Kingston',
+ countryCode: 'JM',
+ dependentLocality: 'Sample Dependent Locality',
+ line1: '123 Jamaica Street',
+ line2: 'Apartment 456',
+ postalCode: 'JM12345',
+ sortingCode: 'ABC-123',
+ state: 'Kingston Parish',
+};
+
+const createCreator = {
+ _id: '123',
+ firstName: 'Jack',
+ lastName: 'Smith',
+ image: null,
+ email: 'jack@example.com',
+ createdAt: '19/06/2022',
+};
+
+const MOCK_USERS = [
+ {
+ user: {
+ _id: 'user1',
+ firstName: 'John',
+ lastName: 'Doe',
+ image: null,
+ email: 'john@example.com',
+ createdAt: '2023-04-13T04:53:17.742+00:00',
+ registeredEvents: [],
+ membershipRequests: [],
+ organizationsBlockedBy: [
+ {
+ _id: 'xyz',
+ name: 'ABC',
+ image: null,
+ address: createAddress,
+ createdAt: '20/06/2022',
+ creator: {
+ _id: '123',
+ firstName: 'John',
+ lastName: 'Doe',
+ image: null,
+ email: 'john@example.com',
+ createdAt: '20/06/2022',
+ },
+ },
+ ],
+ joinedOrganizations: [
+ {
+ _id: 'abc',
+ name: 'Joined Organization 1',
+ image: null,
+ address: createAddress,
+ createdAt: '20/06/2022',
+ creator: {
+ _id: '123',
+ firstName: 'John',
+ lastName: 'Doe',
+ image: null,
+ email: 'john@example.com',
+ createdAt: '20/06/2022',
+ },
+ },
+ ],
+ },
+ appUserProfile: {
+ _id: 'user1',
+ adminFor: [
+ {
+ _id: '123',
+ },
+ ],
+ isSuperAdmin: true,
+ createdOrganizations: [],
+ createdEvents: [],
+ eventAdmin: [],
+ },
+ },
+ {
+ user: {
+ _id: 'user2',
+ firstName: 'Jane',
+ lastName: 'Doe',
+ image: null,
+ email: 'john@example.com',
+ createdAt: '2023-04-17T04:53:17.742+00:00',
+ registeredEvents: [],
+ membershipRequests: [],
+ organizationsBlockedBy: [
+ {
+ _id: '456',
+ name: 'ABC',
+ image: null,
+ address: createAddress,
+ createdAt: '21/06/2022',
+ creator: {
+ _id: '123',
+ firstName: 'John',
+ lastName: 'Doe',
+ image: null,
+ email: 'john@example.com',
+ createdAt: '21/06/2022',
+ },
+ },
+ ],
+ joinedOrganizations: [
+ {
+ _id: '123',
+ name: 'Palisadoes',
+ image: null,
+ address: createAddress,
+ createdAt: '21/06/2022',
+ creator: {
+ _id: '123',
+ firstName: 'John',
+ lastName: 'Doe',
+ image: null,
+ email: 'john@example.com',
+ createdAt: '21/06/2022',
+ },
+ },
+ ],
+ },
+ appUserProfile: {
+ _id: 'user2',
+ adminFor: [
+ {
+ _id: '123',
+ },
+ ],
+ isSuperAdmin: false,
+ createdOrganizations: [],
+ createdEvents: [],
+ eventAdmin: [],
+ },
+ },
+ {
+ user: {
+ _id: 'user3',
+ firstName: 'Jack',
+ lastName: 'Smith',
+ image: null,
+ email: 'jack@example.com',
+ createdAt: '2023-04-09T04:53:17.742+00:00',
+ registeredEvents: [],
+ membershipRequests: [],
+ organizationsBlockedBy: [
+ {
+ _id: 'xyz',
+ name: 'ABC',
+ image: null,
+ address: createAddress,
+ createdAt: '19/06/2022',
+ creator: createCreator,
+ },
+ ],
+ joinedOrganizations: [
+ {
+ _id: 'abc',
+ name: 'Joined Organization 1',
+ image: null,
+ address: createAddress,
+ createdAt: '19/06/2022',
+ creator: createCreator,
+ },
+ ],
+ },
+ appUserProfile: {
+ _id: 'user3',
+ adminFor: [],
+ isSuperAdmin: false,
+ createdOrganizations: [],
+ createdEvents: [],
+ eventAdmin: [],
+ },
+ },
+];
+
+const MOCK_USERS2 = [
+ ...MOCK_USERS,
+ {
+ user: {
+ _id: 'user4',
+ firstName: 'Emma',
+ lastName: 'Johnson',
+ image: null,
+ email: 'emma@example.com',
+ createdAt: '2023-04-22T04:53:17.742+00:00',
+ registeredEvents: [],
+ membershipRequests: [],
+ organizationsBlockedBy: [
+ {
+ _id: 'xyz',
+ name: 'ABC',
+ image: null,
+ address: createAddress,
+ createdAt: '19/06/2022',
+ creator: createCreator,
+ },
+ ],
+ joinedOrganizations: [
+ {
+ _id: 'abc',
+ name: 'Joined Organization 1',
+ image: null,
+ address: createAddress,
+ createdAt: '19/06/2022',
+ creator: createCreator,
+ },
+ ],
+ },
+ appUserProfile: {
+ _id: 'user4',
+ adminFor: [],
+ isSuperAdmin: false,
+ createdOrganizations: [],
+ createdEvents: [],
+ eventAdmin: [],
+ },
+ },
+ {
+ user: {
+ _id: 'user5',
+ firstName: 'Liam',
+ lastName: 'Smith',
+ image: null,
+ email: 'liam@example.com',
+ createdAt: '2023-04-23T04:53:17.742+00:00',
+ registeredEvents: [],
+ membershipRequests: [],
+ organizationsBlockedBy: [
+ {
+ _id: 'xyz',
+ name: 'ABC',
+ image: null,
+ address: createAddress,
+ createdAt: '19/06/2022',
+ creator: createCreator,
+ },
+ ],
+ joinedOrganizations: [
+ {
+ _id: 'abc',
+ name: 'Joined Organization 1',
+ image: null,
+ address: createAddress,
+ createdAt: '19/06/2022',
+ creator: createCreator,
+ },
+ ],
+ },
+ appUserProfile: {
+ _id: 'user5',
+ adminFor: [],
+ isSuperAdmin: false,
+ createdOrganizations: [],
+ createdEvents: [],
+ eventAdmin: [],
+ },
+ },
+ {
+ user: {
+ _id: 'user6',
+ firstName: 'Olivia',
+ lastName: 'Brown',
+ image: null,
+ email: 'olivia@example.com',
+ createdAt: '2023-04-24T04:53:17.742+00:00',
+ registeredEvents: [],
+ membershipRequests: [],
+ organizationsBlockedBy: [
+ {
+ _id: 'xyz',
+ name: 'ABC',
+ image: null,
+ address: createAddress,
+ createdAt: '19/06/2022',
+ creator: createCreator,
+ },
+ ],
+ joinedOrganizations: [
+ {
+ _id: 'abc',
+ name: 'Joined Organization 1',
+ image: null,
+ address: createAddress,
+ createdAt: '19/06/2022',
+ creator: createCreator,
+ },
+ ],
+ },
+ appUserProfile: {
+ _id: 'user6',
+ adminFor: [],
+ isSuperAdmin: false,
+ createdOrganizations: [],
+ createdEvents: [],
+ eventAdmin: [],
+ },
+ },
+ {
+ user: {
+ _id: 'user7',
+ firstName: 'Noah',
+ lastName: 'Williams',
+ image: null,
+ email: 'noah@example.com',
+ createdAt: '2023-04-25T04:53:17.742+00:00',
+ registeredEvents: [],
+ membershipRequests: [],
+ organizationsBlockedBy: [
+ {
+ _id: 'xyz',
+ name: 'ABC',
+ image: null,
+ address: createAddress,
+ createdAt: '19/06/2022',
+ creator: createCreator,
+ },
+ ],
+ joinedOrganizations: [
+ {
+ _id: 'abc',
+ name: 'Joined Organization 1',
+ image: null,
+ address: createAddress,
+ createdAt: '19/06/2022',
+ creator: createCreator,
+ },
+ ],
+ },
+ appUserProfile: {
+ _id: 'user7',
+ adminFor: [],
+ isSuperAdmin: false,
+ createdOrganizations: [],
+ createdEvents: [],
+ eventAdmin: [],
+ },
+ },
+ {
+ user: {
+ _id: 'user8',
+ firstName: 'Ava',
+ lastName: 'Jones',
+ image: null,
+ email: 'ava@example.com',
+ createdAt: '2023-04-26T04:53:17.742+00:00',
+ registeredEvents: [],
+ membershipRequests: [],
+ organizationsBlockedBy: [
+ {
+ _id: 'xyz',
+ name: 'ABC',
+ image: null,
+ address: createAddress,
+ createdAt: '19/06/2022',
+ creator: createCreator,
+ },
+ ],
+ joinedOrganizations: [
+ {
+ _id: 'abc',
+ name: 'Joined Organization 1',
+ image: null,
+ address: createAddress,
+ createdAt: '19/06/2022',
+ creator: createCreator,
+ },
+ ],
+ },
+ appUserProfile: {
+ _id: 'user8',
+ adminFor: [],
+ isSuperAdmin: false,
+ createdOrganizations: [],
+ createdEvents: [],
+ eventAdmin: [],
+ },
+ },
+ {
+ user: {
+ _id: 'user9',
+ firstName: 'Ethan',
+ lastName: 'Garcia',
+ image: null,
+ email: 'ethan@example.com',
+ createdAt: '2023-04-27T04:53:17.742+00:00',
+ registeredEvents: [],
+ membershipRequests: [],
+ organizationsBlockedBy: [
+ {
+ _id: 'xyz',
+ name: 'ABC',
+ image: null,
+ address: createAddress,
+ createdAt: '19/06/2022',
+ creator: createCreator,
+ },
+ ],
+ joinedOrganizations: [
+ {
+ _id: 'abc',
+ name: 'Joined Organization 1',
+ image: null,
+ address: createAddress,
+ createdAt: '19/06/2022',
+ creator: createCreator,
+ },
+ ],
+ },
+ appUserProfile: {
+ _id: 'user9',
+ adminFor: [],
+ isSuperAdmin: false,
+ createdOrganizations: [],
+ createdEvents: [],
+ eventAdmin: [],
+ },
+ },
+ {
+ user: {
+ _id: 'user10',
+ firstName: 'Sophia',
+ lastName: 'Martinez',
+ image: null,
+ email: 'sophia@example.com',
+ createdAt: '2023-04-28T04:53:17.742+00:00',
+ registeredEvents: [],
+ membershipRequests: [],
+ organizationsBlockedBy: [
+ {
+ _id: 'xyz',
+ name: 'ABC',
+ image: null,
+ address: createAddress,
+ createdAt: '19/06/2022',
+ creator: createCreator,
+ },
+ ],
+ joinedOrganizations: [
+ {
+ _id: 'abc',
+ name: 'Joined Organization 1',
+ image: null,
+ address: createAddress,
+ createdAt: '19/06/2022',
+ creator: createCreator,
+ },
+ ],
+ },
+ appUserProfile: {
+ _id: 'user10',
+ adminFor: [],
+ isSuperAdmin: false,
+ createdOrganizations: [],
+ createdEvents: [],
+ eventAdmin: [],
+ },
+ },
+ {
+ user: {
+ _id: 'user11',
+ firstName: 'Mason',
+ lastName: 'Davis',
+ image: null,
+ email: 'mason@example.com',
+ createdAt: '2023-04-29T04:53:17.742+00:00',
+ registeredEvents: [],
+ membershipRequests: [],
+ organizationsBlockedBy: [
+ {
+ _id: 'xyz',
+ name: 'ABC',
+ image: null,
+ address: createAddress,
+ createdAt: '19/06/2022',
+ creator: createCreator,
+ },
+ ],
+ joinedOrganizations: [
+ {
+ _id: 'abc',
+ name: 'Joined Organization 1',
+ image: null,
+ address: createAddress,
+ createdAt: '19/06/2022',
+ creator: createCreator,
+ },
+ ],
+ },
+ appUserProfile: {
+ _id: 'user11',
+ adminFor: [],
+ isSuperAdmin: false,
+ createdOrganizations: [],
+ createdEvents: [],
+ eventAdmin: [],
+ },
+ },
+ {
+ user: {
+ _id: 'user12',
+ firstName: 'Isabella',
+ lastName: 'Rodriguez',
+ image: null,
+ email: 'isabella@example.com',
+ createdAt: '2023-04-30T04:53:17.742+00:00',
+ registeredEvents: [],
+ membershipRequests: [],
+ organizationsBlockedBy: [
+ {
+ _id: 'xyz',
+ name: 'ABC',
+ image: null,
+ address: createAddress,
+ createdAt: '19/06/2022',
+ creator: createCreator,
+ },
+ ],
+ joinedOrganizations: [
+ {
+ _id: 'abc',
+ name: 'Joined Organization 1',
+ image: null,
+ address: createAddress,
+ createdAt: '19/06/2022',
+ creator: createCreator,
+ },
+ ],
+ },
+ appUserProfile: {
+ _id: 'user12',
+ adminFor: [],
+ isSuperAdmin: false,
+ createdOrganizations: [],
+ createdEvents: [],
+ eventAdmin: [],
+ },
+ },
+ {
+ user: {
+ _id: 'user13',
+ firstName: 'Logan',
+ lastName: 'Wilson',
+ image: null,
+ email: 'logan@example.com',
+ createdAt: '2023-04-08T04:53:17.742+00:00',
+ registeredEvents: [],
+ membershipRequests: [],
+ organizationsBlockedBy: [
+ {
+ _id: 'xyz',
+ name: 'ABC',
+ image: null,
+ address: createAddress,
+ createdAt: '19/06/2022',
+ creator: createCreator,
+ },
+ ],
+ joinedOrganizations: [
+ {
+ _id: 'abc',
+ name: 'Joined Organization 1',
+ image: null,
+ address: createAddress,
+ createdAt: '19/06/2022',
+ creator: createCreator,
+ },
+ ],
+ },
+ appUserProfile: {
+ _id: 'user13',
+ adminFor: [],
+ isSuperAdmin: false,
+ createdOrganizations: [],
+ createdEvents: [],
+ eventAdmin: [],
+ },
+ },
+ {
+ user: {
+ _id: 'user14',
+ firstName: 'Mia',
+ lastName: 'Anderson',
+ image: null,
+ email: 'mia@example.com',
+ createdAt: '2023-04-07T04:53:17.742+00:00',
+ registeredEvents: [],
+ membershipRequests: [],
+ organizationsBlockedBy: [
+ {
+ _id: 'xyz',
+ name: 'ABC',
+ image: null,
+ address: createAddress,
+ createdAt: '19/06/2022',
+ creator: createCreator,
+ },
+ ],
+ joinedOrganizations: [
+ {
+ _id: 'abc',
+ name: 'Joined Organization 1',
+ image: null,
+ address: createAddress,
+ createdAt: '19/06/2022',
+ creator: createCreator,
+ },
+ ],
+ },
+ appUserProfile: {
+ _id: 'user14',
+ adminFor: [],
+ isSuperAdmin: false,
+ createdOrganizations: [],
+ createdEvents: [],
+ eventAdmin: [],
+ },
+ },
+ {
+ user: {
+ _id: 'user15',
+ firstName: 'Lucas',
+ lastName: 'Thomas',
+ image: null,
+ email: 'lucas@example.com',
+ createdAt: '2023-04-05T04:53:17.742+00:00',
+ registeredEvents: [],
+ membershipRequests: [],
+ organizationsBlockedBy: [
+ {
+ _id: 'xyz',
+ name: 'ABC',
+ image: null,
+ address: createAddress,
+ createdAt: '19/06/2022',
+ creator: createCreator,
+ },
+ ],
+ joinedOrganizations: [
+ {
+ _id: 'abc',
+ name: 'Joined Organization 1',
+ image: null,
+ address: createAddress,
+ createdAt: '19/06/2022',
+ creator: createCreator,
+ },
+ ],
+ },
+ appUserProfile: {
+ _id: 'user15',
+ adminFor: [],
+ isSuperAdmin: false,
+ createdOrganizations: [],
+ createdEvents: [],
+ eventAdmin: [],
+ },
+ },
+];
+
+const MOCKS_NEW = [
+ {
+ request: {
+ query: USER_LIST,
+ variables: {
+ first: 12,
+ skip: 0,
+ firstName_contains: '',
+ lastName_contains: '',
+ order: 'createdAt_DESC',
+ },
+ },
+ result: {
+ data: {
+ users: MOCK_USERS,
+ },
+ },
+ },
+ {
+ request: {
+ query: ORGANIZATION_CONNECTION_LIST,
+ },
+ result: {
+ data: {
+ organizationsConnection: [],
+ },
+ },
+ },
+];
+
+const MOCKS_NEW2 = [
+ {
+ request: {
+ query: USER_LIST,
+ variables: {
+ first: 12,
+ skip: 0,
+ firstName_contains: '',
+ lastName_contains: '',
+ order: 'createdAt_DESC',
+ },
+ },
+ result: {
+ data: {
+ users: MOCK_USERS2.slice(0, 12),
+ },
+ },
+ },
+ {
+ request: {
+ query: ORGANIZATION_CONNECTION_LIST,
+ },
+ result: {
+ data: {
+ organizationsConnection: [],
+ },
+ },
+ },
+ {
+ request: {
+ query: USER_LIST,
+ variables: {
+ first: 24,
+ skip: 0,
+ firstName_contains: '',
+ lastName_contains: '',
+ order: 'createdAt_DESC',
+ filter: '',
+ },
+ },
+ result: {
+ data: {
+ users: MOCK_USERS2.slice(12, 15),
+ },
+ },
+ },
+];
+
+const MOCKS_NEW3 = [
+ {
+ request: {
+ query: USER_LIST,
+ variables: {
+ first: 12,
+ skip: 0,
+ firstName_contains: '',
+ lastName_contains: '',
+ order: 'createdAt_DESC',
+ },
+ },
+ result: {
+ data: {
+ users: MOCK_USERS2.slice(0, 12),
+ },
+ },
+ },
+ {
+ request: {
+ query: ORGANIZATION_CONNECTION_LIST,
+ },
+ result: {
+ data: {
+ organizationsConnection: [],
+ },
+ },
+ },
+ {
+ request: {
+ query: USER_LIST,
+ variables: {
+ first: 24,
+ skip: 0,
+ firstName_contains: '',
+ lastName_contains: '',
+ order: 'createdAt_DESC',
+ filter: '',
+ },
+ },
+ result: {
+ data: {
+ users: MOCK_USERS2.slice(11, 15),
+ },
+ },
+ },
+ {
+ request: {
+ query: USER_LIST,
+ variables: {
+ first: 24,
+ skip: 0,
+ firstName_contains: '',
+ lastName_contains: '',
+ order: 'createdAt_DESC',
+ filter: '',
+ },
+ },
+ result: {
+ data: {
+ users: MOCK_USERS2.slice(11, 15),
+ },
+ },
+ },
+ {
+ request: {
+ query: USER_LIST,
+ variables: {
+ first: 13,
+ skip: 3,
+ firstName_contains: '',
+ lastName_contains: '',
+ order: 'createdAt_DESC',
+ filter: '',
+ },
+ },
+ result: {
+ data: {
+ users: [],
+ },
+ },
+ },
+];
+
+const link = new StaticMockLink(MOCKS, true);
+const link2 = new StaticMockLink(EMPTY_MOCKS, true);
+const link3 = new StaticMockLink(MOCKS2, true);
+const link5 = new StaticMockLink(MOCKS_NEW, true);
+const link6 = new StaticMockLink(MOCKS_NEW2, true);
+const link7 = new StaticMockLink(MOCKS_NEW3, true);
+
+async function wait(ms = 1000): Promise {
+ await act(() => {
+ return new Promise((resolve) => {
+ setTimeout(resolve, ms);
+ });
+ });
+}
+beforeEach(() => {
+ setItem('id', '123');
+ setItem('SuperAdmin', true);
+ setItem('FirstName', 'John');
+ setItem('AdminFor', [{ name: 'adi', _id: '1234', image: '' }]);
+ setItem('LastName', 'Doe');
+});
+
+afterEach(() => {
+ localStorage.clear();
+ vi.restoreAllMocks();
+});
+
+describe('Testing Users screen', () => {
+ it('Component should be rendered properly', async () => {
+ render(
+
+
+
+
+
+
+
+
+ ,
+ );
+
+ await wait();
+ expect(screen.getByTestId('testcomp')).toBeInTheDocument();
+ });
+
+ it(`Component should be rendered properly when user is not superAdmin
+ and or userId does not exists in localstorage`, async () => {
+ setItem('AdminFor', ['123']);
+ removeItem('SuperAdmin');
+ await wait();
+ setItem('id', '');
+ render(
+
+
+
+
+
+
+
+
+ ,
+ );
+ await wait();
+ });
+
+ it(`Component should be rendered properly when userId does not exists in localstorage`, async () => {
+ removeItem('AdminFor');
+ removeItem('SuperAdmin');
+ await wait();
+ removeItem('id');
+ render(
+
+
+
+
+
+
+
+
+ ,
+ );
+ await wait();
+ });
+
+ it('Component should be rendered properly when user is superAdmin', async () => {
+ render(
+
+
+
+
+
+
+
+
+ ,
+ );
+
+ await wait();
+ });
+
+ it('Testing seach by name functionality', async () => {
+ render(
+
+
+
+
+
+
+
+
+ ,
+ );
+
+ await wait();
+ const searchBtn = screen.getByTestId('searchButton');
+ const search1 = 'John';
+ userEvent.type(screen.getByTestId(/searchByName/i), search1);
+ userEvent.click(searchBtn);
+ await wait();
+ expect(screen.queryByText(/not found/i)).not.toBeInTheDocument();
+
+ const search2 = 'Pete{backspace}{backspace}{backspace}{backspace}';
+ userEvent.type(screen.getByTestId(/searchByName/i), search2);
+
+ const search3 =
+ 'John{backspace}{backspace}{backspace}{backspace}Sam{backspace}{backspace}{backspace}';
+ userEvent.type(screen.getByTestId(/searchByName/i), search3);
+
+ const search4 = 'Sam{backspace}{backspace}P{backspace}';
+ userEvent.type(screen.getByTestId(/searchByName/i), search4);
+
+ const search5 = 'Xe';
+ userEvent.type(screen.getByTestId(/searchByName/i), search5);
+ userEvent.clear(screen.getByTestId(/searchByName/i));
+ userEvent.type(screen.getByTestId(/searchByName/i), '');
+ userEvent.click(searchBtn);
+ await wait();
+ });
+
+ it('testing search not found', async () => {
+ await act(async () => {
+ render(
+
+
+
+
+
+
+
+
+ ,
+ );
+ });
+ await wait();
+
+ const searchBtn = screen.getByTestId('searchButton');
+ const searchInput = screen.getByTestId(/searchByName/i);
+
+ await act(async () => {
+ // Clear the search input
+ userEvent.clear(searchInput);
+ // Search for a name that doesn't exist
+ userEvent.type(screen.getByTestId(/searchByName/i), 'NonexistentName');
+ userEvent.click(searchBtn);
+ });
+
+ expect(screen.queryByText(/No User Found/i)).toBeInTheDocument();
+ });
+
+ it('Testing User data is not present', async () => {
+ render(
+
+
+
+
+
+
+
+
+ ,
+ );
+
+ await wait();
+ expect(screen.getByText(/No User Found/i)).toBeTruthy();
+ });
+
+ it('Should render warning alert when there are no organizations', async () => {
+ const { container } = render(
+
+
+
+
+
+
+
+
+
+ ,
+ );
+
+ await wait(200);
+ expect(container.textContent).toMatch(
+ 'Organizations not found, please create an organization through dashboard',
+ );
+ });
+
+ it('Should not render warning alert when there are organizations present', async () => {
+ const { container } = render(
+
+
+
+
+
+
+
+
+
+ ,
+ );
+
+ await wait();
+
+ expect(container.textContent).not.toMatch(
+ 'Organizations not found, please create an organization through dashboard',
+ );
+ });
+
+ it('Testing filter functionality', async () => {
+ await act(async () => {
+ render(
+
+
+
+
+
+
+
+
+
+ ,
+ );
+ });
+ await wait();
+
+ const searchInput = screen.getByTestId('filter');
+ expect(searchInput).toBeInTheDocument();
+
+ const inputText = screen.getByTestId('filterUsers');
+
+ await act(async () => {
+ fireEvent.click(inputText);
+ });
+
+ const toggleText = screen.getByTestId('admin');
+
+ await act(async () => {
+ fireEvent.click(toggleText);
+ });
+
+ expect(searchInput).toBeInTheDocument();
+
+ await act(async () => {
+ fireEvent.click(inputText);
+ });
+
+ let toggleTite = screen.getByTestId('superAdmin');
+
+ await act(async () => {
+ fireEvent.click(toggleTite);
+ });
+
+ expect(searchInput).toBeInTheDocument();
+
+ await act(async () => {
+ fireEvent.click(inputText);
+ });
+
+ toggleTite = screen.getByTestId('user');
+
+ await act(async () => {
+ fireEvent.click(toggleTite);
+ });
+
+ expect(searchInput).toBeInTheDocument();
+
+ await act(async () => {
+ fireEvent.click(inputText);
+ });
+
+ toggleTite = screen.getByTestId('cancel');
+
+ await act(async () => {
+ fireEvent.click(toggleTite);
+ });
+
+ await wait();
+
+ expect(searchInput).toBeInTheDocument();
+ });
+
+ it('check for rerendering', async () => {
+ const { rerender } = render(
+
+
+
+
+
+
+
+
+
+ ,
+ );
+
+ await wait();
+ rerender(
+
+
+
+
+
+
+
+
+
+ ,
+ );
+ await wait();
+ });
+
+ it('should set hasMore to false if users length is less than perPageResult', async () => {
+ const link = new StaticMockLink(EMPTY_MOCKS, true);
+
+ render(
+
+
+
+
+
+
+
+
+
+ ,
+ );
+
+ await wait(200);
+
+ // Check if "No User Found" is displayed
+ expect(screen.getByText(/No User Found/i)).toBeInTheDocument();
+ });
+
+ it('should filter users correctly', async () => {
+ await act(async () => {
+ render(
+
+
+
+
+
+
+
+
+
+ ,
+ );
+ });
+ await wait();
+
+ const filterButton = screen.getByTestId('filterUsers');
+
+ await act(async () => {
+ fireEvent.click(filterButton);
+ });
+
+ const filterAdmin = screen.getByTestId('admin');
+
+ await act(async () => {
+ fireEvent.click(filterAdmin);
+ });
+
+ // await wait();
+ expect(screen.getByText('Jane Doe')).toBeInTheDocument();
+
+ await act(async () => {
+ fireEvent.click(filterButton);
+ });
+
+ const filterSuperAdmin = screen.getByTestId('superAdmin');
+
+ await act(async () => {
+ fireEvent.click(filterSuperAdmin);
+ });
+
+ // await wait();
+ expect(screen.getByText('John Doe')).toBeInTheDocument();
+
+ await act(async () => {
+ fireEvent.click(filterButton);
+ });
+
+ const filterUser = screen.getByTestId('user');
+ await act(async () => {
+ fireEvent.click(filterUser);
+ });
+
+ // await wait();
+ expect(screen.getByText('Jack Smith')).toBeInTheDocument();
+
+ await act(async () => {
+ fireEvent.click(filterButton);
+ });
+
+ const filterCancel = screen.getByTestId('cancel');
+
+ await act(async () => {
+ fireEvent.click(filterCancel);
+ });
+
+ // await wait();
+ expect(screen.getByText('John Doe')).toBeInTheDocument();
+ expect(screen.getByText('Jane Doe')).toBeInTheDocument();
+ expect(screen.getByText('Jack Smith')).toBeInTheDocument();
+ });
+
+ it('Users should be sorted in newest order correctly', async () => {
+ await act(async () => {
+ render(
+
+
+
+
+
+
+
+
+
+ ,
+ );
+ });
+ await wait();
+
+ const inputText = screen.getByTestId('sortUsers');
+
+ await act(async () => {
+ fireEvent.click(inputText);
+ });
+
+ const toggleTite = screen.getByTestId('newest');
+
+ await act(async () => {
+ fireEvent.click(toggleTite);
+ });
+
+ // Verify the users are sorted by newest
+
+ const displayedUsers = screen.getAllByRole('row');
+ await wait();
+ expect(displayedUsers[1]).toHaveTextContent('Jane Doe');
+ expect(displayedUsers[2]).toHaveTextContent('John Doe');
+ });
+
+ it('Check if pressing enter key triggers search', async () => {
+ await act(async () => {
+ render(
+
+
+
+
+
+
+
+
+
+ ,
+ );
+ });
+ await wait();
+ const searchInput = screen.getByTestId('searchByName');
+
+ await act(async () => {
+ userEvent.type(searchInput, 'John');
+ });
+ await act(async () => {
+ userEvent.type(searchInput, '{enter}');
+ });
+ });
+
+ it('Users should be sorted in oldest order correctly', async () => {
+ await act(async () => {
+ render(
+
+
+
+
+
+
+
+
+
+ ,
+ );
+ });
+ await wait();
+
+ const inputText = screen.getByTestId('sortUsers');
+
+ await act(async () => {
+ fireEvent.click(inputText);
+ });
+
+ const toggleTite = screen.getByTestId('oldest');
+
+ await act(async () => {
+ fireEvent.click(toggleTite);
+ });
+
+ // Verify the users are sorted by oldest
+
+ const displayedUsers = screen.getAllByRole('row');
+ await wait();
+ expect(displayedUsers[1]).toHaveTextContent('Jack Smith');
+ expect(displayedUsers[2]).toHaveTextContent('John Doe');
+ });
+
+ it('Role filter should not update if selected role is already selected', async () => {
+ await act(async () => {
+ render(
+
+
+
+
+
+
+
+
+
+ ,
+ );
+ });
+ await wait();
+
+ const filterButton = screen.getByTestId('filterUsers');
+
+ await act(async () => {
+ fireEvent.click(filterButton);
+ });
+
+ const filterAdmin = screen.getByTestId('admin');
+
+ await act(async () => {
+ fireEvent.click(filterAdmin);
+ });
+
+ // await wait();
+ expect(screen.getByText('Jane Doe')).toBeInTheDocument();
+
+ await act(async () => {
+ fireEvent.click(filterAdmin);
+ });
+
+ // await wait();
+ expect(screen.getByText('Jane Doe')).toBeInTheDocument();
+ });
+
+ it('Sort filter should not update if selected sort is already selected', async () => {
+ await act(async () => {
+ render(
+
+
+
+
+
+
+
+
+
+ ,
+ );
+ });
+ await wait();
+
+ const inputText = screen.getByTestId('sortUsers');
+
+ await act(async () => {
+ fireEvent.click(inputText);
+ });
+
+ const toggleTite = screen.getByTestId('newest');
+
+ await act(async () => {
+ fireEvent.click(toggleTite);
+ });
+
+ // Verify the users are sorted by newest
+
+ const displayedUsers = screen.getAllByRole('row');
+ await wait();
+ expect(displayedUsers[1]).toHaveTextContent('Jane Doe');
+ expect(displayedUsers[2]).toHaveTextContent('John Doe');
+
+ await act(async () => {
+ fireEvent.click(inputText);
+ });
+
+ const toggleTite2 = screen.getByTestId('newest');
+
+ await act(async () => {
+ fireEvent.click(toggleTite2);
+ });
+
+ // Verify the users are sorted by newest
+
+ const displayedUsers2 = screen.getAllByRole('row');
+ await wait();
+ expect(displayedUsers2[1]).toHaveTextContent('Jane Doe');
+ expect(displayedUsers2[2]).toHaveTextContent('John Doe');
+ });
+
+ it('Reset and Refetch function should work when we search an empty string', async () => {
+ render(
+
+
+
+
+
+
+
+
+ ,
+ );
+
+ await wait();
+ const searchBtn = screen.getByTestId('searchButton');
+ const search1 = '';
+ userEvent.type(screen.getByTestId(/searchByName/i), search1);
+ userEvent.click(searchBtn);
+ await wait();
+ expect(screen.queryByText(/Jane Doe/i)).toBeInTheDocument();
+ expect(screen.queryByText(/John Doe/i)).toBeInTheDocument();
+ expect(screen.queryByText(/Jack Smith/i)).toBeInTheDocument();
+ });
+
+ it('Users should be loaded on scroll using loadmoreusers function', async () => {
+ const { container } = render(
+
+
+
+
+
+
+
+
+ ,
+ );
+
+ await wait();
+ const users = container
+ .getElementsByTagName('tbody')[0]
+ .querySelectorAll('tr');
+ expect(users.length).toBe(12);
+
+ await act(async () => {
+ fireEvent.scroll(window, { target: { scrollY: 1000 } });
+ });
+
+ await wait();
+
+ const users2 = container
+ .getElementsByTagName('tbody')[0]
+ .querySelectorAll('tr');
+ expect(users2.length).toBe(15);
+ });
+
+ it('should not show duplicate users when scrolling by using mergedUsers and loadUnqUsers', async () => {
+ const { container } = render(
+
+
+
+
+
+
+
+
+ ,
+ );
+
+ await wait();
+ const users = container
+ .getElementsByTagName('tbody')[0]
+ .querySelectorAll('tr');
+ expect(users.length).toBe(12);
+
+ await act(async () => {
+ fireEvent.scroll(window, { target: { scrollY: 1000 } });
+ });
+
+ await wait();
+
+ const users2 = container
+ .getElementsByTagName('tbody')[0]
+ .querySelectorAll('tr');
+ expect(users2.length).toBe(15);
+ });
+});
diff --git a/src/screens/Users/Users.test.tsx b/src/screens/Users/Users.test.tsx
deleted file mode 100644
index 65558e6ea7..0000000000
--- a/src/screens/Users/Users.test.tsx
+++ /dev/null
@@ -1,778 +0,0 @@
-import React from 'react';
-import { MockedProvider } from '@apollo/react-testing';
-import { act, fireEvent, render, screen } from '@testing-library/react';
-import 'jest-localstorage-mock';
-import 'jest-location-mock';
-import { I18nextProvider } from 'react-i18next';
-import { Provider } from 'react-redux';
-import { BrowserRouter } from 'react-router-dom';
-import { ToastContainer } from 'react-toastify';
-import userEvent from '@testing-library/user-event';
-import { store } from 'state/store';
-import { StaticMockLink } from 'utils/StaticMockLink';
-import i18nForTest from 'utils/i18nForTest';
-import Users from './Users';
-import { EMPTY_MOCKS, MOCKS, MOCKS2 } from './UsersMocks';
-import useLocalStorage from 'utils/useLocalstorage';
-
-import {
- USER_LIST,
- ORGANIZATION_CONNECTION_LIST,
-} from 'GraphQl/Queries/Queries';
-
-const { setItem, removeItem } = useLocalStorage();
-
-const MOCK_USERS = [
- {
- user: {
- _id: 'user1',
- firstName: 'John',
- lastName: 'Doe',
- image: null,
- email: 'john@example.com',
- createdAt: '20/06/2022',
- registeredEvents: [],
- membershipRequests: [],
- organizationsBlockedBy: [
- {
- _id: 'xyz',
- name: 'ABC',
- image: null,
- address: {
- city: 'Kingston',
- countryCode: 'JM',
- dependentLocality: 'Sample Dependent Locality',
- line1: '123 Jamaica Street',
- line2: 'Apartment 456',
- postalCode: 'JM12345',
- sortingCode: 'ABC-123',
- state: 'Kingston Parish',
- },
- createdAt: '20/06/2022',
- creator: {
- _id: '123',
- firstName: 'John',
- lastName: 'Doe',
- image: null,
- email: 'john@example.com',
- createdAt: '20/06/2022',
- },
- },
- ],
- joinedOrganizations: [
- {
- _id: 'abc',
- name: 'Joined Organization 1',
- image: null,
- address: {
- city: 'Kingston',
- countryCode: 'JM',
- dependentLocality: 'Sample Dependent Locality',
- line1: '123 Jamaica Street',
- line2: 'Apartment 456',
- postalCode: 'JM12345',
- sortingCode: 'ABC-123',
- state: 'Kingston Parish',
- },
- createdAt: '20/06/2022',
- creator: {
- _id: '123',
- firstName: 'John',
- lastName: 'Doe',
- image: null,
- email: 'john@example.com',
- createdAt: '20/06/2022',
- },
- },
- ],
- },
- appUserProfile: {
- _id: 'user1',
- adminFor: [
- {
- _id: '123',
- },
- ],
- isSuperAdmin: true,
- createdOrganizations: [],
- createdEvents: [],
- eventAdmin: [],
- },
- },
- {
- user: {
- _id: 'user2',
- firstName: 'Jane',
- lastName: 'Doe',
- image: null,
- email: 'john@example.com',
- createdAt: '21/06/2022',
- registeredEvents: [],
- membershipRequests: [],
- organizationsBlockedBy: [
- {
- _id: '456',
- name: 'ABC',
- image: null,
- address: {
- city: 'Kingston',
- countryCode: 'JM',
- dependentLocality: 'Sample Dependent Locality',
- line1: '123 Jamaica Street',
- line2: 'Apartment 456',
- postalCode: 'JM12345',
- sortingCode: 'ABC-123',
- state: 'Kingston Parish',
- },
- createdAt: '21/06/2022',
- creator: {
- _id: '123',
- firstName: 'John',
- lastName: 'Doe',
- image: null,
- email: 'john@example.com',
- createdAt: '21/06/2022',
- },
- },
- ],
- joinedOrganizations: [
- {
- _id: '123',
- name: 'Palisadoes',
- image: null,
- address: {
- city: 'Kingston',
- countryCode: 'JM',
- dependentLocality: 'Sample Dependent Locality',
- line1: '123 Jamaica Street',
- line2: 'Apartment 456',
- postalCode: 'JM12345',
- sortingCode: 'ABC-123',
- state: 'Kingston Parish',
- },
- createdAt: '21/06/2022',
- creator: {
- _id: '123',
- firstName: 'John',
- lastName: 'Doe',
- image: null,
- email: 'john@example.com',
- createdAt: '21/06/2022',
- },
- },
- ],
- },
- appUserProfile: {
- _id: 'user2',
- adminFor: [
- {
- _id: '123',
- },
- ],
- isSuperAdmin: false,
- createdOrganizations: [],
- createdEvents: [],
- eventAdmin: [],
- },
- },
- {
- user: {
- _id: 'user3',
- firstName: 'Jack',
- lastName: 'Smith',
- image: null,
- email: 'jack@example.com',
- createdAt: '19/06/2022',
- registeredEvents: [],
- membershipRequests: [],
- organizationsBlockedBy: [
- {
- _id: 'xyz',
- name: 'ABC',
- image: null,
- address: {
- city: 'Kingston',
- countryCode: 'JM',
- dependentLocality: 'Sample Dependent Locality',
- line1: '123 Jamaica Street',
- line2: 'Apartment 456',
- postalCode: 'JM12345',
- sortingCode: 'ABC-123',
- state: 'Kingston Parish',
- },
- createdAt: '19/06/2022',
- creator: {
- _id: '123',
- firstName: 'Jack',
- lastName: 'Smith',
- image: null,
- email: 'jack@example.com',
- createdAt: '19/06/2022',
- },
- },
- ],
- joinedOrganizations: [
- {
- _id: 'abc',
- name: 'Joined Organization 1',
- image: null,
- address: {
- city: 'Kingston',
- countryCode: 'JM',
- dependentLocality: 'Sample Dependent Locality',
- line1: '123 Jamaica Street',
- line2: 'Apartment 456',
- postalCode: 'JM12345',
- sortingCode: 'ABC-123',
- state: 'Kingston Parish',
- },
- createdAt: '19/06/2022',
- creator: {
- _id: '123',
- firstName: 'Jack',
- lastName: 'Smith',
- image: null,
- email: 'jack@example.com',
- createdAt: '19/06/2022',
- },
- },
- ],
- },
- appUserProfile: {
- _id: 'user3',
- adminFor: [],
- isSuperAdmin: false,
- createdOrganizations: [],
- createdEvents: [],
- eventAdmin: [],
- },
- },
-];
-
-const MOCKS_NEW = [
- {
- request: {
- query: USER_LIST,
- variables: {
- first: 12,
- skip: 0,
- firstName_contains: '',
- lastName_contains: '',
- order: 'createdAt_DESC',
- },
- },
- result: {
- data: {
- users: MOCK_USERS,
- },
- },
- },
- {
- request: {
- query: ORGANIZATION_CONNECTION_LIST,
- },
- result: {
- data: {
- organizationsConnection: [],
- },
- },
- },
-];
-
-const link = new StaticMockLink(MOCKS, true);
-const link2 = new StaticMockLink(EMPTY_MOCKS, true);
-const link3 = new StaticMockLink(MOCKS2, true);
-const link5 = new StaticMockLink(MOCKS_NEW, true);
-
-async function wait(ms = 1000): Promise {
- await act(() => {
- return new Promise((resolve) => {
- setTimeout(resolve, ms);
- });
- });
-}
-beforeEach(() => {
- setItem('id', '123');
- setItem('SuperAdmin', true);
- setItem('FirstName', 'John');
- setItem('AdminFor', [{ name: 'adi', _id: '1234', image: '' }]);
- setItem('LastName', 'Doe');
-});
-
-afterEach(() => {
- localStorage.clear();
-});
-
-describe('Testing Users screen', () => {
- test('Component should be rendered properly', async () => {
- render(
-
-
-
-
-
-
-
-
- ,
- );
-
- await wait();
- expect(screen.getByTestId('testcomp')).toBeInTheDocument();
- });
-
- test(`Component should be rendered properly when user is not superAdmin
- and or userId does not exists in localstorage`, async () => {
- setItem('AdminFor', ['123']);
- removeItem('SuperAdmin');
- await wait();
- setItem('id', '');
- render(
-
-
-
-
-
-
-
-
- ,
- );
- await wait();
- });
-
- test(`Component should be rendered properly when userId does not exists in localstorage`, async () => {
- removeItem('AdminFor');
- removeItem('SuperAdmin');
- await wait();
- removeItem('id');
- render(
-
-
-
-
-
-
-
-
- ,
- );
- await wait();
- });
-
- test('Component should be rendered properly when user is superAdmin', async () => {
- render(
-
-
-
-
-
-
-
-
- ,
- );
-
- await wait();
- });
-
- test('Testing seach by name functionality', async () => {
- render(
-
-
-
-
-
-
-
-
- ,
- );
-
- await wait();
- const searchBtn = screen.getByTestId('searchButton');
- const search1 = 'John';
- userEvent.type(screen.getByTestId(/searchByName/i), search1);
- userEvent.click(searchBtn);
- await wait();
- expect(screen.queryByText(/not found/i)).not.toBeInTheDocument();
-
- const search2 = 'Pete{backspace}{backspace}{backspace}{backspace}';
- userEvent.type(screen.getByTestId(/searchByName/i), search2);
-
- const search3 =
- 'John{backspace}{backspace}{backspace}{backspace}Sam{backspace}{backspace}{backspace}';
- userEvent.type(screen.getByTestId(/searchByName/i), search3);
-
- const search4 = 'Sam{backspace}{backspace}P{backspace}';
- userEvent.type(screen.getByTestId(/searchByName/i), search4);
-
- const search5 = 'Xe';
- userEvent.type(screen.getByTestId(/searchByName/i), search5);
- userEvent.clear(screen.getByTestId(/searchByName/i));
- userEvent.type(screen.getByTestId(/searchByName/i), '');
- userEvent.click(searchBtn);
- await wait();
- });
-
- test('testing search not found', async () => {
- await act(async () => {
- render(
-
-
-
-
-
-
-
-
- ,
- );
- });
- await wait();
-
- const searchBtn = screen.getByTestId('searchButton');
- const searchInput = screen.getByTestId(/searchByName/i);
-
- await act(async () => {
- // Clear the search input
- userEvent.clear(searchInput);
- // Search for a name that doesn't exist
- userEvent.type(screen.getByTestId(/searchByName/i), 'NonexistentName');
- userEvent.click(searchBtn);
- });
-
- expect(screen.queryByText(/No User Found/i)).toBeInTheDocument();
- });
-
- test('Testing User data is not present', async () => {
- render(
-
-
-
-
-
-
-
-
- ,
- );
-
- await wait();
- expect(screen.getByText(/No User Found/i)).toBeTruthy();
- });
-
- test('Should render warning alert when there are no organizations', async () => {
- const { container } = render(
-
-
-
-
-
-
-
-
-
- ,
- );
-
- await wait(200);
- expect(container.textContent).toMatch(
- 'Organizations not found, please create an organization through dashboard',
- );
- });
-
- test('Should not render warning alert when there are organizations present', async () => {
- const { container } = render(
-
-
-
-
-
-
-
-
-
- ,
- );
-
- await wait();
-
- expect(container.textContent).not.toMatch(
- 'Organizations not found, please create an organization through dashboard',
- );
- });
-
- test('Testing filter functionality', async () => {
- await act(async () => {
- render(
-
-
-
-
-
-
-
-
-
- ,
- );
- });
- await wait();
-
- const searchInput = screen.getByTestId('filter');
- expect(searchInput).toBeInTheDocument();
-
- const inputText = screen.getByTestId('filterUsers');
-
- await act(async () => {
- fireEvent.click(inputText);
- });
-
- const toggleText = screen.getByTestId('admin');
-
- await act(async () => {
- fireEvent.click(toggleText);
- });
-
- expect(searchInput).toBeInTheDocument();
-
- await act(async () => {
- fireEvent.click(inputText);
- });
-
- let toggleTite = screen.getByTestId('superAdmin');
-
- await act(async () => {
- fireEvent.click(toggleTite);
- });
-
- expect(searchInput).toBeInTheDocument();
-
- await act(async () => {
- fireEvent.click(inputText);
- });
-
- toggleTite = screen.getByTestId('user');
-
- await act(async () => {
- fireEvent.click(toggleTite);
- });
-
- expect(searchInput).toBeInTheDocument();
-
- await act(async () => {
- fireEvent.click(inputText);
- });
-
- toggleTite = screen.getByTestId('cancel');
-
- await act(async () => {
- fireEvent.click(toggleTite);
- });
-
- await wait();
-
- expect(searchInput).toBeInTheDocument();
- });
-
- test('check for rerendering', async () => {
- const { rerender } = render(
-
-
-
-
-
-
-
-
-
- ,
- );
-
- await wait();
- rerender(
-
-
-
-
-
-
-
-
-
- ,
- );
- await wait();
- });
-
- test('should set hasMore to false if users length is less than perPageResult', async () => {
- const link = new StaticMockLink(EMPTY_MOCKS, true);
-
- render(
-
-
-
-
-
-
-
-
-
- ,
- );
-
- await wait(200);
-
- // Check if "No User Found" is displayed
- expect(screen.getByText(/No User Found/i)).toBeInTheDocument();
- });
-
- test('should filter users correctly', async () => {
- await act(async () => {
- render(
-
-
-
-
-
-
-
-
-
- ,
- );
- });
- await wait();
-
- const filterButton = screen.getByTestId('filterUsers');
-
- await act(async () => {
- fireEvent.click(filterButton);
- });
-
- const filterAdmin = screen.getByTestId('admin');
-
- await act(async () => {
- fireEvent.click(filterAdmin);
- });
-
- await wait();
- expect(screen.getByText('Jane Doe')).toBeInTheDocument();
-
- await act(async () => {
- fireEvent.click(filterButton);
- });
-
- const filterSuperAdmin = screen.getByTestId('superAdmin');
-
- await act(async () => {
- fireEvent.click(filterSuperAdmin);
- });
-
- await wait();
- expect(screen.getByText('John Doe')).toBeInTheDocument();
-
- await act(async () => {
- fireEvent.click(filterButton);
- });
-
- const filterUser = screen.getByTestId('user');
- await act(async () => {
- fireEvent.click(filterUser);
- });
-
- await wait();
- expect(screen.getByText('Jack Smith')).toBeInTheDocument();
-
- await act(async () => {
- fireEvent.click(filterButton);
- });
-
- const filterCancel = screen.getByTestId('cancel');
-
- await act(async () => {
- fireEvent.click(filterCancel);
- });
-
- await wait();
- expect(screen.getByText('John Doe')).toBeInTheDocument();
- expect(screen.getByText('Jane Doe')).toBeInTheDocument();
- expect(screen.getByText('Jack Smith')).toBeInTheDocument();
- });
-
- test('Users should be sorted and filtered correctly', async () => {
- await act(async () => {
- render(
-
-
-
-
-
-
-
-
-
- ,
- );
- });
- await wait();
-
- // Check if the sorting and filtering logic was applied correctly
- const rows = screen.getAllByRole('row');
-
- const firstRow = rows[1];
- const secondRow = rows[2];
-
- expect(firstRow).toHaveTextContent('John Doe');
- expect(secondRow).toHaveTextContent('Jane Doe');
-
- await wait();
-
- const inputText = screen.getByTestId('sortUsers');
-
- await act(async () => {
- fireEvent.click(inputText);
- });
-
- const toggleText = screen.getByTestId('oldest');
-
- await act(async () => {
- fireEvent.click(toggleText);
- fireEvent.click(inputText);
- });
-
- const toggleTite = screen.getByTestId('newest');
-
- await act(async () => {
- fireEvent.click(toggleTite);
- });
-
- // Verify the users are sorted by oldest
- await wait();
-
- const displayedUsers = screen.getAllByRole('row');
- expect(displayedUsers[1]).toHaveTextContent('John Doe'); // assuming User1 is the oldest
- expect(displayedUsers[displayedUsers.length - 1]).toHaveTextContent(
- 'Jack Smith',
- ); // assuming UserN is the newest
-
- await wait();
-
- await act(async () => {
- fireEvent.click(inputText);
- });
-
- const toggleOld = screen.getByTestId('oldest');
-
- await act(async () => {
- fireEvent.click(toggleOld);
- fireEvent.click(inputText);
- });
-
- const toggleNewest = screen.getByTestId('newest');
- await act(async () => {
- fireEvent.click(toggleNewest);
- });
- });
-});
diff --git a/src/screens/Users/Users.tsx b/src/screens/Users/Users.tsx
index b046679a00..936807f1ec 100644
--- a/src/screens/Users/Users.tsx
+++ b/src/screens/Users/Users.tsx
@@ -77,15 +77,19 @@ const Users = (): JSX.Element => {
const [searchByName, setSearchByName] = useState('');
const [sortingOption, setSortingOption] = useState('newest');
const [filteringOption, setFilteringOption] = useState('cancel');
+ const [loadUnqUsers, setLoadUnqUsers] = useState(0);
const userType = getItem('SuperAdmin')
? 'SUPERADMIN'
: getItem('AdminFor')
? 'ADMIN'
: 'USER';
const loggedInUserId = getItem('id');
+ const [usersData, setUsersData] = useState<
+ { users: InterfaceQueryUserListItem[] } | undefined
+ >(undefined);
const {
- data: usersData,
+ data,
loading: loading,
fetchMore,
refetch: refetchUsers,
@@ -114,6 +118,12 @@ const Users = (): JSX.Element => {
notifyOnNetworkStatusChange: true,
});
+ useEffect(() => {
+ if (data) {
+ setUsersData(data);
+ }
+ }, [data, isLoading]);
+
const { data: dataOrgs } = useQuery(ORGANIZATION_CONNECTION_LIST);
const [displayedUsers, setDisplayedUsers] = useState(usersData?.users || []);
@@ -122,14 +132,13 @@ const Users = (): JSX.Element => {
if (!usersData) {
return;
}
+
if (usersData.users.length < perPageResult) {
setHasMore(false);
}
- if (usersData && usersData.users) {
- let newDisplayedUsers = sortUsers(usersData.users, sortingOption);
- newDisplayedUsers = filterUsers(newDisplayedUsers, filteringOption);
- setDisplayedUsers(newDisplayedUsers);
- }
+ let newDisplayedUsers = sortUsers(usersData.users, sortingOption);
+ newDisplayedUsers = filterUsers(newDisplayedUsers, filteringOption);
+ setDisplayedUsers(newDisplayedUsers);
}, [usersData, sortingOption, filteringOption]);
// To clear the search when the component is unmounted
@@ -166,6 +175,12 @@ const Users = (): JSX.Element => {
}
}, [loading]);
+ useEffect(() => {
+ if (loadUnqUsers > 0) {
+ loadMoreUsers(displayedUsers.length, loadUnqUsers);
+ }
+ }, [displayedUsers]);
+
const handleSearch = (value: string): void => {
setSearchByName(value);
if (value === '') {
@@ -208,12 +223,12 @@ const Users = (): JSX.Element => {
setHasMore(true);
};
/* istanbul ignore next */
- const loadMoreUsers = (): void => {
+ const loadMoreUsers = (skipValue: number, limitVal: number): void => {
setIsLoadingMore(true);
fetchMore({
variables: {
- skip: usersData?.users.length || 0,
- userType: 'ADMIN',
+ first: limitVal + perPageResult || perPageResult,
+ skip: skipValue - perPageResult >= 0 ? skipValue - perPageResult : 0,
filter: searchByName,
order: sortingOption === 'newest' ? 'createdAt_DESC' : 'createdAt_ASC',
},
@@ -227,18 +242,32 @@ const Users = (): JSX.Element => {
) => {
setIsLoadingMore(false);
if (!fetchMoreResult) return prev || { users: [] };
- if (fetchMoreResult.users.length < perPageResult) {
- setHasMore(false);
+
+ const mergedUsers = [...(prev?.users || []), ...fetchMoreResult.users];
+
+ const uniqueUsers = Array.from(
+ new Map(mergedUsers.map((user) => [user.user._id, user])).values(),
+ );
+ if (uniqueUsers.length < mergedUsers.length) {
+ setLoadUnqUsers(mergedUsers.length - uniqueUsers.length);
+ } else setLoadUnqUsers(0);
+
+ // Load more users will always run after the initial request, hence prev is not going to be undefined
+ if (prev?.users) {
+ if (uniqueUsers.length - prev?.users.length < perPageResult) {
+ setHasMore(false);
+ }
}
- return {
- users: [...(prev?.users || []), ...fetchMoreResult.users],
- };
+
+ return { users: uniqueUsers };
},
});
};
const handleSorting = (option: string): void => {
- setDisplayedUsers([]);
+ if (option === sortingOption) {
+ return;
+ }
setHasMore(true);
setSortingOption(option);
};
@@ -256,19 +285,21 @@ const Users = (): JSX.Element => {
new Date(a.user.createdAt).getTime(),
);
return sortedUsers;
- } else {
- sortedUsers.sort(
- (a, b) =>
- new Date(a.user.createdAt).getTime() -
- new Date(b.user.createdAt).getTime(),
- );
- return sortedUsers;
}
+ sortedUsers.sort(
+ (a, b) =>
+ new Date(a.user.createdAt).getTime() -
+ new Date(b.user.createdAt).getTime(),
+ );
+ return sortedUsers;
};
const handleFiltering = (option: string): void => {
- setDisplayedUsers([]);
+ if (option === filteringOption) {
+ return;
+ }
setFilteringOption(option);
+ setHasMore(true);
};
const filterUsers = (
@@ -352,13 +383,17 @@ const Users = (): JSX.Element => {
handleSorting('newest')}
+ onClick={(): void => {
+ handleSorting('newest');
+ }}
data-testid="newest"
>
{t('Newest')}
handleSorting('oldest')}
+ onClick={(): void => {
+ handleSorting('oldest');
+ }}
data-testid="oldest"
>
{t('Oldest')}
@@ -444,7 +479,9 @@ const Users = (): JSX.Element => {
/* istanbul ignore next */
displayedUsers.length ?? 0
}
- next={loadMoreUsers}
+ next={() => {
+ loadMoreUsers(displayedUsers.length, perPageResult);
+ }}
loader={
Date: Wed, 25 Dec 2024 10:33:46 +0530
Subject: [PATCH 078/133] fix: Add SubTag and Tag Modal Footer buttons
margin-bottom set to 10px (#2846)
---
src/style/app.module.css | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/style/app.module.css b/src/style/app.module.css
index 440d988cf5..5bfdef1e66 100644
--- a/src/style/app.module.css
+++ b/src/style/app.module.css
@@ -154,6 +154,7 @@
}
.closeButton {
+ margin-bottom: 10px;
color: var(--delete-button-color);
margin-right: 5px;
background-color: var(--delete-button-bg);
From ce358e5cef115cdf1e721a14f20bc5be62ae0c16 Mon Sep 17 00:00:00 2001
From: Gurram Karthik <167804249+gurramkarthiknetha@users.noreply.github.com>
Date: Wed, 25 Dec 2024 10:34:57 +0530
Subject: [PATCH 079/133] fixed:#2475 Refactor:
src/components/AddOn/support/components/MainContent/MainContent.test.tsx from
Jest to Vitest (#2843)
* fixed-2475-fixed
* removed import
---
.../{MainContent.test.tsx => MainContent.spec.tsx} | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
rename src/components/AddOn/support/components/MainContent/{MainContent.test.tsx => MainContent.spec.tsx} (70%)
diff --git a/src/components/AddOn/support/components/MainContent/MainContent.test.tsx b/src/components/AddOn/support/components/MainContent/MainContent.spec.tsx
similarity index 70%
rename from src/components/AddOn/support/components/MainContent/MainContent.test.tsx
rename to src/components/AddOn/support/components/MainContent/MainContent.spec.tsx
index 81adbc916e..90988e8d2b 100644
--- a/src/components/AddOn/support/components/MainContent/MainContent.test.tsx
+++ b/src/components/AddOn/support/components/MainContent/MainContent.spec.tsx
@@ -1,5 +1,6 @@
import React from 'react';
import { render } from '@testing-library/react';
+import { describe, it, expect } from 'vitest';
import { Provider } from 'react-redux';
import { BrowserRouter } from 'react-router-dom';
@@ -11,7 +12,7 @@ describe('Testing MainContent component', () => {
children: 'This is a dummy text',
};
- test('should render props and children for the Main Content', () => {
+ it('should render props and children for the Main Content', () => {
const { getByTestId, getByText } = render(
@@ -20,7 +21,7 @@ describe('Testing MainContent component', () => {
,
);
- expect(getByTestId('mainContentCheck')).toBeInTheDocument();
- expect(getByText(props.children)).toBeInTheDocument();
+ expect(getByTestId('mainContentCheck')).not.toBeNull();
+ expect(getByText(props.children)).not.toBeNull();
});
});
From f60d17de8dc74f9f98d9e1431da007bd04806df7 Mon Sep 17 00:00:00 2001
From: Pratap Rathi
Date: Wed, 25 Dec 2024 10:45:54 +0530
Subject: [PATCH 080/133] Refactor: Migrated
src/components/DynamicDropDown/DynamicDropDown.test.tsx from Jest to Vitest
(#2847)
---
...DropDown.test.tsx => DynamicDropDown.spec.tsx} | 15 ++++++++-------
1 file changed, 8 insertions(+), 7 deletions(-)
rename src/components/DynamicDropDown/{DynamicDropDown.test.tsx => DynamicDropDown.spec.tsx} (91%)
diff --git a/src/components/DynamicDropDown/DynamicDropDown.test.tsx b/src/components/DynamicDropDown/DynamicDropDown.spec.tsx
similarity index 91%
rename from src/components/DynamicDropDown/DynamicDropDown.test.tsx
rename to src/components/DynamicDropDown/DynamicDropDown.spec.tsx
index dac98ca9e6..85c3208a20 100644
--- a/src/components/DynamicDropDown/DynamicDropDown.test.tsx
+++ b/src/components/DynamicDropDown/DynamicDropDown.spec.tsx
@@ -11,11 +11,12 @@ import { BrowserRouter } from 'react-router-dom';
import { I18nextProvider } from 'react-i18next';
import i18nForTest from 'utils/i18nForTest';
import userEvent from '@testing-library/user-event';
+import { vi, expect, it } from 'vitest';
describe('DynamicDropDown component', () => {
- test('renders and handles selection correctly', async () => {
+ it('renders and handles selection correctly', async () => {
const formData = { fieldName: 'value2' };
- const setFormData = jest.fn();
+ const setFormData = vi.fn();
render(
@@ -60,10 +61,10 @@ describe('DynamicDropDown component', () => {
expect(dropdownButton).toHaveTextContent('Label 2');
});
});
- test('calls custom handleChange function when provided', async () => {
+ it('calls custom handleChange function when provided', async () => {
const formData = { fieldName: 'value1' };
- const setFormData = jest.fn();
- const customHandleChange = jest.fn();
+ const setFormData = vi.fn();
+ const customHandleChange = vi.fn();
render(
@@ -103,9 +104,9 @@ describe('DynamicDropDown component', () => {
);
expect(setFormData).not.toHaveBeenCalled();
});
- test('handles keyboard navigation correctly', async () => {
+ it('handles keyboard navigation correctly', async () => {
const formData = { fieldName: 'value1' };
- const setFormData = jest.fn();
+ const setFormData = vi.fn();
render(
From 4132c7de13b7468f652d6659d7d92bbadb0681bd Mon Sep 17 00:00:00 2001
From: Abhishek Raj <113784630+abbi4code@users.noreply.github.com>
Date: Wed, 25 Dec 2024 12:12:41 +0530
Subject: [PATCH 081/133] checkenvFile test migrated from jest to vitest
(#2849)
---
...ckEnvFile.test.ts => checkEnvFile.spec.ts} | 25 +++++++++++++------
1 file changed, 17 insertions(+), 8 deletions(-)
rename src/setup/checkEnvFile/{checkEnvFile.test.ts => checkEnvFile.spec.ts} (62%)
diff --git a/src/setup/checkEnvFile/checkEnvFile.test.ts b/src/setup/checkEnvFile/checkEnvFile.spec.ts
similarity index 62%
rename from src/setup/checkEnvFile/checkEnvFile.test.ts
rename to src/setup/checkEnvFile/checkEnvFile.spec.ts
index a23976db4a..c2b75db0a6 100644
--- a/src/setup/checkEnvFile/checkEnvFile.test.ts
+++ b/src/setup/checkEnvFile/checkEnvFile.spec.ts
@@ -1,11 +1,22 @@
import fs from 'fs';
import { checkEnvFile } from './checkEnvFile';
+import { vi } from 'vitest';
-jest.mock('fs');
+/**
+ * This file contains unit tests for the `checkEnvFile` function.
+ *
+ * The tests cover:
+ * - Behavior when the `.env` file is missing required keys and appending them appropriately.
+ * - Ensuring no changes are made when all keys are present in the `.env` file.
+ *
+ * These tests utilize Vitest for test execution and mock the `fs` module to simulate file operations.
+ */
+
+vi.mock('fs');
describe('checkEnvFile', () => {
beforeEach(() => {
- jest.resetAllMocks();
+ vi.resetAllMocks();
});
it('should append missing keys to the .env file', () => {
@@ -13,13 +24,12 @@ describe('checkEnvFile', () => {
const envExampleContent =
'EXISTING_KEY=existing_value\nNEW_KEY=default_value\n';
- jest
- .spyOn(fs, 'readFileSync')
+ vi.spyOn(fs, 'readFileSync')
.mockReturnValueOnce(envContent)
.mockReturnValueOnce(envExampleContent)
.mockReturnValueOnce(envExampleContent);
- jest.spyOn(fs, 'appendFileSync');
+ vi.spyOn(fs, 'appendFileSync');
checkEnvFile();
@@ -33,12 +43,11 @@ describe('checkEnvFile', () => {
const envContent = 'EXISTING_KEY=existing_value\n';
const envExampleContent = 'EXISTING_KEY=existing_value\n';
- jest
- .spyOn(fs, 'readFileSync')
+ vi.spyOn(fs, 'readFileSync')
.mockReturnValueOnce(envContent)
.mockReturnValueOnce(envExampleContent);
- jest.spyOn(fs, 'appendFileSync');
+ vi.spyOn(fs, 'appendFileSync');
checkEnvFile();
From 00216ba25294c24df2f70e874295ad939a80a878 Mon Sep 17 00:00:00 2001
From: Abhishek Raj <113784630+abbi4code@users.noreply.github.com>
Date: Wed, 25 Dec 2024 12:21:11 +0530
Subject: [PATCH 082/133] organizationCard tests migrated from jest to vitest
(#2852)
---
...tionCard.test.tsx => OrganizationCard.spec.tsx} | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)
rename src/components/OrganizationCard/{OrganizationCard.test.tsx => OrganizationCard.spec.tsx} (66%)
diff --git a/src/components/OrganizationCard/OrganizationCard.test.tsx b/src/components/OrganizationCard/OrganizationCard.spec.tsx
similarity index 66%
rename from src/components/OrganizationCard/OrganizationCard.test.tsx
rename to src/components/OrganizationCard/OrganizationCard.spec.tsx
index e4abf3a1fd..c557253d59 100644
--- a/src/components/OrganizationCard/OrganizationCard.test.tsx
+++ b/src/components/OrganizationCard/OrganizationCard.spec.tsx
@@ -2,8 +2,18 @@ import React from 'react';
import { render, screen } from '@testing-library/react';
import OrganizationCard from './OrganizationCard';
+/**
+ * This file contains unit tests for the `OrganizationCard` component.
+ *
+ * The tests cover:
+ * - Rendering the component with all provided props and verifying the correct display of text elements.
+ * - Ensuring the component handles cases where certain props (like image) are not provided.
+ *
+ * These tests utilize the React Testing Library for rendering and querying DOM elements.
+ */
+
describe('Testing the Organization 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', () => {
const props = {
id: '123',
image: 'https://via.placeholder.com/80',
@@ -20,7 +30,7 @@ describe('Testing the Organization Card', () => {
expect(screen.getByText(props.lastName)).toBeInTheDocument();
});
- test('Should render text elements when props value is not passed', () => {
+ it('Should render text elements when props value is not passed', () => {
const props = {
id: '123',
image: '',
From f8da9d572d1843c5de26ee3f3b0492cdfec825a9 Mon Sep 17 00:00:00 2001
From: MANDEEP N H <146331633+mandeepnh5@users.noreply.github.com>
Date: Wed, 25 Dec 2024 13:02:10 +0530
Subject: [PATCH 083/133] Migrated src/components/AgendaItems/* from Jest to
Vitest (#2850)
* Update Agenda items vitest
* Update jest to vitest
* update modal reverted
---
...tainer.test.tsx => AgendaItemsContainer.spec.tsx} | 12 +++++-------
.../AgendaItems/AgendaItemsContainerProps.ts | 5 +++--
...dal.test.tsx => AgendaItemsPreviewModal.spec.tsx} | 7 ++++---
3 files changed, 12 insertions(+), 12 deletions(-)
rename src/components/AgendaItems/{AgendaItemsContainer.test.tsx => AgendaItemsContainer.spec.tsx} (98%)
rename src/components/AgendaItems/{AgendaItemsPreviewModal.test.tsx => AgendaItemsPreviewModal.spec.tsx} (94%)
diff --git a/src/components/AgendaItems/AgendaItemsContainer.test.tsx b/src/components/AgendaItems/AgendaItemsContainer.spec.tsx
similarity index 98%
rename from src/components/AgendaItems/AgendaItemsContainer.test.tsx
rename to src/components/AgendaItems/AgendaItemsContainer.spec.tsx
index 8b391a2073..f8f6ab948d 100644
--- a/src/components/AgendaItems/AgendaItemsContainer.test.tsx
+++ b/src/components/AgendaItems/AgendaItemsContainer.spec.tsx
@@ -7,9 +7,7 @@ import {
fireEvent,
} 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';
@@ -24,20 +22,20 @@ import { StaticMockLink } from 'utils/StaticMockLink';
import { props, props2 } from './AgendaItemsContainerProps';
import { MOCKS, MOCKS_ERROR } from './AgendaItemsContainerMocks';
import AgendaItemsContainer from './AgendaItemsContainer';
-
+import { describe, test, expect, vi } from 'vitest';
const link = new StaticMockLink(MOCKS, true);
const link2 = new StaticMockLink(MOCKS_ERROR, true);
-jest.mock('react-toastify', () => ({
+vi.mock('react-toastify', () => ({
toast: {
- success: jest.fn(),
- error: jest.fn(),
+ success: vi.fn(),
+ error: vi.fn(),
},
}));
//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;
}
diff --git a/src/components/AgendaItems/AgendaItemsContainerProps.ts b/src/components/AgendaItems/AgendaItemsContainerProps.ts
index d6dcf3feca..f19d5ff9df 100644
--- a/src/components/AgendaItems/AgendaItemsContainerProps.ts
+++ b/src/components/AgendaItems/AgendaItemsContainerProps.ts
@@ -1,4 +1,5 @@
type AgendaItemConnectionType = 'Event';
+import { vi } from 'vitest';
export const props = {
agendaItemConnection: 'Event' as AgendaItemConnectionType,
@@ -68,7 +69,7 @@ export const props = {
},
},
],
- agendaItemRefetch: jest.fn(),
+ agendaItemRefetch: vi.fn(),
agendaItemCategories: [
{
_id: 'agendaCategory1',
@@ -96,6 +97,6 @@ export const props = {
export const props2 = {
agendaItemConnection: 'Event' as AgendaItemConnectionType,
agendaItemData: [],
- agendaItemRefetch: jest.fn(),
+ agendaItemRefetch: vi.fn(),
agendaItemCategories: [],
};
diff --git a/src/components/AgendaItems/AgendaItemsPreviewModal.test.tsx b/src/components/AgendaItems/AgendaItemsPreviewModal.spec.tsx
similarity index 94%
rename from src/components/AgendaItems/AgendaItemsPreviewModal.test.tsx
rename to src/components/AgendaItems/AgendaItemsPreviewModal.spec.tsx
index 0a7b4646ba..35c67576cc 100644
--- a/src/components/AgendaItems/AgendaItemsPreviewModal.test.tsx
+++ b/src/components/AgendaItems/AgendaItemsPreviewModal.spec.tsx
@@ -11,6 +11,7 @@ import { LocalizationProvider } from '@mui/x-date-pickers';
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
import AgendaItemsPreviewModal from './AgendaItemsPreviewModal';
+import { describe, test, expect, vi } from 'vitest';
const mockFormState = {
title: 'Test Title',
@@ -44,10 +45,10 @@ describe('AgendaItemsPreviewModal', () => {
From 1bc2d3b088992ab41c476de8e91cab946a90089b Mon Sep 17 00:00:00 2001
From: MANDEEP N H <146331633+mandeepnh5@users.noreply.github.com>
Date: Wed, 25 Dec 2024 13:03:02 +0530
Subject: [PATCH 084/133] Migrated
src/components/AgendaItems/AgendaItemsUpdateModal.test.tsx from Jest to
Vitest (#2851)
* Update jest to vitest
* Fix linting issue
---
...st.tsx => AgendaItemsUpdateModal.spec.tsx} | 19 ++++++++++---------
1 file changed, 10 insertions(+), 9 deletions(-)
rename src/components/AgendaItems/{AgendaItemsUpdateModal.test.tsx => AgendaItemsUpdateModal.spec.tsx} (96%)
diff --git a/src/components/AgendaItems/AgendaItemsUpdateModal.test.tsx b/src/components/AgendaItems/AgendaItemsUpdateModal.spec.tsx
similarity index 96%
rename from src/components/AgendaItems/AgendaItemsUpdateModal.test.tsx
rename to src/components/AgendaItems/AgendaItemsUpdateModal.spec.tsx
index 0f11ea31b2..8d277419fa 100644
--- a/src/components/AgendaItems/AgendaItemsUpdateModal.test.tsx
+++ b/src/components/AgendaItems/AgendaItemsUpdateModal.spec.tsx
@@ -12,13 +12,14 @@ 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';
+import type { MockedFunction } from 'vitest';
+import { describe, test, expect, vi } from 'vitest';
const mockFormState = {
title: 'Test Title',
@@ -67,19 +68,19 @@ const mockAgendaItemCategories = [
},
];
-const mockHideUpdateModal = jest.fn();
-const mockSetFormState = jest.fn();
-const mockUpdateAgendaItemHandler = jest.fn();
+const mockHideUpdateModal = vi.fn();
+const mockSetFormState = vi.fn();
+const mockUpdateAgendaItemHandler = vi.fn();
const mockT = (key: string): string => key;
-jest.mock('react-toastify', () => ({
+vi.mock('react-toastify', () => ({
toast: {
- success: jest.fn(),
- error: jest.fn(),
+ success: vi.fn(),
+ error: vi.fn(),
},
}));
-jest.mock('utils/convertToBase64');
-const mockedConvertToBase64 = convertToBase64 as jest.MockedFunction<
+vi.mock('utils/convertToBase64');
+const mockedConvertToBase64 = convertToBase64 as MockedFunction<
typeof convertToBase64
>;
From e719b826cbb986aef5db40f57c26f0b19585d6ff Mon Sep 17 00:00:00 2001
From: khushi santosh patil
<143253539+khushipatil1523@users.noreply.github.com>
Date: Wed, 25 Dec 2024 14:43:11 +0530
Subject: [PATCH 085/133] convert test from jest to vitest (#2856)
---
...test.tsx => EventDashboardScreen.spec.tsx} | 35 +++++++++++--------
1 file changed, 20 insertions(+), 15 deletions(-)
rename src/components/EventDashboardScreen/{EventDashboardScreen.test.tsx => EventDashboardScreen.spec.tsx} (85%)
diff --git a/src/components/EventDashboardScreen/EventDashboardScreen.test.tsx b/src/components/EventDashboardScreen/EventDashboardScreen.spec.tsx
similarity index 85%
rename from src/components/EventDashboardScreen/EventDashboardScreen.test.tsx
rename to src/components/EventDashboardScreen/EventDashboardScreen.spec.tsx
index 6b48b034a9..7fc5028658 100644
--- a/src/components/EventDashboardScreen/EventDashboardScreen.test.tsx
+++ b/src/components/EventDashboardScreen/EventDashboardScreen.spec.tsx
@@ -1,8 +1,8 @@
import React from 'react';
+import { describe, it, expect, vi } from 'vitest';
import { MockedProvider } from '@apollo/react-testing';
import { fireEvent, render, screen } from '@testing-library/react';
import { I18nextProvider } from 'react-i18next';
-import 'jest-location-mock';
import { Provider } from 'react-redux';
import { BrowserRouter } from 'react-router-dom';
import { store } from 'state/store';
@@ -11,27 +11,32 @@ import EventDashboardScreen from './EventDashboardScreen';
import { ORGANIZATIONS_LIST } from 'GraphQl/Queries/Queries';
import { StaticMockLink } from 'utils/StaticMockLink';
import useLocalStorage from 'utils/useLocalstorage';
+
const { setItem } = useLocalStorage();
Object.defineProperty(window, 'matchMedia', {
writable: true,
- value: jest.fn().mockImplementation((query) => ({
+ value: vi.fn().mockImplementation((query) => ({
matches: false,
media: query,
onchange: null,
- addListener: jest.fn(), // Deprecated
- removeListener: jest.fn(), // Deprecated
- addEventListener: jest.fn(),
- removeEventListener: jest.fn(),
- dispatchEvent: jest.fn(),
+ addListener: vi.fn(), // Deprecated
+ removeListener: vi.fn(), // Deprecated
+ addEventListener: vi.fn(),
+ removeEventListener: vi.fn(),
+ dispatchEvent: vi.fn(),
})),
});
let mockID: string | undefined = '123';
-jest.mock('react-router-dom', () => ({
- ...jest.requireActual('react-router-dom'),
- useParams: () => ({ orgId: mockID }),
-}));
+
+vi.mock('react-router-dom', async () => {
+ const actual = await vi.importActual('react-router-dom');
+ return {
+ ...actual,
+ useParams: () => ({ orgId: mockID }),
+ };
+});
const MOCKS = [
{
@@ -86,7 +91,7 @@ const clickToggleMenuBtn = (toggleButton: HTMLElement): void => {
};
describe('Testing LeftDrawer in OrganizationScreen', () => {
- test('should be redirected to / if IsLoggedIn is false', async () => {
+ it('should be redirected to / if IsLoggedIn is false', async () => {
setItem('IsLoggedIn', false);
render(
@@ -101,7 +106,7 @@ describe('Testing LeftDrawer in OrganizationScreen', () => {
);
expect(window.location.pathname).toEqual('/');
});
- test('should be redirected to / if ss is false', async () => {
+ it('should be redirected to / if ss is false', async () => {
setItem('IsLoggedIn', true);
render(
@@ -115,7 +120,7 @@ describe('Testing LeftDrawer in OrganizationScreen', () => {
,
);
});
- test('Testing LeftDrawer in page functionality', async () => {
+ it('Testing LeftDrawer in page functionality', async () => {
setItem('IsLoggedIn', true);
setItem('AdminFor', [
{ _id: '6637904485008f171cf29924', __typename: 'Organization' },
@@ -148,7 +153,7 @@ describe('Testing LeftDrawer in OrganizationScreen', () => {
expect(icon).toHaveClass('fa fa-angle-double-right');
});
- test('should be redirected to / if orgId is undefined', async () => {
+ it('should be redirected to / if orgId is undefined', async () => {
mockID = undefined;
render(
From 910690b57e8f55c59e75a3476128f78c7d4938a3 Mon Sep 17 00:00:00 2001
From: MANDEEP N H <146331633+mandeepnh5@users.noreply.github.com>
Date: Wed, 25 Dec 2024 14:45:18 +0530
Subject: [PATCH 086/133] Migrated
src/components/InfiniteScrollLoader/InfiniteScrollLoader.test.tsx from Jest
to Vitest (#2854)
* Update infintite scroll loader jest to vitest
* Fix linting issue
---
...finiteScrollLoader.test.tsx => InfiniteScrollLoader.spec.tsx} | 1 +
1 file changed, 1 insertion(+)
rename src/components/InfiniteScrollLoader/{InfiniteScrollLoader.test.tsx => InfiniteScrollLoader.spec.tsx} (90%)
diff --git a/src/components/InfiniteScrollLoader/InfiniteScrollLoader.test.tsx b/src/components/InfiniteScrollLoader/InfiniteScrollLoader.spec.tsx
similarity index 90%
rename from src/components/InfiniteScrollLoader/InfiniteScrollLoader.test.tsx
rename to src/components/InfiniteScrollLoader/InfiniteScrollLoader.spec.tsx
index 1e179e0de0..3159082105 100644
--- a/src/components/InfiniteScrollLoader/InfiniteScrollLoader.test.tsx
+++ b/src/components/InfiniteScrollLoader/InfiniteScrollLoader.spec.tsx
@@ -1,6 +1,7 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import InfiniteScrollLoader from './InfiniteScrollLoader';
+import { describe, test, expect } from 'vitest';
describe('Testing InfiniteScrollLoader component', () => {
test('Component should be rendered properly', () => {
From 1eab2c1b37d5ebc75da80566406146c1f496144f Mon Sep 17 00:00:00 2001
From: MANDEEP N H <146331633+mandeepnh5@users.noreply.github.com>
Date: Wed, 25 Dec 2024 14:46:19 +0530
Subject: [PATCH 087/133] Migrated
src/components/ContriStats/ContriStats.test.tsx from Jest to Vitest. (#2855)
* Update contistats jest to vitest
* Fix linting issue
* Fix package json issue
---
.../ContriStats/{ContriStats.test.tsx => ContriStats.spec.tsx} | 1 +
1 file changed, 1 insertion(+)
rename src/components/ContriStats/{ContriStats.test.tsx => ContriStats.spec.tsx} (96%)
diff --git a/src/components/ContriStats/ContriStats.test.tsx b/src/components/ContriStats/ContriStats.spec.tsx
similarity index 96%
rename from src/components/ContriStats/ContriStats.test.tsx
rename to src/components/ContriStats/ContriStats.spec.tsx
index 8edb853684..4a9f1fc94f 100644
--- a/src/components/ContriStats/ContriStats.test.tsx
+++ b/src/components/ContriStats/ContriStats.spec.tsx
@@ -6,6 +6,7 @@ import { ApolloClient, ApolloProvider, InMemoryCache } from '@apollo/client';
import type { NormalizedCacheObject } from '@apollo/client';
import i18nForTest from 'utils/i18nForTest';
import { BACKEND_URL } from 'Constant/constant';
+import { describe, test, expect } from 'vitest';
const client: ApolloClient = new ApolloClient({
cache: new InMemoryCache(),
From ba43121f13dd99b6aaf51f21783f92b2c48cc044 Mon Sep 17 00:00:00 2001
From: MANDEEP N H <146331633+mandeepnh5@users.noreply.github.com>
Date: Wed, 25 Dec 2024 15:51:34 +0530
Subject: [PATCH 088/133] Migrated
src/components/LoginPortalToggle/LoginPortalToggle.test.tsx from Jest to
Vitest. (#2857)
* Update login portal toggle test to vitest
* Fix linting issue
---
.../{LoginPortalToggle.test.tsx => LoginPortalToggle.spec.tsx} | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
rename src/components/LoginPortalToggle/{LoginPortalToggle.test.tsx => LoginPortalToggle.spec.tsx} (92%)
diff --git a/src/components/LoginPortalToggle/LoginPortalToggle.test.tsx b/src/components/LoginPortalToggle/LoginPortalToggle.spec.tsx
similarity index 92%
rename from src/components/LoginPortalToggle/LoginPortalToggle.test.tsx
rename to src/components/LoginPortalToggle/LoginPortalToggle.spec.tsx
index 327e6cccea..eee24f6376 100644
--- a/src/components/LoginPortalToggle/LoginPortalToggle.test.tsx
+++ b/src/components/LoginPortalToggle/LoginPortalToggle.spec.tsx
@@ -6,6 +6,7 @@ import { I18nextProvider } from 'react-i18next';
import LoginPortalToggle from './LoginPortalToggle';
import { store } from 'state/store';
import i18nForTest from 'utils/i18nForTest';
+import { describe, test, vi } from 'vitest';
async function wait(ms = 100): Promise {
await act(() => {
@@ -17,7 +18,7 @@ async function wait(ms = 100): Promise {
describe('Testing LoginPortalToggle component', () => {
test('Component Should be rendered properly', async () => {
- const mockOnToggle = jest.fn();
+ const mockOnToggle = vi.fn();
render(
From ad6ca7c673c7d8bf75933cf705a5f1b1c3c40506 Mon Sep 17 00:00:00 2001
From: MANDEEP N H <146331633+mandeepnh5@users.noreply.github.com>
Date: Wed, 25 Dec 2024 15:52:02 +0530
Subject: [PATCH 089/133] Update member request card jest to vitest (#2859)
---
.../{MemberRequestCard.test.tsx => MemberRequestCard.spec.tsx} | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
rename src/components/MemberRequestCard/{MemberRequestCard.test.tsx => MemberRequestCard.spec.tsx} (97%)
diff --git a/src/components/MemberRequestCard/MemberRequestCard.test.tsx b/src/components/MemberRequestCard/MemberRequestCard.spec.tsx
similarity index 97%
rename from src/components/MemberRequestCard/MemberRequestCard.test.tsx
rename to src/components/MemberRequestCard/MemberRequestCard.spec.tsx
index a38a046ea2..5779d3688a 100644
--- a/src/components/MemberRequestCard/MemberRequestCard.test.tsx
+++ b/src/components/MemberRequestCard/MemberRequestCard.spec.tsx
@@ -11,6 +11,7 @@ import {
import MemberRequestCard from './MemberRequestCard';
import i18nForTest from 'utils/i18nForTest';
import { StaticMockLink } from 'utils/StaticMockLink';
+import { describe, vi, expect } from 'vitest';
const MOCKS = [
{
@@ -65,7 +66,7 @@ describe('Testing Member Request Card', () => {
email: 'johndoe@gmail.com',
};
- global.alert = jest.fn();
+ global.alert = vi.fn();
it('should render props and text elements test for the page component', async () => {
global.confirm = (): boolean => true;
From 154588e4f8d50dfbb0dea21882790e9905105ab5 Mon Sep 17 00:00:00 2001
From: Ramneet Singh <144323012+Ramneet04@users.noreply.github.com>
Date: Wed, 25 Dec 2024 15:53:47 +0530
Subject: [PATCH 090/133] Refactor:
src/utils/timezoneUtils/dateTimeMiddleware.test.ts from Jest to Vitest
(#2775)
* file name changed
* migrated to vitest from jest
* handled the split function correctly
* added comments that were missing
---
...are.test.ts => dateTimeMiddleware.spec.ts} | 31 ++++++++++---------
src/utils/timezoneUtils/dateTimeMiddleware.ts | 20 +++++++-----
2 files changed, 29 insertions(+), 22 deletions(-)
rename src/utils/timezoneUtils/{dateTimeMiddleware.test.ts => dateTimeMiddleware.spec.ts} (92%)
diff --git a/src/utils/timezoneUtils/dateTimeMiddleware.test.ts b/src/utils/timezoneUtils/dateTimeMiddleware.spec.ts
similarity index 92%
rename from src/utils/timezoneUtils/dateTimeMiddleware.test.ts
rename to src/utils/timezoneUtils/dateTimeMiddleware.spec.ts
index b14702b546..ead19444c3 100644
--- a/src/utils/timezoneUtils/dateTimeMiddleware.test.ts
+++ b/src/utils/timezoneUtils/dateTimeMiddleware.spec.ts
@@ -3,6 +3,7 @@ import type { Operation, FetchResult } from '@apollo/client/core';
import { Observable } from '@apollo/client/core';
import { gql } from '@apollo/client';
import type { DocumentNode } from 'graphql';
+import { describe, it, expect, vi } from 'vitest';
const DUMMY_QUERY: DocumentNode = gql`
query GetDummyData {
@@ -19,12 +20,12 @@ describe('Date Time Middleware Tests', () => {
query: DUMMY_QUERY,
operationName: 'GetDummyData',
variables: { startDate: '2023-09-01', startTime: '12:00:00' },
- getContext: jest.fn(() => ({})),
- setContext: jest.fn(),
+ getContext: vi.fn(() => ({})),
+ setContext: vi.fn(),
extensions: {},
};
- const forward = jest.fn(
+ const forward = vi.fn(
(op) =>
new Observable((observer) => {
expect(op.variables['startDate']).toBe('2023-09-01');
@@ -55,12 +56,12 @@ describe('Date Time Middleware Tests', () => {
query: DUMMY_QUERY,
operationName: 'GetDummyData',
variables: {},
- getContext: jest.fn(() => ({})),
- setContext: jest.fn(),
+ getContext: vi.fn(() => ({})),
+ setContext: vi.fn(),
extensions: {},
};
- const forward = jest.fn(
+ const forward = vi.fn(
() =>
new Observable((observer) => {
observer.next(testResponse);
@@ -98,12 +99,12 @@ describe('Date Time Middleware Tests', () => {
query: DUMMY_QUERY,
operationName: 'GetDummyData',
variables: { startDate: 'not-a-date', startTime: '25:99:99' },
- getContext: jest.fn(() => ({})),
- setContext: jest.fn(),
+ getContext: vi.fn(() => ({})),
+ setContext: vi.fn(),
extensions: {},
};
- const forward = jest.fn(
+ const forward = vi.fn(
(op) =>
new Observable((observer) => {
expect(op.variables['startDate']).toBe('not-a-date');
@@ -130,12 +131,12 @@ describe('Date Time Middleware Tests', () => {
query: DUMMY_QUERY,
operationName: 'GetDummyData',
variables: {},
- getContext: jest.fn(() => ({})),
- setContext: jest.fn(),
+ getContext: vi.fn(() => ({})),
+ setContext: vi.fn(),
extensions: {},
};
- const forward = jest.fn(
+ const forward = vi.fn(
() =>
new Observable((observer) => {
observer.next(testResponse);
@@ -188,12 +189,12 @@ describe('Date Time Middleware Tests', () => {
},
},
},
- getContext: jest.fn(() => ({})),
- setContext: jest.fn(),
+ getContext: vi.fn(() => ({})),
+ setContext: vi.fn(),
extensions: {},
};
- const forward = jest.fn(
+ const forward = vi.fn(
(op) =>
new Observable((observer) => {
expect(op.variables.event.startDate).toBe('2023-10-01');
diff --git a/src/utils/timezoneUtils/dateTimeMiddleware.ts b/src/utils/timezoneUtils/dateTimeMiddleware.ts
index 70fc20a026..f3be59bacb 100644
--- a/src/utils/timezoneUtils/dateTimeMiddleware.ts
+++ b/src/utils/timezoneUtils/dateTimeMiddleware.ts
@@ -14,6 +14,13 @@ const combineDateTime = (date: string, time: string): string => {
const splitDateTime = (dateTimeStr: string): { date: string; time: string } => {
const dateTime = dayjs.utc(dateTimeStr);
+ if (!dateTime.isValid()) {
+ const [date, time] = dateTimeStr.split('T');
+ return {
+ date: date,
+ time: time,
+ };
+ }
return {
date: dateTime.format('YYYY-MM-DD'),
time: dateTime.format('HH:mm:ss.SSS[Z]'),
@@ -21,18 +28,17 @@ const splitDateTime = (dateTimeStr: string): { date: string; time: string } => {
};
const convertUTCToLocal = (dateStr: string): string => {
- if (dayjs(dateStr).isValid()) {
- return dayjs.utc(dateStr).local().format('YYYY-MM-DDTHH:mm:ss.SSS');
+ if (!dayjs(dateStr).isValid()) {
+ return dateStr;
}
- return dateStr;
+ return dayjs.utc(dateStr).local().format('YYYY-MM-DDTHH:mm:ss.SSS');
};
const convertLocalToUTC = (dateStr: string): string => {
- if (dayjs(dateStr).isValid()) {
- const result = dayjs(dateStr).utc().format('YYYY-MM-DDTHH:mm:ss.SSS[Z]');
- return result;
+ if (!dayjs(dateStr).isValid()) {
+ return dateStr; // Leave the invalid value unchanged
}
- return dateStr;
+ return dayjs(dateStr).utc().format('YYYY-MM-DDTHH:mm:ss.SSS[Z]');
};
const traverseAndConvertDates = (
From a62911b76a3a2b1d5e086835a6592eec1e88bf71 Mon Sep 17 00:00:00 2001
From: Vishnu Gurrapu
Date: Wed, 25 Dec 2024 15:55:25 +0530
Subject: [PATCH 091/133] fixed-2363 (#2860)
---
...gister.test.tsx => AddOnRegister.spec.tsx} | 29 +++++++++++--------
1 file changed, 17 insertions(+), 12 deletions(-)
rename src/components/AddOn/core/AddOnRegister/{AddOnRegister.test.tsx => AddOnRegister.spec.tsx} (89%)
diff --git a/src/components/AddOn/core/AddOnRegister/AddOnRegister.test.tsx b/src/components/AddOn/core/AddOnRegister/AddOnRegister.spec.tsx
similarity index 89%
rename from src/components/AddOn/core/AddOnRegister/AddOnRegister.test.tsx
rename to src/components/AddOn/core/AddOnRegister/AddOnRegister.spec.tsx
index dc6a7c2091..bbddef4fc7 100644
--- a/src/components/AddOn/core/AddOnRegister/AddOnRegister.test.tsx
+++ b/src/components/AddOn/core/AddOnRegister/AddOnRegister.spec.tsx
@@ -20,6 +20,7 @@ import i18nForTest from 'utils/i18nForTest';
import { I18nextProvider } from 'react-i18next';
import { toast } from 'react-toastify';
import useLocalStorage from 'utils/useLocalstorage';
+import { vi } from 'vitest';
const { getItem } = useLocalStorage();
@@ -74,26 +75,30 @@ const pluginData = {
pluginDesc: 'Test Description',
};
-jest.mock('react-toastify', () => ({
+vi.mock('react-toastify', () => ({
toast: {
- success: jest.fn(),
+ success: vi.fn(),
},
}));
-const mockNavigate = jest.fn();
+const mockNavigate = vi.fn();
let mockId: string | undefined = 'id';
-jest.mock('react-router-dom', () => ({
- ...jest.requireActual('react-router-dom'),
- useParams: () => ({ orgId: mockId }),
- useNavigate: () => mockNavigate,
-}));
+
+vi.mock('react-router-dom', async () => {
+ const actual = await import('react-router-dom');
+ return {
+ ...actual,
+ useParams: () => ({ orgId: mockId }),
+ useNavigate: () => mockNavigate,
+ };
+});
describe('Testing AddOnRegister', () => {
const props = {
id: '6234d8bf6ud937ddk70ecc5c9',
};
- test('should render modal and take info to add plugin for registered organization', async () => {
+ it('should render modal and take info to add plugin for registered organization', async () => {
await act(async () => {
render(
@@ -127,7 +132,7 @@ describe('Testing AddOnRegister', () => {
);
});
- test('Expect toast.success to be called on successful plugin addition', async () => {
+ it('Expect toast.success to be called on successful plugin addition', async () => {
await act(async () => {
render(
@@ -158,7 +163,7 @@ describe('Testing AddOnRegister', () => {
expect(toast.success).toHaveBeenCalledWith('Plugin added Successfully');
});
- test('Expect the window to reload after successful plugin addition', async () => {
+ it('Expect the window to reload after successful plugin addition', async () => {
await act(async () => {
render(
@@ -189,7 +194,7 @@ describe('Testing AddOnRegister', () => {
expect(mockNavigate).toHaveBeenCalledWith(0);
});
- test('should be redirected to /orglist if orgId is undefined', async () => {
+ it('should be redirected to /orglist if orgId is undefined', async () => {
mockId = undefined;
render(
From 471f113575515feb873f247dc7f16cfcbc548101 Mon Sep 17 00:00:00 2001
From: khushi santosh patil
<143253539+khushipatil1523@users.noreply.github.com>
Date: Wed, 25 Dec 2024 15:56:30 +0530
Subject: [PATCH 092/133] Refactor jest to vitest #2832 (#2861)
* convert test from jest to vitest
* convert test from jest to vitest
* convert test from jest to vitest
* convert test from jest to vitest
* convert test from jest to vitest
---
src/components/Loader/{Loader.test.tsx => Loader.spec.tsx} | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
rename src/components/Loader/{Loader.test.tsx => Loader.spec.tsx} (76%)
diff --git a/src/components/Loader/Loader.test.tsx b/src/components/Loader/Loader.spec.tsx
similarity index 76%
rename from src/components/Loader/Loader.test.tsx
rename to src/components/Loader/Loader.spec.tsx
index c512b480e3..ab312a9155 100644
--- a/src/components/Loader/Loader.test.tsx
+++ b/src/components/Loader/Loader.spec.tsx
@@ -1,23 +1,24 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import Loader from './Loader';
+import { describe, it, expect } from 'vitest';
describe('Testing Loader component', () => {
- test('Component should be rendered properly', () => {
+ it('Component should be rendered properly', () => {
render();
expect(screen.getByTestId('spinner-wrapper')).toBeInTheDocument();
expect(screen.getByTestId('spinner')).toBeInTheDocument();
});
- test('Component should render on custom sizes', () => {
+ it('Component should render on custom sizes', () => {
render();
expect(screen.getByTestId('spinner-wrapper')).toBeInTheDocument();
expect(screen.getByTestId('spinner')).toBeInTheDocument();
});
- test('Component should render with large size', () => {
+ it('Component should render with large size', () => {
render();
expect(screen.getByTestId('spinner-wrapper')).toBeInTheDocument();
From 87bfd94224e2f88b7edccf42f190c07b43067b2b Mon Sep 17 00:00:00 2001
From: Nikhil Raj <125121367+hustlernik@users.noreply.github.com>
Date: Thu, 26 Dec 2024 00:40:38 +0530
Subject: [PATCH 093/133] refactor: jest to vitest migration (#2864)
---
src/utils/chartToPdf.spec.ts | 153 +++++++++++++++++++++++++++++++
src/utils/chartToPdf.test.ts | 168 -----------------------------------
2 files changed, 153 insertions(+), 168 deletions(-)
create mode 100644 src/utils/chartToPdf.spec.ts
delete mode 100644 src/utils/chartToPdf.test.ts
diff --git a/src/utils/chartToPdf.spec.ts b/src/utils/chartToPdf.spec.ts
new file mode 100644
index 0000000000..e1ab67fdb0
--- /dev/null
+++ b/src/utils/chartToPdf.spec.ts
@@ -0,0 +1,153 @@
+import { expect, describe, test, beforeEach, afterEach, vi } from 'vitest';
+import type { Mock } from 'vitest';
+import {
+ exportToCSV,
+ exportTrendsToCSV,
+ exportDemographicsToCSV,
+} from './chartToPdf';
+
+describe('CSV Export Functions', () => {
+ // Define more specific types for our mocks
+ let mockCreateElement: Mock;
+ let mockAppendChild: Mock;
+ let mockRemoveChild: Mock;
+ let mockClick: Mock;
+ let mockSetAttribute: Mock;
+ let mockLink: HTMLAnchorElement;
+
+ beforeEach(() => {
+ // Mock URL methods with specific types
+ (global.URL.createObjectURL as unknown) = vi.fn(() => 'mock-url');
+ (global.URL.revokeObjectURL as unknown) = vi.fn();
+
+ // Mock DOM methods
+ mockSetAttribute = vi.fn();
+ mockClick = vi.fn();
+ mockLink = {
+ setAttribute: mockSetAttribute,
+ click: mockClick,
+ parentNode: document.body,
+ } as unknown as HTMLAnchorElement;
+
+ // Mock createElement with proper type assertion
+ mockCreateElement = vi.fn().mockReturnValue(mockLink);
+ document.createElement =
+ mockCreateElement as unknown as typeof document.createElement;
+
+ // Mock appendChild and removeChild with proper type assertions
+ mockAppendChild = vi.fn().mockReturnValue(mockLink);
+ mockRemoveChild = vi.fn().mockReturnValue(mockLink);
+
+ document.body.appendChild =
+ mockAppendChild as unknown as typeof document.body.appendChild;
+ document.body.removeChild =
+ mockRemoveChild as unknown as typeof document.body.removeChild;
+ });
+
+ afterEach(() => {
+ vi.clearAllMocks();
+ });
+
+ test('exports data to CSV with proper formatting', () => {
+ const data: string[][] = [
+ ['Header1', 'Header2'],
+ ['Value1', 'Value2'],
+ ['Value with, comma', 'Value with "quotes"'],
+ ];
+
+ exportToCSV(data, 'test.csv');
+
+ expect(mockCreateElement).toHaveBeenCalledWith('a');
+ expect(mockSetAttribute).toHaveBeenCalledWith('href', 'mock-url');
+ expect(mockSetAttribute).toHaveBeenCalledWith('download', 'test.csv');
+ expect(mockAppendChild).toHaveBeenCalled();
+ expect(mockClick).toHaveBeenCalled();
+ expect(mockRemoveChild).toHaveBeenCalled();
+ expect(URL.revokeObjectURL).toHaveBeenCalledWith('mock-url');
+ });
+
+ test('throws error if data is empty', () => {
+ expect(() => exportToCSV([], 'test.csv')).toThrow('Data cannot be empty');
+ });
+
+ test('throws error if filename is empty', () => {
+ expect(() => exportToCSV([['data']], '')).toThrow('Filename is required');
+ });
+
+ test('adds .csv extension if missing', () => {
+ const data = [['test']];
+ exportToCSV(data, 'filename');
+ expect(mockSetAttribute).toHaveBeenCalledWith('download', 'filename.csv');
+ });
+
+ describe('exportTrendsToCSV', () => {
+ test('exports attendance trends data correctly', () => {
+ const eventLabels: string[] = ['Event1', 'Event2'];
+ const attendeeCounts: number[] = [10, 20];
+ const maleCounts: number[] = [5, 10];
+ const femaleCounts: number[] = [4, 8];
+ const otherCounts: number[] = [1, 2];
+
+ exportTrendsToCSV(
+ eventLabels,
+ attendeeCounts,
+ maleCounts,
+ femaleCounts,
+ otherCounts,
+ );
+
+ expect(mockCreateElement).toHaveBeenCalledWith('a');
+ expect(mockSetAttribute).toHaveBeenCalledWith(
+ 'download',
+ 'attendance_trends.csv',
+ );
+ expect(mockClick).toHaveBeenCalled();
+ });
+ });
+
+ describe('exportDemographicsToCSV', () => {
+ test('exports demographics data correctly', () => {
+ const selectedCategory = 'Age Groups';
+ const categoryLabels: string[] = ['0-18', '19-30', '31+'];
+ const categoryData: number[] = [10, 20, 15];
+
+ exportDemographicsToCSV(selectedCategory, categoryLabels, categoryData);
+
+ expect(mockCreateElement).toHaveBeenCalledWith('a');
+ expect(mockClick).toHaveBeenCalled();
+ expect(mockSetAttribute).toHaveBeenCalledWith('href', 'mock-url');
+ });
+
+ test('throws error if selected category is empty', () => {
+ expect(() => exportDemographicsToCSV('', ['label'], [1])).toThrow(
+ 'Selected category is required',
+ );
+ });
+
+ test('throws error if labels and data arrays have different lengths', () => {
+ expect(() =>
+ exportDemographicsToCSV('Category', ['label1', 'label2'], [1]),
+ ).toThrow('Labels and data arrays must have the same length');
+ });
+
+ test('creates safe filename with timestamp', () => {
+ vi.useFakeTimers();
+ const mockDate = new Date('2023-01-01T00:00:00.000Z');
+ vi.setSystemTime(mockDate);
+
+ const selectedCategory = 'Age & Demographics!';
+ const categoryLabels = ['Group1'];
+ const categoryData = [10];
+
+ exportDemographicsToCSV(selectedCategory, categoryLabels, categoryData);
+
+ const expectedFilename =
+ 'age___demographics__demographics_2023-01-01T00-00-00.000Z.csv';
+ const downloadCalls = mockSetAttribute.mock.calls.filter(
+ (call) => call[0] === 'download',
+ );
+ expect(downloadCalls[0][1]).toBe(expectedFilename);
+ vi.useRealTimers();
+ });
+ });
+});
diff --git a/src/utils/chartToPdf.test.ts b/src/utils/chartToPdf.test.ts
deleted file mode 100644
index b3094fff02..0000000000
--- a/src/utils/chartToPdf.test.ts
+++ /dev/null
@@ -1,168 +0,0 @@
-import {
- exportToCSV,
- exportTrendsToCSV,
- exportDemographicsToCSV,
-} from './chartToPdf';
-
-describe('CSV Export Functions', () => {
- let mockCreateElement: jest.SpyInstance;
- let mockClick: jest.SpyInstance;
- let mockSetAttribute: jest.SpyInstance;
-
- beforeEach(() => {
- // Mock URL methods
- global.URL.createObjectURL = jest.fn(() => 'mock-url');
- global.URL.revokeObjectURL = jest.fn();
-
- // Mock DOM methods
- mockSetAttribute = jest.fn();
- mockClick = jest.fn();
- const mockLink = {
- setAttribute: mockSetAttribute,
- click: mockClick,
- } as unknown as HTMLAnchorElement;
-
- mockCreateElement = jest
- .spyOn(document, 'createElement')
- .mockReturnValue(mockLink as HTMLAnchorElement);
- });
-
- afterEach(() => {
- jest.clearAllMocks();
- });
-
- describe('CSV Export Functions', () => {
- let mockCreateElement: jest.SpyInstance;
- let mockAppendChild: jest.SpyInstance;
- let mockRemoveChild: jest.SpyInstance;
- let mockClick: jest.SpyInstance;
- let mockSetAttribute: jest.SpyInstance;
-
- beforeEach(() => {
- // Mock URL methods
- global.URL.createObjectURL = jest.fn(() => 'mock-url');
- global.URL.revokeObjectURL = jest.fn();
-
- // Mock DOM methods
- mockSetAttribute = jest.fn();
- mockClick = jest.fn();
- const mockLink = {
- setAttribute: mockSetAttribute,
- click: mockClick,
- parentNode: document.body, // Add this to trigger removeChild
- } as unknown as HTMLAnchorElement;
-
- mockCreateElement = jest
- .spyOn(document, 'createElement')
- .mockReturnValue(mockLink as HTMLAnchorElement);
- mockAppendChild = jest
- .spyOn(document.body, 'appendChild')
- .mockImplementation(() => mockLink as HTMLAnchorElement);
- mockRemoveChild = jest
- .spyOn(document.body, 'removeChild')
- .mockImplementation(() => mockLink as HTMLAnchorElement);
- });
-
- test('exports data to CSV with proper formatting', () => {
- const data = [
- ['Header1', 'Header2'],
- ['Value1', 'Value2'],
- ['Value with, comma', 'Value with "quotes"'],
- ];
-
- exportToCSV(data, 'test.csv');
-
- expect(mockCreateElement).toHaveBeenCalledWith('a');
- expect(mockSetAttribute).toHaveBeenCalledWith('href', 'mock-url');
- expect(mockSetAttribute).toHaveBeenCalledWith('download', 'test.csv');
- expect(mockAppendChild).toHaveBeenCalled();
- expect(mockClick).toHaveBeenCalled();
- expect(mockRemoveChild).toHaveBeenCalled();
- expect(URL.revokeObjectURL).toHaveBeenCalledWith('mock-url');
- });
- test('throws error if data is empty', () => {
- expect(() => exportToCSV([], 'test.csv')).toThrow('Data cannot be empty');
- });
-
- test('throws error if filename is empty', () => {
- expect(() => exportToCSV([['data']], '')).toThrow('Filename is required');
- });
-
- test('adds .csv extension if missing', () => {
- const data = [['test']];
- exportToCSV(data, 'filename');
- expect(mockSetAttribute).toHaveBeenCalledWith('download', 'filename.csv');
- });
- });
-
- describe('exportTrendsToCSV', () => {
- test('exports attendance trends data correctly', () => {
- const eventLabels = ['Event1', 'Event2'];
- const attendeeCounts = [10, 20];
- const maleCounts = [5, 10];
- const femaleCounts = [4, 8];
- const otherCounts = [1, 2];
-
- exportTrendsToCSV(
- eventLabels,
- attendeeCounts,
- maleCounts,
- femaleCounts,
- otherCounts,
- );
-
- expect(mockCreateElement).toHaveBeenCalledWith('a');
- expect(mockSetAttribute).toHaveBeenCalledWith(
- 'download',
- 'attendance_trends.csv',
- );
- expect(mockClick).toHaveBeenCalled();
- });
- });
-
- describe('exportDemographicsToCSV', () => {
- test('exports demographics data correctly', () => {
- const selectedCategory = 'Age Groups';
- const categoryLabels = ['0-18', '19-30', '31+'];
- const categoryData = [10, 20, 15];
-
- exportDemographicsToCSV(selectedCategory, categoryLabels, categoryData);
-
- expect(mockCreateElement).toHaveBeenCalledWith('a');
- expect(mockClick).toHaveBeenCalled();
- expect(mockSetAttribute).toHaveBeenCalledWith('href', 'mock-url');
- });
-
- test('throws error if selected category is empty', () => {
- expect(() => exportDemographicsToCSV('', ['label'], [1])).toThrow(
- 'Selected category is required',
- );
- });
-
- test('throws error if labels and data arrays have different lengths', () => {
- expect(() =>
- exportDemographicsToCSV('Category', ['label1', 'label2'], [1]),
- ).toThrow('Labels and data arrays must have the same length');
- });
-
- test('creates safe filename with timestamp', () => {
- jest.useFakeTimers();
- const mockDate = new Date('2023-01-01T00:00:00.000Z');
- jest.setSystemTime(mockDate);
-
- const selectedCategory = 'Age & Demographics!';
- const categoryLabels = ['Group1'];
- const categoryData = [10];
-
- exportDemographicsToCSV(selectedCategory, categoryLabels, categoryData);
-
- const expectedFilename =
- 'age___demographics__demographics_2023-01-01T00-00-00.000Z.csv';
- const downloadCalls = mockSetAttribute.mock.calls.filter(
- (call) => call[0] === 'download',
- );
- expect(downloadCalls[0][1]).toBe(expectedFilename);
- jest.useRealTimers();
- });
- });
-});
From 34a60d0a2a61c942e8fb615e0538f1686e4e8498 Mon Sep 17 00:00:00 2001
From: Nikhil Raj <125121367+hustlernik@users.noreply.github.com>
Date: Thu, 26 Dec 2024 00:42:28 +0530
Subject: [PATCH 094/133] refactor: jest to vitest migration for
askForCustomPort.test.ts (#2867)
---
...mPort.test.ts => askForCustomPort.spec.ts} | 48 +++++++++----------
1 file changed, 22 insertions(+), 26 deletions(-)
rename src/setup/askForCustomPort/{askForCustomPort.test.ts => askForCustomPort.spec.ts} (69%)
diff --git a/src/setup/askForCustomPort/askForCustomPort.test.ts b/src/setup/askForCustomPort/askForCustomPort.spec.ts
similarity index 69%
rename from src/setup/askForCustomPort/askForCustomPort.test.ts
rename to src/setup/askForCustomPort/askForCustomPort.spec.ts
index c46f7b3f91..08e67cec00 100644
--- a/src/setup/askForCustomPort/askForCustomPort.test.ts
+++ b/src/setup/askForCustomPort/askForCustomPort.spec.ts
@@ -1,33 +1,34 @@
+import { describe, it, expect, vi, beforeEach } from 'vitest';
import inquirer from 'inquirer';
import { askForCustomPort, validatePort } from './askForCustomPort';
-jest.mock('inquirer');
+vi.mock('inquirer');
describe('askForCustomPort', () => {
beforeEach(() => {
- jest.clearAllMocks();
+ vi.clearAllMocks();
});
describe('basic port validation', () => {
- test('should return default port if user provides no input', async () => {
- jest
- .spyOn(inquirer, 'prompt')
- .mockResolvedValueOnce({ customPort: '4321' });
+ it('should return default port if user provides no input', async () => {
+ vi.spyOn(inquirer, 'prompt').mockResolvedValueOnce({
+ customPort: '4321',
+ });
const result = await askForCustomPort();
expect(result).toBe(4321);
});
- test('should return user-provided port', async () => {
- jest
- .spyOn(inquirer, 'prompt')
- .mockResolvedValueOnce({ customPort: '8080' });
+ it('should return user-provided port', async () => {
+ vi.spyOn(inquirer, 'prompt').mockResolvedValueOnce({
+ customPort: '8080',
+ });
const result = await askForCustomPort();
expect(result).toBe(8080);
});
- test('should return validation error if port not between 1 and 65535', () => {
+ it('should return validation error if port not between 1 and 65535', () => {
expect(validatePort('abcd')).toBe(
'Please enter a valid port number between 1 and 65535.',
);
@@ -41,9 +42,8 @@ describe('askForCustomPort', () => {
});
describe('retry mechanism', () => {
- test('should handle invalid port input and prompt again', async () => {
- jest
- .spyOn(inquirer, 'prompt')
+ it('should handle invalid port input and prompt again', async () => {
+ vi.spyOn(inquirer, 'prompt')
.mockResolvedValueOnce({ customPort: 'abcd' })
.mockResolvedValueOnce({ customPort: '8080' });
@@ -51,9 +51,8 @@ describe('askForCustomPort', () => {
expect(result).toBe(8080);
});
- test('should return default port after maximum retry attempts', async () => {
- jest
- .spyOn(inquirer, 'prompt')
+ it('should return default port after maximum retry attempts', async () => {
+ vi.spyOn(inquirer, 'prompt')
.mockResolvedValueOnce({ customPort: 'invalid-port-attempt1' })
.mockResolvedValueOnce({ customPort: 'invalid-port-attempt2' })
.mockResolvedValueOnce({ customPort: 'invalid-port-attempt3' })
@@ -67,9 +66,8 @@ describe('askForCustomPort', () => {
});
describe('reserved ports', () => {
- test('should return user-provided port after confirming reserved port', async () => {
- jest
- .spyOn(inquirer, 'prompt')
+ it('should return user-provided port after confirming reserved port', async () => {
+ vi.spyOn(inquirer, 'prompt')
.mockResolvedValueOnce({ customPort: '80' })
.mockResolvedValueOnce({ confirmPort: true });
@@ -77,9 +75,8 @@ describe('askForCustomPort', () => {
expect(result).toBe(80);
});
- test('should re-prompt user for port if reserved port confirmation is denied', async () => {
- jest
- .spyOn(inquirer, 'prompt')
+ it('should re-prompt user for port if reserved port confirmation is denied', async () => {
+ vi.spyOn(inquirer, 'prompt')
.mockResolvedValueOnce({ customPort: '80' })
.mockResolvedValueOnce({ confirmPort: false })
.mockResolvedValueOnce({ customPort: '8080' });
@@ -88,9 +85,8 @@ describe('askForCustomPort', () => {
expect(result).toBe(8080);
});
- test('should return default port if reserved port confirmation is denied after maximum retry attempts', async () => {
- jest
- .spyOn(inquirer, 'prompt')
+ it('should return default port if reserved port confirmation is denied after maximum retry attempts', async () => {
+ vi.spyOn(inquirer, 'prompt')
.mockResolvedValueOnce({ customPort: '80' })
.mockResolvedValueOnce({ confirmPort: false })
.mockResolvedValueOnce({ customPort: '80' })
From 9eef34ca1450c6b77899ee3f3c438147b061b70f Mon Sep 17 00:00:00 2001
From: Abhishek Raj <113784630+abbi4code@users.noreply.github.com>
Date: Thu, 26 Dec 2024 00:45:02 +0530
Subject: [PATCH 095/133] updateSession tests migrated from jest to vitest
(#2863)
---
...ession.test.tsx => UpdateSession.spec.tsx} | 67 ++++++++++---------
1 file changed, 34 insertions(+), 33 deletions(-)
rename src/components/UpdateSession/{UpdateSession.test.tsx => UpdateSession.spec.tsx} (81%)
diff --git a/src/components/UpdateSession/UpdateSession.test.tsx b/src/components/UpdateSession/UpdateSession.spec.tsx
similarity index 81%
rename from src/components/UpdateSession/UpdateSession.test.tsx
rename to src/components/UpdateSession/UpdateSession.spec.tsx
index ce0a868820..3453c990c2 100644
--- a/src/components/UpdateSession/UpdateSession.test.tsx
+++ b/src/components/UpdateSession/UpdateSession.spec.tsx
@@ -1,16 +1,7 @@
import React from 'react';
import { MockedProvider } from '@apollo/client/testing';
-import {
- render,
- screen,
- act,
- within,
- fireEvent,
- waitFor,
-} from '@testing-library/react';
+import { render, screen, act, within } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import 'jest-localstorage-mock';
-import 'jest-location-mock';
import { I18nextProvider } from 'react-i18next';
import { BrowserRouter } from 'react-router-dom';
import { toast } from 'react-toastify';
@@ -19,6 +10,18 @@ import i18n from 'utils/i18nForTest';
import { GET_COMMUNITY_SESSION_TIMEOUT_DATA } from 'GraphQl/Queries/Queries';
import { UPDATE_SESSION_TIMEOUT } from 'GraphQl/Mutations/mutations';
import { errorHandler } from 'utils/errorHandler';
+import { vi } from 'vitest';
+/**
+ * This file contains unit tests for the `UpdateSession` component.
+ *
+ * The tests cover:
+ * - Proper rendering of the component with different scenarios, including mock data, null values, and error states.
+ * - Handling user interactions with the slider, such as setting minimum, maximum, and intermediate values.
+ * - Ensuring callbacks (e.g., `onValueChange`) are triggered correctly based on user input.
+ * - Simulating GraphQL query and mutation operations using mocked data to verify correct behavior in successful and error cases.
+ * - Testing edge cases, including null community data, invalid input values, and API errors, ensuring the component handles them gracefully.
+ * - Verifying proper integration of internationalization, routing, and toast notifications for success or error messages.
+ */
const MOCKS = [
{
@@ -66,31 +69,29 @@ async function wait(ms = 100): Promise {
});
}
-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(),
},
}));
-jest.mock('utils/errorHandler', () => ({
- errorHandler: jest.fn(),
+vi.mock('utils/errorHandler', () => ({
+ errorHandler: vi.fn(),
}));
describe('Testing UpdateTimeout Component', () => {
- let consoleWarnSpy: jest.SpyInstance;
-
beforeEach(() => {
- consoleWarnSpy = jest.spyOn(console, 'warn').mockImplementation();
+ vi.spyOn(console, 'warn').mockImplementation(() => {});
});
afterEach(() => {
- jest.clearAllMocks();
+ vi.clearAllMocks();
});
- test('Should handle minimum slider value correctly', async () => {
- const mockOnValueChange = jest.fn();
+ it('Should handle minimum slider value correctly', async () => {
+ const mockOnValueChange = vi.fn();
render(
@@ -109,8 +110,8 @@ describe('Testing UpdateTimeout Component', () => {
expect(mockOnValueChange).toHaveBeenCalledWith(15); // Adjust based on slider min value
});
- test('Should handle maximum slider value correctly', async () => {
- const mockOnValueChange = jest.fn();
+ it('Should handle maximum slider value correctly', async () => {
+ const mockOnValueChange = vi.fn();
render(
@@ -129,8 +130,8 @@ describe('Testing UpdateTimeout Component', () => {
expect(mockOnValueChange).toHaveBeenCalledWith(60); // Adjust based on slider max value
});
- test('Should not update value if an invalid value is passed', async () => {
- const mockOnValueChange = jest.fn();
+ it('Should not update value if an invalid value is passed', async () => {
+ const mockOnValueChange = vi.fn();
render(
@@ -150,8 +151,8 @@ describe('Testing UpdateTimeout Component', () => {
expect(mockOnValueChange).not.toHaveBeenCalled();
});
- test('Should update slider value on user interaction', async () => {
- const mockOnValueChange = jest.fn();
+ it('Should update slider value on user interaction', async () => {
+ const mockOnValueChange = vi.fn();
render(
@@ -169,7 +170,7 @@ describe('Testing UpdateTimeout Component', () => {
expect(mockOnValueChange).toHaveBeenCalledWith(expect.any(Number)); // Adjust as needed
});
- test('Components should render properly', async () => {
+ it('Components should render properly', async () => {
render(
@@ -203,7 +204,7 @@ describe('Testing UpdateTimeout Component', () => {
expect(screen.getByRole('button', { name: /Update/i })).toBeInTheDocument();
});
- test('Should update session timeout', async () => {
+ it('Should update session timeout', async () => {
render(
@@ -228,7 +229,7 @@ describe('Testing UpdateTimeout Component', () => {
);
});
- test('Should handle query errors', async () => {
+ it('Should handle query errors', async () => {
const errorMocks = [
{
request: {
@@ -253,7 +254,7 @@ describe('Testing UpdateTimeout Component', () => {
expect(errorHandler).toHaveBeenCalled();
});
- test('Should handle update errors', async () => {
+ it('Should handle update errors', async () => {
const errorMocks = [
{
request: {
@@ -306,7 +307,7 @@ describe('Testing UpdateTimeout Component', () => {
expect(errorHandler).toHaveBeenCalled();
});
- test('Should handle null community object gracefully', async () => {
+ it('Should handle null community object gracefully', async () => {
render(
From 8dd63e92be14182566ed061737349f3b658cb63d Mon Sep 17 00:00:00 2001
From: Pratap Rathi
Date: Thu, 26 Dec 2024 01:06:25 +0530
Subject: [PATCH 096/133] Refactor: Migrated
src/components/NotFound/NotFound.test.tsx from Jest to Vitest (#2866)
---
.../NotFound/{NotFound.test.tsx => NotFound.spec.tsx} | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
rename src/components/NotFound/{NotFound.test.tsx => NotFound.spec.tsx} (94%)
diff --git a/src/components/NotFound/NotFound.test.tsx b/src/components/NotFound/NotFound.spec.tsx
similarity index 94%
rename from src/components/NotFound/NotFound.test.tsx
rename to src/components/NotFound/NotFound.spec.tsx
index 54c0bcfe4a..a70e355f7a 100644
--- a/src/components/NotFound/NotFound.test.tsx
+++ b/src/components/NotFound/NotFound.spec.tsx
@@ -1,9 +1,9 @@
import React from 'react';
import { I18nextProvider } from 'react-i18next';
import i18nForTest from 'utils/i18nForTest';
-
import { render, screen } from '@testing-library/react';
import NotFound from './NotFound';
+import { expect, it, describe } from 'vitest';
describe('Tesing the NotFound Component', () => {
it('renders the component with the correct title for posts', () => {
From c57559ea5fd44be1a605d52caa0168c105b47b75 Mon Sep 17 00:00:00 2001
From: Pratap Rathi
Date: Thu, 26 Dec 2024 01:07:21 +0530
Subject: [PATCH 097/133] Migrated src/components/EventListCard from Jest to
Vitest (#2853)
* Refactor: Migrated src/components/EventListCard/EventListCard.test.tsx from Jest to Vitest
* Removed all istanbul ignore comments
---
...stCard.test.tsx => EventListCard.spec.tsx} | 60 +++++++++----------
.../EventListCard/EventListCardModals.tsx | 9 +--
2 files changed, 32 insertions(+), 37 deletions(-)
rename src/components/EventListCard/{EventListCard.test.tsx => EventListCard.spec.tsx} (92%)
diff --git a/src/components/EventListCard/EventListCard.test.tsx b/src/components/EventListCard/EventListCard.spec.tsx
similarity index 92%
rename from src/components/EventListCard/EventListCard.test.tsx
rename to src/components/EventListCard/EventListCard.spec.tsx
index afe81f436e..e0c6cc825f 100644
--- a/src/components/EventListCard/EventListCard.test.tsx
+++ b/src/components/EventListCard/EventListCard.spec.tsx
@@ -17,16 +17,17 @@ import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
import useLocalStorage from 'utils/useLocalstorage';
import { props } from './EventListCardProps';
import { ERROR_MOCKS, MOCKS } from './EventListCardMocks';
+import { vi, beforeAll, afterAll, expect, it } from 'vitest';
const { setItem } = useLocalStorage();
const link = new StaticMockLink(MOCKS, true);
const link2 = new StaticMockLink(ERROR_MOCKS, true);
-jest.mock('react-toastify', () => ({
+vi.mock('react-toastify', () => ({
toast: {
- success: jest.fn(),
- error: jest.fn(),
+ success: vi.fn(),
+ error: vi.fn(),
},
}));
@@ -101,18 +102,17 @@ describe('Testing Event List Card', () => {
};
beforeAll(() => {
- jest.mock('react-router-dom', () => ({
- ...jest.requireActual('react-router-dom'),
- useParams: () => ({ orgId: 'orgId' }),
+ vi.mock('react-router-dom', async () => ({
+ ...(await vi.importActual('react-router-dom')),
}));
});
afterAll(() => {
localStorage.clear();
- jest.clearAllMocks();
+ vi.clearAllMocks();
});
- test('Testing for event modal', async () => {
+ it('Testing for event modal', async () => {
renderEventListCard(props[1]);
userEvent.click(screen.getByTestId('card'));
@@ -129,7 +129,7 @@ describe('Testing Event List Card', () => {
});
});
- test('Should navigate to "/" if orgId is not defined', async () => {
+ it('Should navigate to "/" if orgId is not defined', async () => {
render(
@@ -163,7 +163,7 @@ describe('Testing Event List Card', () => {
});
});
- test('Should render default text if event details are null', async () => {
+ it('Should render default text if event details are null', async () => {
renderEventListCard(props[0]);
await waitFor(() => {
@@ -171,7 +171,7 @@ describe('Testing Event List Card', () => {
});
});
- test('should render props and text elements test for the screen', async () => {
+ it('should render props and text elements test for the screen', async () => {
renderEventListCard(props[1]);
expect(screen.getByText(props[1].eventName)).toBeInTheDocument();
@@ -198,7 +198,7 @@ describe('Testing Event List Card', () => {
});
});
- test('Should render truncated event name when length is more than 100', async () => {
+ it('Should render truncated event name when length is more than 100', async () => {
const longEventName = 'a'.repeat(101);
renderEventListCard({ ...props[1], eventName: longEventName });
@@ -221,7 +221,7 @@ describe('Testing Event List Card', () => {
});
});
- test('Should render full event name when length is less than or equal to 100', async () => {
+ it('Should render full event name when length is less than or equal to 100', async () => {
const shortEventName = 'a'.repeat(100);
renderEventListCard({ ...props[1], eventName: shortEventName });
@@ -242,7 +242,7 @@ describe('Testing Event List Card', () => {
});
});
- test('Should render truncated event description when length is more than 256', async () => {
+ it('Should render truncated event description when length is more than 256', async () => {
const longEventDescription = 'a'.repeat(257);
renderEventListCard({
@@ -268,7 +268,7 @@ describe('Testing Event List Card', () => {
});
});
- test('Should render full event description when length is less than or equal to 256', async () => {
+ it('Should render full event description when length is less than or equal to 256', async () => {
const shortEventDescription = 'a'.repeat(256);
renderEventListCard({
@@ -294,7 +294,7 @@ describe('Testing Event List Card', () => {
});
});
- test('Should navigate to event dashboard when clicked (For Admin)', async () => {
+ it('Should navigate to event dashboard when clicked (For Admin)', async () => {
renderEventListCard(props[1]);
userEvent.click(screen.getByTestId('card'));
@@ -311,7 +311,7 @@ describe('Testing Event List Card', () => {
});
});
- test('Should navigate to event dashboard when clicked (For User)', async () => {
+ it('Should navigate to event dashboard when clicked (For User)', async () => {
setItem('userId', '123');
renderEventListCard(props[2]);
@@ -329,7 +329,7 @@ describe('Testing Event List Card', () => {
});
});
- test('Should update a non-recurring event', async () => {
+ it('Should update a non-recurring event', async () => {
renderEventListCard(props[1]);
userEvent.click(screen.getByTestId('card'));
@@ -372,7 +372,7 @@ describe('Testing Event List Card', () => {
});
});
- test('Should update a non all day non-recurring event', async () => {
+ it('Should update a non all day non-recurring event', async () => {
renderEventListCard(props[1]);
userEvent.click(screen.getByTestId('card'));
@@ -425,7 +425,7 @@ describe('Testing Event List Card', () => {
});
});
- test('should update a single event to be recurring', async () => {
+ it('should update a single event to be recurring', async () => {
renderEventListCard(props[1]);
userEvent.click(screen.getByTestId('card'));
@@ -469,7 +469,7 @@ describe('Testing Event List Card', () => {
});
});
- test('should show different update options for a recurring event based on different conditions', async () => {
+ it('should show different update options for a recurring event based on different conditions', async () => {
renderEventListCard(props[5]);
userEvent.click(screen.getByTestId('card'));
@@ -595,7 +595,7 @@ describe('Testing Event List Card', () => {
});
});
- test('should show recurrenceRule as changed if the recurrence weekdays have changed', async () => {
+ it('should show recurrenceRule as changed if the recurrence weekdays have changed', async () => {
renderEventListCard(props[4]);
userEvent.click(screen.getByTestId('card'));
@@ -656,7 +656,7 @@ describe('Testing Event List Card', () => {
});
});
- test('should update all instances of a recurring event', async () => {
+ it('should update all instances of a recurring event', async () => {
renderEventListCard(props[6]);
userEvent.click(screen.getByTestId('card'));
@@ -706,7 +706,7 @@ describe('Testing Event List Card', () => {
});
});
- test('should update thisAndFollowingInstances of a recurring event', async () => {
+ it('should update thisAndFollowingInstances of a recurring event', async () => {
renderEventListCard(props[5]);
userEvent.click(screen.getByTestId('card'));
@@ -772,7 +772,7 @@ describe('Testing Event List Card', () => {
});
});
- test('should render the delete modal', async () => {
+ it('should render the delete modal', async () => {
renderEventListCard(props[1]);
userEvent.click(screen.getByTestId('card'));
@@ -807,7 +807,7 @@ describe('Testing Event List Card', () => {
});
});
- test('should call the delete event mutation when the "Yes" button is clicked', async () => {
+ it('should call the delete event mutation when the "Yes" button is clicked', async () => {
renderEventListCard(props[1]);
userEvent.click(screen.getByTestId('card'));
@@ -833,7 +833,7 @@ describe('Testing Event List Card', () => {
});
});
- test('select different delete options on recurring events & then delete the recurring event', async () => {
+ it('select different delete options on recurring events & then delete the recurring event', async () => {
renderEventListCard(props[4]);
await wait();
@@ -873,7 +873,7 @@ describe('Testing Event List Card', () => {
});
});
- test('should show an error toast when the delete event mutation fails', async () => {
+ it('should show an error toast when the delete event mutation fails', async () => {
// Destructure key from props[1] and pass it separately to avoid spreading it
const { key, ...otherProps } = props[1];
render(
@@ -908,7 +908,7 @@ describe('Testing Event List Card', () => {
});
});
- test('handle register should work properly', async () => {
+ it('handle register should work properly', async () => {
setItem('userId', '456');
renderEventListCard(props[2]);
@@ -933,7 +933,7 @@ describe('Testing Event List Card', () => {
});
});
- test('should show already registered text when the user is registered for an event', async () => {
+ it('should show already registered text when the user is registered for an event', async () => {
renderEventListCard(props[3]);
userEvent.click(screen.getByTestId('card'));
diff --git a/src/components/EventListCard/EventListCardModals.tsx b/src/components/EventListCard/EventListCardModals.tsx
index 193890941c..7755da2a5a 100644
--- a/src/components/EventListCard/EventListCardModals.tsx
+++ b/src/components/EventListCard/EventListCardModals.tsx
@@ -292,7 +292,6 @@ function EventListCardModals({
}
}
} catch (error: unknown) {
- /* istanbul ignore next */
errorHandler(t, error);
}
};
@@ -362,7 +361,6 @@ function EventListCardModals({
hideViewModal();
}
} catch (error: unknown) {
- /* istanbul ignore next */
errorHandler(t, error);
}
}
@@ -491,9 +489,7 @@ function EventListCardModals({
recurrenceStartDate: date?.toDate(),
weekDays: [Days[date?.toDate().getDay()]],
weekDayOccurenceInMonth: weekDayOccurenceInMonth
- ? /* istanbul ignore next */ getWeekDayOccurenceInMonth(
- date?.toDate(),
- )
+ ? getWeekDayOccurenceInMonth(date?.toDate())
: undefined,
});
}
@@ -531,8 +527,7 @@ function EventListCardModals({
endTime:
timeToDayJs(formState.endTime) < time
? time?.format('HH:mm:ss')
- : /* istanbul ignore next */
- formState.endTime,
+ : formState.endTime,
});
}
}}
From 5feefcdd102836b1d5cfb32eb4f44751cb540d2a Mon Sep 17 00:00:00 2001
From: Ramneet Singh <144323012+Ramneet04@users.noreply.github.com>
Date: Thu, 26 Dec 2024 01:08:50 +0530
Subject: [PATCH 098/133] Refactor
src/components/CollapsibleDropdown/CollapsibleDropdown.test.tsx from Jest to
Vitest #2809 (#2868)
* file name changed
* migrated from jest to vitest
---
....test.tsx => CollapsibleDropdown.spec.tsx} | 34 +++++++++++++------
1 file changed, 23 insertions(+), 11 deletions(-)
rename src/components/CollapsibleDropdown/{CollapsibleDropdown.test.tsx => CollapsibleDropdown.spec.tsx} (87%)
diff --git a/src/components/CollapsibleDropdown/CollapsibleDropdown.test.tsx b/src/components/CollapsibleDropdown/CollapsibleDropdown.spec.tsx
similarity index 87%
rename from src/components/CollapsibleDropdown/CollapsibleDropdown.test.tsx
rename to src/components/CollapsibleDropdown/CollapsibleDropdown.spec.tsx
index efee248ffb..b288fb9de5 100644
--- a/src/components/CollapsibleDropdown/CollapsibleDropdown.test.tsx
+++ b/src/components/CollapsibleDropdown/CollapsibleDropdown.spec.tsx
@@ -8,21 +8,33 @@ import { store } from 'state/store';
import { Provider } from 'react-redux';
import { I18nextProvider } from 'react-i18next';
import i18nForTest from 'utils/i18nForTest';
+import { describe, expect, test, vi, afterEach } from 'vitest';
+import type { Location } from '@remix-run/router';
-jest.mock('react-router-dom', () => ({
- ...jest.requireActual('react-router-dom'),
- useLocation: () => ({
- pathname: '/orgstore',
- state: {},
- key: '',
- search: '',
- hash: '',
- }),
-}));
+afterEach(() => {
+ vi.resetModules();
+});
+
+const currentLocation: Location = {
+ pathname: '/orgstore',
+ state: {},
+ key: '',
+ search: '',
+ hash: '',
+};
+
+vi.mock('react-router-dom', async (importOriginal) => {
+ const mod = (await importOriginal()) as object;
+
+ return {
+ ...mod,
+ useLocation: () => currentLocation,
+ };
+});
const props: InterfaceCollapsibleDropdown = {
showDropdown: true,
- setShowDropdown: jest.fn(),
+ setShowDropdown: vi.fn(),
target: {
name: 'DropDown Category',
url: undefined,
From b9693d56741babba5a729d57277338f471b6c2c3 Mon Sep 17 00:00:00 2001
From: Pranav Nathe <93403830+pranavnathe@users.noreply.github.com>
Date: Thu, 26 Dec 2024 01:10:14 +0530
Subject: [PATCH 099/133] Refactor tests to use Vitest (#2869)
---
.../{DeleteUser.test.tsx => DeleteUser.spec.tsx} | 3 ++-
.../{OtherSettings.test.tsx => OtherSettings.spec.tsx} | 3 ++-
.../{UserProfile.test.tsx => UserProfile.spec.tsx} | 3 ++-
3 files changed, 6 insertions(+), 3 deletions(-)
rename src/components/UserProfileSettings/{DeleteUser.test.tsx => DeleteUser.spec.tsx} (90%)
rename src/components/UserProfileSettings/{OtherSettings.test.tsx => OtherSettings.spec.tsx} (89%)
rename src/components/UserProfileSettings/{UserProfile.test.tsx => UserProfile.spec.tsx} (92%)
diff --git a/src/components/UserProfileSettings/DeleteUser.test.tsx b/src/components/UserProfileSettings/DeleteUser.spec.tsx
similarity index 90%
rename from src/components/UserProfileSettings/DeleteUser.test.tsx
rename to src/components/UserProfileSettings/DeleteUser.spec.tsx
index 34ab44fbe5..d089d82607 100644
--- a/src/components/UserProfileSettings/DeleteUser.test.tsx
+++ b/src/components/UserProfileSettings/DeleteUser.spec.tsx
@@ -5,9 +5,10 @@ import { BrowserRouter } from 'react-router-dom';
import { I18nextProvider } from 'react-i18next';
import i18nForTest from 'utils/i18nForTest';
import DeleteUser from './DeleteUser';
+import { describe, it, expect } from 'vitest';
describe('Delete User component', () => {
- test('renders delete user correctly', () => {
+ it('renders delete user correctly', () => {
const { getByText, getAllByText } = render(
diff --git a/src/components/UserProfileSettings/OtherSettings.test.tsx b/src/components/UserProfileSettings/OtherSettings.spec.tsx
similarity index 89%
rename from src/components/UserProfileSettings/OtherSettings.test.tsx
rename to src/components/UserProfileSettings/OtherSettings.spec.tsx
index 990a430931..490ad2322c 100644
--- a/src/components/UserProfileSettings/OtherSettings.test.tsx
+++ b/src/components/UserProfileSettings/OtherSettings.spec.tsx
@@ -5,9 +5,10 @@ import { BrowserRouter } from 'react-router-dom';
import { I18nextProvider } from 'react-i18next';
import i18nForTest from 'utils/i18nForTest';
import OtherSettings from './OtherSettings';
+import { describe, it, expect } from 'vitest';
describe('Delete User component', () => {
- test('renders delete user correctly', () => {
+ it('renders delete user correctly', () => {
const { getByText } = render(
diff --git a/src/components/UserProfileSettings/UserProfile.test.tsx b/src/components/UserProfileSettings/UserProfile.spec.tsx
similarity index 92%
rename from src/components/UserProfileSettings/UserProfile.test.tsx
rename to src/components/UserProfileSettings/UserProfile.spec.tsx
index 82caad5d81..dbf7987789 100644
--- a/src/components/UserProfileSettings/UserProfile.test.tsx
+++ b/src/components/UserProfileSettings/UserProfile.spec.tsx
@@ -5,9 +5,10 @@ import { MockedProvider } from '@apollo/react-testing';
import { BrowserRouter } from 'react-router-dom';
import { I18nextProvider } from 'react-i18next';
import i18nForTest from 'utils/i18nForTest';
+import { describe, it, expect } from 'vitest';
describe('UserProfile component', () => {
- test('renders user profile details correctly', () => {
+ it('renders user profile details correctly', () => {
const userDetails = {
firstName: 'Christopher',
lastName: 'Doe',
From c42135bdca221a9eb04af9a91b648a78add892bf Mon Sep 17 00:00:00 2001
From: Rahul Chougule <87270395+rahulch07@users.noreply.github.com>
Date: Thu, 26 Dec 2024 01:12:46 +0530
Subject: [PATCH 100/133] Refactor
src/components/RequestsTableItem/RequestsTableItem.test.tsx from Jest to
Vitest (#2873)
---
...em.test.tsx => RequestsTableItem.spec.tsx} | 85 ++++++++++++++++---
.../RequestsTableItemMocks.ts | 8 +-
2 files changed, 79 insertions(+), 14 deletions(-)
rename src/components/RequestsTableItem/{RequestsTableItem.test.tsx => RequestsTableItem.spec.tsx} (62%)
diff --git a/src/components/RequestsTableItem/RequestsTableItem.test.tsx b/src/components/RequestsTableItem/RequestsTableItem.spec.tsx
similarity index 62%
rename from src/components/RequestsTableItem/RequestsTableItem.test.tsx
rename to src/components/RequestsTableItem/RequestsTableItem.spec.tsx
index bbd895300b..b5194fcdce 100644
--- a/src/components/RequestsTableItem/RequestsTableItem.test.tsx
+++ b/src/components/RequestsTableItem/RequestsTableItem.spec.tsx
@@ -11,6 +11,7 @@ import { BrowserRouter } from 'react-router-dom';
const link = new StaticMockLink(MOCKS, true);
import useLocalStorage from 'utils/useLocalstorage';
import userEvent from '@testing-library/user-event';
+import { vi } from 'vitest';
const { setItem } = useLocalStorage();
@@ -21,13 +22,13 @@ 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(),
},
}));
@@ -37,17 +38,17 @@ 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;
}
console.warn(message);
});
- test('Should render props and text elements test for the page component', async () => {
+ it('Should render props and text elements it for the page component', async () => {
const props: {
request: InterfaceRequestsListItem;
index: number;
@@ -81,7 +82,7 @@ describe('Testing User Table Item', () => {
expect(screen.getByText(/john@example.com/i)).toBeInTheDocument();
});
- test('Accept MembershipRequest Button works properly', async () => {
+ it('Accept MembershipRequest Button works properly', async () => {
const props: {
request: InterfaceRequestsListItem;
index: number;
@@ -113,7 +114,39 @@ describe('Testing User Table Item', () => {
userEvent.click(screen.getByTestId('acceptMembershipRequestBtn123'));
});
- test('Reject MembershipRequest Button works properly', async () => {
+ it('Accept MembershipRequest handles error', async () => {
+ const props: {
+ request: InterfaceRequestsListItem;
+ index: number;
+ resetAndRefetch: () => void;
+ } = {
+ request: {
+ _id: '1',
+ user: {
+ firstName: 'John',
+ lastName: 'Doe',
+ email: 'john@example.com',
+ },
+ },
+ index: 1,
+ resetAndRefetch: resetAndRefetchMock,
+ };
+
+ render(
+
+
+
+
+
+
+ ,
+ );
+
+ await wait();
+ userEvent.click(screen.getByTestId('acceptMembershipRequestBtn1'));
+ });
+
+ it('Reject MembershipRequest Button works properly', async () => {
const props: {
request: InterfaceRequestsListItem;
index: number;
@@ -144,4 +177,36 @@ describe('Testing User Table Item', () => {
await wait();
userEvent.click(screen.getByTestId('rejectMembershipRequestBtn123'));
});
+
+ it('Reject MembershipRequest handles error', async () => {
+ const props: {
+ request: InterfaceRequestsListItem;
+ index: number;
+ resetAndRefetch: () => void;
+ } = {
+ request: {
+ _id: '1',
+ user: {
+ firstName: 'John',
+ lastName: 'Doe',
+ email: 'john@example.com',
+ },
+ },
+ index: 1,
+ resetAndRefetch: resetAndRefetchMock,
+ };
+
+ render(
+
+
+
+
+
+
+ ,
+ );
+
+ await wait();
+ userEvent.click(screen.getByTestId('rejectMembershipRequestBtn1'));
+ });
});
diff --git a/src/components/RequestsTableItem/RequestsTableItemMocks.ts b/src/components/RequestsTableItem/RequestsTableItemMocks.ts
index 22ea245d3a..22bd61d0ac 100644
--- a/src/components/RequestsTableItem/RequestsTableItemMocks.ts
+++ b/src/components/RequestsTableItem/RequestsTableItemMocks.ts
@@ -8,13 +8,13 @@ export const MOCKS = [
request: {
query: ACCEPT_ORGANIZATION_REQUEST_MUTATION,
variables: {
- id: '1',
+ id: '123',
},
},
result: {
data: {
acceptMembershipRequest: {
- _id: '1',
+ _id: '123',
},
},
},
@@ -23,13 +23,13 @@ export const MOCKS = [
request: {
query: REJECT_ORGANIZATION_REQUEST_MUTATION,
variables: {
- id: '1',
+ id: '123',
},
},
result: {
data: {
rejectMembershipRequest: {
- _id: '1',
+ _id: '123',
},
},
},
From 5c7fcd7665bcea6b126bc6d67684fad4184a25dc Mon Sep 17 00:00:00 2001
From: Shiva <148421597+shivasankaran18@users.noreply.github.com>
Date: Thu, 26 Dec 2024 01:15:53 +0530
Subject: [PATCH 101/133] refactor:vitest to src/state/* (#2870)
---
.../action-creators/{index.test.ts => index.spec.ts} | 9 +++++----
src/state/helpers/{Action.test.ts => Action.spec.ts} | 7 +++++--
.../{pluginReducer.test.ts => pluginReducer.spec.ts} | 0
.../{routesReducer.test.ts => routesReducer.spec.ts} | 0
...RoutersReducer.test.ts => userRoutersReducer.spec.ts} | 0
src/state/{store.test.tsx => store.spec.tsx} | 0
6 files changed, 10 insertions(+), 6 deletions(-)
rename src/state/action-creators/{index.test.ts => index.spec.ts} (90%)
rename src/state/helpers/{Action.test.ts => Action.spec.ts} (53%)
rename src/state/reducers/{pluginReducer.test.ts => pluginReducer.spec.ts} (100%)
rename src/state/reducers/{routesReducer.test.ts => routesReducer.spec.ts} (100%)
rename src/state/reducers/{userRoutersReducer.test.ts => userRoutersReducer.spec.ts} (100%)
rename src/state/{store.test.tsx => store.spec.tsx} (100%)
diff --git a/src/state/action-creators/index.test.ts b/src/state/action-creators/index.spec.ts
similarity index 90%
rename from src/state/action-creators/index.test.ts
rename to src/state/action-creators/index.spec.ts
index 33aa642b8a..141eb679d9 100644
--- a/src/state/action-creators/index.test.ts
+++ b/src/state/action-creators/index.spec.ts
@@ -1,3 +1,4 @@
+import { vi } from 'vitest';
import {
updateInstalled,
installPlugin,
@@ -10,7 +11,7 @@ describe('Testing rc/state/action-creators/index.ts', () => {
const temp = updateInstalled('testPlug');
expect(typeof temp).toBe('function');
//stubbing the childfunction to check execution
- const childFunction = jest.fn();
+ const childFunction = vi.fn();
temp(childFunction);
expect(childFunction).toHaveBeenCalled();
});
@@ -20,7 +21,7 @@ describe('Testing rc/state/action-creators/index.ts', () => {
const temp = installPlugin('testPlug');
expect(typeof temp).toBe('function');
//stubbing the childfunction to check execution
- const childFunction = jest.fn();
+ const childFunction = vi.fn();
temp(childFunction);
expect(childFunction).toHaveBeenCalled();
});
@@ -30,7 +31,7 @@ describe('Testing rc/state/action-creators/index.ts', () => {
const temp = removePlugin('testPlug');
expect(typeof temp).toBe('function');
//stubbing the childfunction to check execution
- const childFunction = jest.fn();
+ const childFunction = vi.fn();
temp(childFunction);
expect(childFunction).toHaveBeenCalled();
});
@@ -40,7 +41,7 @@ describe('Testing rc/state/action-creators/index.ts', () => {
const temp = updatePluginLinks('testPlug');
expect(typeof temp).toBe('function');
//stubbing the childfunction to check execution
- const childFunction = jest.fn();
+ const childFunction = vi.fn();
temp(childFunction);
expect(childFunction).toHaveBeenCalled();
});
diff --git a/src/state/helpers/Action.test.ts b/src/state/helpers/Action.spec.ts
similarity index 53%
rename from src/state/helpers/Action.test.ts
rename to src/state/helpers/Action.spec.ts
index a971c6c160..cc81153617 100644
--- a/src/state/helpers/Action.test.ts
+++ b/src/state/helpers/Action.spec.ts
@@ -1,8 +1,11 @@
import type { InterfaceAction } from './Action';
test('Testing Reducer Action Interface', () => {
- ({
+ const action = {
type: 'STRING_ACTION_TYPE',
payload: 'ANY_PAYLOAD',
- }) as InterfaceAction;
+ } as InterfaceAction;
+
+ expect(action.type).toBe('STRING_ACTION_TYPE');
+ expect(action.payload).toBe('ANY_PAYLOAD');
});
diff --git a/src/state/reducers/pluginReducer.test.ts b/src/state/reducers/pluginReducer.spec.ts
similarity index 100%
rename from src/state/reducers/pluginReducer.test.ts
rename to src/state/reducers/pluginReducer.spec.ts
diff --git a/src/state/reducers/routesReducer.test.ts b/src/state/reducers/routesReducer.spec.ts
similarity index 100%
rename from src/state/reducers/routesReducer.test.ts
rename to src/state/reducers/routesReducer.spec.ts
diff --git a/src/state/reducers/userRoutersReducer.test.ts b/src/state/reducers/userRoutersReducer.spec.ts
similarity index 100%
rename from src/state/reducers/userRoutersReducer.test.ts
rename to src/state/reducers/userRoutersReducer.spec.ts
diff --git a/src/state/store.test.tsx b/src/state/store.spec.tsx
similarity index 100%
rename from src/state/store.test.tsx
rename to src/state/store.spec.tsx
From 22436b5f3a79fae2d6ac32edd4d09dd3c94d9a9b Mon Sep 17 00:00:00 2001
From: Ramneet Singh <144323012+Ramneet04@users.noreply.github.com>
Date: Thu, 26 Dec 2024 02:19:54 +0530
Subject: [PATCH 102/133] Refactor
src/components/SuperAdminScreen/SuperAdminScreen.test.tsx from Jest to Vitest
#2820 (#2874)
* file name changed
* migrated jest to vitest
---
.../{SuperAdminScreen.test.tsx => SuperAdminScreen.spec.tsx} | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
rename src/components/SuperAdminScreen/{SuperAdminScreen.test.tsx => SuperAdminScreen.spec.tsx} (97%)
diff --git a/src/components/SuperAdminScreen/SuperAdminScreen.test.tsx b/src/components/SuperAdminScreen/SuperAdminScreen.spec.tsx
similarity index 97%
rename from src/components/SuperAdminScreen/SuperAdminScreen.test.tsx
rename to src/components/SuperAdminScreen/SuperAdminScreen.spec.tsx
index 84b740ab12..53804a54db 100644
--- a/src/components/SuperAdminScreen/SuperAdminScreen.test.tsx
+++ b/src/components/SuperAdminScreen/SuperAdminScreen.spec.tsx
@@ -1,13 +1,13 @@
import React from 'react';
import { MockedProvider } from '@apollo/react-testing';
import { fireEvent, render, screen } 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 { store } from 'state/store';
import i18nForTest from 'utils/i18nForTest';
import SuperAdminScreen from './SuperAdminScreen';
+import { describe, test, expect } from 'vitest';
const resizeWindow = (width: number): void => {
window.innerWidth = width;
From 979d584897e6caa168ef8ac91bc26e889d38fd00 Mon Sep 17 00:00:00 2001
From: Mayank Jha <132004139+MayankJha014@users.noreply.github.com>
Date: Thu, 26 Dec 2024 03:43:51 +0530
Subject: [PATCH 103/133] OrganizationCardStart to vitest (#2876)
---
...tionCardStart.test.tsx => OrganizationCardStart.spec.tsx} | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
rename src/components/OrganizationCardStart/{OrganizationCardStart.test.tsx => OrganizationCardStart.spec.tsx} (76%)
diff --git a/src/components/OrganizationCardStart/OrganizationCardStart.test.tsx b/src/components/OrganizationCardStart/OrganizationCardStart.spec.tsx
similarity index 76%
rename from src/components/OrganizationCardStart/OrganizationCardStart.test.tsx
rename to src/components/OrganizationCardStart/OrganizationCardStart.spec.tsx
index dd65c8649e..71263fb65b 100644
--- a/src/components/OrganizationCardStart/OrganizationCardStart.test.tsx
+++ b/src/components/OrganizationCardStart/OrganizationCardStart.spec.tsx
@@ -1,9 +1,10 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import OrganizationCardStart from './OrganizationCardStart';
+import { describe, expect } from 'vitest';
describe('Testing the Organization Cards', () => {
- test('should render props and text elements test for the page component', () => {
+ it('should render props and text elements test for the page component', () => {
const props = {
id: '123',
image: 'https://via.placeholder.com/80',
@@ -15,7 +16,7 @@ describe('Testing the Organization Cards', () => {
expect(screen.getByText(props.name)).toBeInTheDocument();
});
- test('Should render text elements when props value is not passed', () => {
+ it('Should render text elements when props value is not passed', () => {
const props = {
id: '123',
image: '',
From e2177047a5fed03588a2a53a6dc7b39153b153b5 Mon Sep 17 00:00:00 2001
From: Rahul Chougule <87270395+rahulch07@users.noreply.github.com>
Date: Thu, 26 Dec 2024 03:46:47 +0530
Subject: [PATCH 104/133] Refactored jest to vitest #2825 (#2877)
* refactored Jest to Vitest
* removed jest file
---
...e.test.tsx => UserPasswordUpdate.spec.tsx} | 104 ++++++++++++------
.../UserPasswordUpdateMocks.ts | 40 +++++++
2 files changed, 113 insertions(+), 31 deletions(-)
rename src/components/UserPasswordUpdate/{UserPasswordUpdate.test.tsx => UserPasswordUpdate.spec.tsx} (58%)
create mode 100644 src/components/UserPasswordUpdate/UserPasswordUpdateMocks.ts
diff --git a/src/components/UserPasswordUpdate/UserPasswordUpdate.test.tsx b/src/components/UserPasswordUpdate/UserPasswordUpdate.spec.tsx
similarity index 58%
rename from src/components/UserPasswordUpdate/UserPasswordUpdate.test.tsx
rename to src/components/UserPasswordUpdate/UserPasswordUpdate.spec.tsx
index 65f5e40f76..0d704eaed8 100644
--- a/src/components/UserPasswordUpdate/UserPasswordUpdate.test.tsx
+++ b/src/components/UserPasswordUpdate/UserPasswordUpdate.spec.tsx
@@ -1,43 +1,22 @@
import React, { act } from 'react';
-import { render, screen } from '@testing-library/react';
+import { render, screen, waitFor } from '@testing-library/react';
import { MockedProvider } from '@apollo/react-testing';
import userEvent from '@testing-library/user-event';
import { I18nextProvider } from 'react-i18next';
-import { UPDATE_USER_PASSWORD_MUTATION } from 'GraphQl/Mutations/mutations';
import i18nForTest from 'utils/i18nForTest';
import UserPasswordUpdate from './UserPasswordUpdate';
import { StaticMockLink } from 'utils/StaticMockLink';
import { toast as mockToast } from 'react-toastify';
+import { MOCKS } from './UserPasswordUpdateMocks';
+import { vi } from 'vitest';
-jest.mock('react-toastify', () => ({
+vi.mock('react-toastify', () => ({
toast: {
- error: jest.fn(),
- success: jest.fn(),
+ error: vi.fn(),
+ success: vi.fn(),
},
}));
-const MOCKS = [
- {
- request: {
- query: UPDATE_USER_PASSWORD_MUTATION,
- variables: {
- previousPassword: 'anshgoyal',
- newPassword: 'anshgoyalansh',
- confirmNewPassword: 'anshgoyalansh',
- },
- },
- result: {
- data: {
- users: [
- {
- _id: '1',
- },
- ],
- },
- },
- },
-];
-
const link = new StaticMockLink(MOCKS, true);
async function wait(ms = 5): Promise {
@@ -56,9 +35,9 @@ describe('Testing User Password Update', () => {
confirmNewPassword: 'ThePalisadoesFoundation',
};
- global.alert = jest.fn();
+ global.alert = vi.fn();
- test('should render props and text elements test for the page component', async () => {
+ it('should render props and text elements it for the page component', async () => {
render(
@@ -93,7 +72,7 @@ describe('Testing User Password Update', () => {
).toBeInTheDocument();
});
- test('displays an error when the password field is empty', async () => {
+ it('displays an error when the password field is empty', async () => {
render(
@@ -108,7 +87,7 @@ describe('Testing User Password Update', () => {
expect(mockToast.error).toHaveBeenCalledWith(`Password can't be empty`);
});
- test('displays an error when new and confirm password field does not match', async () => {
+ it('displays an error when new and confirm password field does not match', async () => {
render(
@@ -140,4 +119,67 @@ describe('Testing User Password Update', () => {
'New and Confirm password do not match.',
);
});
+
+ it('Successfully update old password', async () => {
+ render(
+
+
+
+
+ ,
+ );
+
+ await wait();
+
+ userEvent.type(
+ screen.getByPlaceholderText(/Previous Password/i),
+ formData.previousPassword,
+ );
+ userEvent.type(
+ screen.getAllByPlaceholderText(/New Password/i)[0],
+ formData.newPassword,
+ );
+ userEvent.type(
+ screen.getByPlaceholderText(/Confirm New Password/i),
+ formData.confirmNewPassword,
+ );
+
+ userEvent.click(screen.getByText(/Save Changes/i));
+ expect(mockToast.success).toHaveBeenCalledWith(
+ 'Password updated Successfully',
+ );
+ });
+
+ it('wrong old password', async () => {
+ render(
+
+
+
+
+ ,
+ );
+
+ // await wait();
+
+ userEvent.type(
+ screen.getByPlaceholderText(/Previous Password/i),
+ formData.wrongPassword,
+ );
+ userEvent.type(
+ screen.getAllByPlaceholderText(/New Password/i)[0],
+ formData.newPassword,
+ );
+ userEvent.type(
+ screen.getByPlaceholderText(/Confirm New Password/i),
+ formData.confirmNewPassword,
+ );
+
+ userEvent.click(screen.getByText(/Save Changes/i));
+
+ await waitFor(() =>
+ expect(mockToast.error).toHaveBeenCalledWith(
+ 'ApolloError: Invalid previous password',
+ ),
+ );
+ });
});
diff --git a/src/components/UserPasswordUpdate/UserPasswordUpdateMocks.ts b/src/components/UserPasswordUpdate/UserPasswordUpdateMocks.ts
new file mode 100644
index 0000000000..634286f590
--- /dev/null
+++ b/src/components/UserPasswordUpdate/UserPasswordUpdateMocks.ts
@@ -0,0 +1,40 @@
+import { UPDATE_USER_PASSWORD_MUTATION } from 'GraphQl/Mutations/mutations';
+
+export const MOCKS = [
+ {
+ request: {
+ query: UPDATE_USER_PASSWORD_MUTATION,
+ variables: {
+ previousPassword: 'Palisadoes',
+ newPassword: 'ThePalisadoesFoundation',
+ confirmNewPassword: 'ThePalisadoesFoundation',
+ },
+ },
+ result: {
+ data: {
+ users: [
+ {
+ _id: '1',
+ },
+ ],
+ },
+ },
+ },
+ {
+ request: {
+ query: UPDATE_USER_PASSWORD_MUTATION,
+ variables: {
+ previousPassword: 'This is wrong password',
+ newPassword: 'ThePalisadoesFoundation',
+ confirmNewPassword: 'ThePalisadoesFoundation',
+ },
+ },
+ result: {
+ errors: [
+ {
+ message: 'Invalid previous password',
+ },
+ ],
+ },
+ },
+];
From 8bc57607a98a06f2dc39144317f6f009b29de8e1 Mon Sep 17 00:00:00 2001
From: Abhishek Raj <113784630+abbi4code@users.noreply.github.com>
Date: Thu, 26 Dec 2024 03:47:26 +0530
Subject: [PATCH 105/133] OrgPostCard tests migrated from jest to vitest
(#2878)
---
...PostCard.test.tsx => OrgPostCard.spec.tsx} | 139 +++++++++++-------
1 file changed, 86 insertions(+), 53 deletions(-)
rename src/components/OrgPostCard/{OrgPostCard.test.tsx => OrgPostCard.spec.tsx} (86%)
diff --git a/src/components/OrgPostCard/OrgPostCard.test.tsx b/src/components/OrgPostCard/OrgPostCard.spec.tsx
similarity index 86%
rename from src/components/OrgPostCard/OrgPostCard.test.tsx
rename to src/components/OrgPostCard/OrgPostCard.spec.tsx
index 7105e5e8f2..5364766aee 100644
--- a/src/components/OrgPostCard/OrgPostCard.test.tsx
+++ b/src/components/OrgPostCard/OrgPostCard.spec.tsx
@@ -10,7 +10,6 @@ import { MockedProvider } from '@apollo/react-testing';
import OrgPostCard from './OrgPostCard';
import { I18nextProvider } from 'react-i18next';
import userEvent from '@testing-library/user-event';
-import 'jest-localstorage-mock';
import {
DELETE_POST_MUTATION,
UPDATE_POST_MUTATION,
@@ -21,6 +20,36 @@ import { StaticMockLink } from 'utils/StaticMockLink';
import convertToBase64 from 'utils/convertToBase64';
import { BrowserRouter } from 'react-router-dom';
import useLocalStorage from 'utils/useLocalstorage';
+import { vi } from 'vitest';
+
+/**
+ * Unit tests for the OrgPostCard component, which displays organization posts with various interactions.
+ *
+ * These tests verify:
+ * - Basic rendering and display functionality:
+ * - Proper rendering of post content (title, text, images, videos)
+ * - "Read more" toggle button behavior
+ * - Image and video display handling
+ * - Fallback behavior when media is missing
+ *
+ * - Modal interactions:
+ * - Opening/closing primary modal on post click
+ * - Secondary modal functionality for edit/delete operations
+ * - Form validation in edit modal
+ * - Media upload handling in edit modal
+ *
+ * - Post management operations:
+ * - Creating and updating posts
+ * - Deleting posts
+ * - Pinning/unpinning posts
+ * - Error handling for failed operations
+ *
+ * - Media handling:
+ * - Image upload and preview
+ * - Video upload and preview
+ * - Auto-play behavior on hover
+ * - Clearing uploaded media
+ */
const { setItem } = useLocalStorage();
@@ -71,19 +100,23 @@ 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(),
},
}));
-jest.mock('i18next-browser-languagedetector', () => ({
- init: jest.fn(),
- type: 'languageDetector',
- detect: jest.fn(() => 'en'),
- cacheUserLanguage: jest.fn(),
-}));
+vi.mock('i18next-browser-languagedetector', () => {
+ return {
+ default: {
+ init: vi.fn(),
+ type: 'languageDetector',
+ detect: vi.fn(() => 'en'),
+ cacheUserLanguage: vi.fn(),
+ },
+ };
+});
const link = new StaticMockLink(MOCKS, true);
async function wait(ms = 100): Promise {
await act(() => {
@@ -99,7 +132,7 @@ describe('Testing Organization Post Card', () => {
Object.defineProperty(window, 'location', {
configurable: true,
value: {
- reload: jest.fn(),
+ reload: vi.fn(),
},
});
});
@@ -122,20 +155,16 @@ describe('Testing Organization Post Card', () => {
pinned: false,
};
- 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(),
},
}));
- jest.mock('react', () => ({
- ...jest.requireActual('react'),
- useRef: jest.fn(),
- }));
- global.alert = jest.fn();
+ global.alert = vi.fn();
- test('Opens post on image click', () => {
+ it('Opens post on image click', () => {
const { getByTestId, getByAltText } = render(
@@ -149,7 +178,7 @@ describe('Testing Organization Post Card', () => {
expect(getByTestId('card-title')).toBeInTheDocument();
expect(getByAltText('image')).toBeInTheDocument();
});
- test('renders with default props', () => {
+ it('renders with default props', () => {
const { getByAltText, getByTestId } = render(
@@ -161,7 +190,7 @@ describe('Testing Organization Post Card', () => {
expect(getByTestId('card-title')).toBeInTheDocument();
expect(getByAltText('image')).toBeInTheDocument();
});
- test('toggles "Read more" button', () => {
+ it('toggles "Read more" button', () => {
const { getByTestId } = render(
@@ -176,7 +205,7 @@ describe('Testing Organization Post Card', () => {
fireEvent.click(toggleButton);
expect(toggleButton).toHaveTextContent('Read more');
});
- test('opens and closes edit modal', async () => {
+ it('opens and closes edit modal', async () => {
setItem('id', '123');
render(
@@ -196,7 +225,7 @@ describe('Testing Organization Post Card', () => {
userEvent.click(createOrgBtn);
userEvent.click(screen.getByTestId('closeOrganizationModal'));
});
- test('Should render text elements when props value is not passed', async () => {
+ it('Should render text elements when props value is not passed', async () => {
global.confirm = (): boolean => false;
render(
@@ -209,7 +238,7 @@ describe('Testing Organization Post Card', () => {
userEvent.click(screen.getByAltText('image'));
expect(screen.getByAltText('Post Image')).toBeInTheDocument();
});
- test('Testing post updating after post is updated', async () => {
+ it('Testing post updating after post is updated', async () => {
const { getByTestId } = render(
@@ -265,7 +294,7 @@ describe('Testing Organization Post Card', () => {
await waitFor(() => {
convertToBase64(file); // Replace with the expected base64-encoded image
});
- document.getElementById = jest.fn(() => input);
+ document.getElementById = vi.fn(() => input);
const clearImageButton = getByTestId('closeimage');
fireEvent.click(clearImageButton);
}
@@ -278,7 +307,7 @@ describe('Testing Organization Post Card', () => {
{ timeout: 2500 },
);
});
- test('Testing post updating functionality fail case', async () => {
+ it('Testing post updating functionality fail case', async () => {
const props2 = {
id: '',
postID: '123',
@@ -343,7 +372,7 @@ describe('Testing Organization Post Card', () => {
await waitFor(() => {
convertToBase64(file); // Replace with the expected base64-encoded image
});
- document.getElementById = jest.fn(() => input);
+ document.getElementById = vi.fn(() => input);
const clearImageButton = getByTestId('closeimage');
fireEvent.click(clearImageButton);
}
@@ -356,7 +385,7 @@ describe('Testing Organization Post Card', () => {
{ timeout: 2500 },
);
});
- test('Testing pin post functionality', async () => {
+ it('Testing pin post functionality', async () => {
render(
@@ -378,7 +407,7 @@ describe('Testing Organization Post Card', () => {
{ timeout: 3000 },
);
});
- test('Testing pin post functionality fail case', async () => {
+ it('Testing pin post functionality fail case', async () => {
const props2 = {
id: '',
postID: '123',
@@ -403,7 +432,7 @@ describe('Testing Organization Post Card', () => {
userEvent.click(screen.getByTestId('moreiconbtn'));
userEvent.click(screen.getByTestId('pinpostBtn'));
});
- test('Testing post delete functionality', async () => {
+ it('Testing post delete functionality', async () => {
render(
@@ -429,7 +458,7 @@ describe('Testing Organization Post Card', () => {
{ timeout: 3000 },
);
});
- test('Testing post delete functionality fail case', async () => {
+ it('Testing post delete functionality fail case', async () => {
const props2 = {
id: '',
postID: '123',
@@ -458,7 +487,7 @@ describe('Testing Organization Post Card', () => {
userEvent.click(screen.getByTestId('deletePostModalBtn'));
fireEvent.click(screen.getByTestId('deletePostBtn'));
});
- test('Testing close functionality of primary modal', async () => {
+ it('Testing close functionality of primary modal', async () => {
render(
@@ -475,7 +504,7 @@ describe('Testing Organization Post Card', () => {
//Primary Modal is closed
expect(screen.queryByTestId('moreiconbtn')).not.toBeInTheDocument();
});
- test('Testing close functionality of secondary modal', async () => {
+ it('Testing close functionality of secondary modal', async () => {
render(
@@ -496,7 +525,7 @@ describe('Testing Organization Post Card', () => {
expect(screen.queryByTestId('pinpostBtn')).not.toBeInTheDocument();
expect(screen.queryByTestId('closebtn')).not.toBeInTheDocument();
});
- test('renders without "Read more" button when postInfo length is less than or equal to 43', () => {
+ it('renders without "Read more" button when postInfo length is less than or equal to 43', () => {
render(
@@ -506,7 +535,7 @@ describe('Testing Organization Post Card', () => {
);
expect(screen.queryByTestId('toggleBtn')).not.toBeInTheDocument();
});
- test('renders with "Read more" button when postInfo length is more than 43', () => {
+ it('renders with "Read more" button when postInfo length is more than 43', () => {
const props2 = {
id: '12',
postID: '123',
@@ -529,7 +558,7 @@ describe('Testing Organization Post Card', () => {
expect(screen.getByTestId('toggleBtn')).toBeInTheDocument();
});
- test('updates state variables correctly when handleEditModal is called', () => {
+ it('updates state variables correctly when handleEditModal is called', () => {
const link2 = new StaticMockLink(MOCKS, true);
render(
@@ -555,7 +584,7 @@ describe('Testing Organization Post Card', () => {
expect(screen.queryByTestId('pinpostBtn')).not.toBeInTheDocument();
expect(screen.queryByTestId('closebtn')).not.toBeInTheDocument();
});
- test('updates state variables correctly when handleDeleteModal is called', () => {
+ it('updates state variables correctly when handleDeleteModal is called', () => {
const link2 = new StaticMockLink(MOCKS, true);
render(
@@ -581,7 +610,7 @@ describe('Testing Organization Post Card', () => {
expect(screen.queryByTestId('pinpostBtn')).not.toBeInTheDocument();
expect(screen.queryByTestId('closebtn')).not.toBeInTheDocument();
});
- test('clears postvideo state and resets file input value', async () => {
+ it('clears postvideo state and resets file input value', async () => {
const { getByTestId } = render(
@@ -615,7 +644,7 @@ describe('Testing Organization Post Card', () => {
userEvent.click(screen.getByTestId('closePreview'));
}
});
- test('clears postimage state and resets file input value', async () => {
+ it('clears postimage state and resets file input value', async () => {
const { getByTestId } = render(
@@ -647,12 +676,12 @@ describe('Testing Organization Post Card', () => {
await waitFor(() => {
convertToBase64(file); // Replace with the expected base64-encoded image
});
- document.getElementById = jest.fn(() => input);
+ document.getElementById = vi.fn(() => input);
const clearImageButton = getByTestId('closeimage');
fireEvent.click(clearImageButton);
}
});
- test('clears postitle state and resets file input value', async () => {
+ it('clears postitle state and resets file input value', async () => {
const { getByTestId } = render(
@@ -677,7 +706,7 @@ describe('Testing Organization Post Card', () => {
expect(screen.getByTestId('closeOrganizationModal')).toBeInTheDocument();
expect(screen.getByTestId('updatePostBtn')).toBeInTheDocument();
});
- test('clears postinfo state and resets file input value', async () => {
+ it('clears postinfo state and resets file input value', async () => {
const { getByTestId } = render(
@@ -702,7 +731,7 @@ describe('Testing Organization Post Card', () => {
expect(screen.getByTestId('closeOrganizationModal')).toBeInTheDocument();
expect(screen.getByTestId('updatePostBtn')).toBeInTheDocument();
});
- test('Testing create organization modal', async () => {
+ it('Testing create organization modal', async () => {
setItem('id', '123');
render(
@@ -724,7 +753,7 @@ describe('Testing Organization Post Card', () => {
userEvent.click(createOrgBtn);
userEvent.click(screen.getByTestId('closeOrganizationModal'));
});
- test('should toggle post pin when pin button is clicked', async () => {
+ it('should toggle post pin when pin button is clicked', async () => {
const { getByTestId } = render(
@@ -744,6 +773,12 @@ describe('Testing Organization Post Card', () => {
});
});
test('testing video play and pause on mouse enter and leave events', async () => {
+ const playMock = vi.fn();
+ const pauseMock = vi.fn();
+
+ HTMLMediaElement.prototype.play = playMock;
+ HTMLMediaElement.prototype.pause = pauseMock;
+
const { getByTestId } = render(
@@ -754,16 +789,14 @@ describe('Testing Organization Post Card', () => {
const card = getByTestId('cardVid');
- HTMLVideoElement.prototype.play = jest.fn();
- HTMLVideoElement.prototype.pause = jest.fn();
-
fireEvent.mouseEnter(card);
- expect(HTMLVideoElement.prototype.play).toHaveBeenCalled();
+ expect(playMock).toHaveBeenCalledTimes(1);
fireEvent.mouseLeave(card);
- expect(HTMLVideoElement.prototype.pause).toHaveBeenCalled();
+ expect(pauseMock).toHaveBeenCalledTimes(1);
});
- test('for rendering when no image and no video is available', async () => {
+
+ it('for rendering when no image and no video is available', async () => {
const props2 = {
id: '',
postID: '123',
From 3209a185e8923c0f047a5e7c46f7a12dc2096eca Mon Sep 17 00:00:00 2001
From: Syed Ali Ul Hasan
Date: Thu, 26 Dec 2024 05:58:45 +0530
Subject: [PATCH 106/133] Added Event Registrants Tab under Event Management
Dashboard (#2804)
* added event registrants under event management
* modified eslintrc.json to ignore .svg
* added language support
* increased code coverage and migrated test to vitest
* removed individual css files for the components
---------
Co-authored-by: Peter Harrison <16875803+palisadoes@users.noreply.github.com>
---
.eslintrc.json | 8 +-
package-lock.json | 1565 ++++++++++++++++-
package.json | 1 +
public/images/svg/options-outline.svg | 11 +
public/images/svg/organization.svg | 16 +
public/locales/en/translation.json | 11 +
public/locales/fr/translation.json | 11 +
public/locales/hi/translation.json | 11 +
public/locales/sp/translation.json | 12 +
public/locales/zh/translation.json | 11 +
src/GraphQl/Queries/Queries.ts | 10 +
.../CheckIn/CheckInWrapper.module.css | 13 -
src/components/CheckIn/CheckInWrapper.tsx | 19 +-
src/components/CheckIn/tagTemplate.ts | 7 +-
.../EventRegistrant/EventRegistrants.spec.tsx | 264 +++
.../EventRegistrant/EventRegistrants.tsx | 227 +++
.../EventRegistrant/Registrations.mocks.ts | 67 +
.../EventRegistrantsWrapper.module.css | 13 -
.../EventRegistrantsWrapper.test.tsx | 2 +-
.../EventRegistrantsWrapper.tsx | 28 +-
.../EventManagement/EventManagement.tsx | 5 +-
21 files changed, 2236 insertions(+), 76 deletions(-)
create mode 100644 public/images/svg/options-outline.svg
create mode 100644 public/images/svg/organization.svg
delete mode 100644 src/components/CheckIn/CheckInWrapper.module.css
create mode 100644 src/components/EventManagement/EventRegistrant/EventRegistrants.spec.tsx
create mode 100644 src/components/EventManagement/EventRegistrant/EventRegistrants.tsx
create mode 100644 src/components/EventManagement/EventRegistrant/Registrations.mocks.ts
delete mode 100644 src/components/EventRegistrantsModal/EventRegistrantsWrapper.module.css
diff --git a/.eslintrc.json b/.eslintrc.json
index 165e406024..67fea73faf 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -143,5 +143,11 @@
"version": "detect"
}
},
- "ignorePatterns": ["**/*.css", "**/*.scss", "**/*.less", "**/*.json"]
+ "ignorePatterns": [
+ "**/*.css",
+ "**/*.scss",
+ "**/*.less",
+ "**/*.json",
+ "**/*.svg"
+ ]
}
diff --git a/package-lock.json b/package-lock.json
index 07a65a79c6..9c801aa1c0 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -23,6 +23,7 @@
"@mui/x-charts": "^7.22.2",
"@mui/x-data-grid": "^7.22.1",
"@mui/x-date-pickers": "^7.18.0",
+ "@pdfme/common": "^5.2.11",
"@pdfme/generator": "^5.2.3",
"@pdfme/schemas": "^5.1.6",
"@reduxjs/toolkit": "^2.3.0",
@@ -154,6 +155,141 @@
"node": ">=6.0.0"
}
},
+ "node_modules/@ant-design/colors": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/@ant-design/colors/-/colors-7.1.0.tgz",
+ "integrity": "sha512-MMoDGWn1y9LdQJQSHiCC20x3uZ3CwQnv9QMz6pCmJOrqdgM9YxsoVVY0wtrdXbmfSgnV0KNk6zi09NAhMR2jvg==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@ctrl/tinycolor": "^3.6.1"
+ }
+ },
+ "node_modules/@ant-design/cssinjs": {
+ "version": "1.22.1",
+ "resolved": "https://registry.npmjs.org/@ant-design/cssinjs/-/cssinjs-1.22.1.tgz",
+ "integrity": "sha512-SLuXM4wiEE1blOx94iXrkOgseMZHzdr4ngdFu3VVDq6AOWh7rlwqTkMAtJho3EsBF6x/eUGOtK53VZXGQG7+sQ==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@babel/runtime": "^7.11.1",
+ "@emotion/hash": "^0.8.0",
+ "@emotion/unitless": "^0.7.5",
+ "classnames": "^2.3.1",
+ "csstype": "^3.1.3",
+ "rc-util": "^5.35.0",
+ "stylis": "^4.3.4"
+ },
+ "peerDependencies": {
+ "react": ">=16.0.0",
+ "react-dom": ">=16.0.0"
+ }
+ },
+ "node_modules/@ant-design/cssinjs-utils": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/@ant-design/cssinjs-utils/-/cssinjs-utils-1.1.3.tgz",
+ "integrity": "sha512-nOoQMLW1l+xR1Co8NFVYiP8pZp3VjIIzqV6D6ShYF2ljtdwWJn5WSsH+7kvCktXL/yhEtWURKOfH5Xz/gzlwsg==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@ant-design/cssinjs": "^1.21.0",
+ "@babel/runtime": "^7.23.2",
+ "rc-util": "^5.38.0"
+ },
+ "peerDependencies": {
+ "react": ">=16.9.0",
+ "react-dom": ">=16.9.0"
+ }
+ },
+ "node_modules/@ant-design/cssinjs/node_modules/@emotion/hash": {
+ "version": "0.8.0",
+ "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz",
+ "integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==",
+ "license": "MIT",
+ "peer": true
+ },
+ "node_modules/@ant-design/cssinjs/node_modules/@emotion/unitless": {
+ "version": "0.7.5",
+ "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz",
+ "integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==",
+ "license": "MIT",
+ "peer": true
+ },
+ "node_modules/@ant-design/cssinjs/node_modules/stylis": {
+ "version": "4.3.4",
+ "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.4.tgz",
+ "integrity": "sha512-osIBl6BGUmSfDkyH2mB7EFvCJntXDrLhKjHTRj/rK6xLH0yuPrHULDRQzKokSOD4VoorhtKpfcfW1GAntu8now==",
+ "license": "MIT",
+ "peer": true
+ },
+ "node_modules/@ant-design/fast-color": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/@ant-design/fast-color/-/fast-color-2.0.6.tgz",
+ "integrity": "sha512-y2217gk4NqL35giHl72o6Zzqji9O7vHh9YmhUVkPtAOpoTCH4uWxo/pr4VE8t0+ChEPs0qo4eJRC5Q1eXWo3vA==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@babel/runtime": "^7.24.7"
+ },
+ "engines": {
+ "node": ">=8.x"
+ }
+ },
+ "node_modules/@ant-design/icons": {
+ "version": "5.5.2",
+ "resolved": "https://registry.npmjs.org/@ant-design/icons/-/icons-5.5.2.tgz",
+ "integrity": "sha512-xc53rjVBl9v2BqFxUjZGti/RfdDeA8/6KYglmInM2PNqSXc/WfuGDTifJI/ZsokJK0aeKvOIbXc9y2g8ILAhEA==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@ant-design/colors": "^7.0.0",
+ "@ant-design/icons-svg": "^4.4.0",
+ "@babel/runtime": "^7.24.8",
+ "classnames": "^2.2.6",
+ "rc-util": "^5.31.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "peerDependencies": {
+ "react": ">=16.0.0",
+ "react-dom": ">=16.0.0"
+ }
+ },
+ "node_modules/@ant-design/icons-svg": {
+ "version": "4.4.2",
+ "resolved": "https://registry.npmjs.org/@ant-design/icons-svg/-/icons-svg-4.4.2.tgz",
+ "integrity": "sha512-vHbT+zJEVzllwP+CM+ul7reTEfBR0vgxFe7+lREAsAA7YGsYpboiq2sQNeQeRvh09GfQgs/GyFEvZpJ9cLXpXA==",
+ "license": "MIT",
+ "peer": true
+ },
+ "node_modules/@ant-design/react-slick": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@ant-design/react-slick/-/react-slick-1.1.2.tgz",
+ "integrity": "sha512-EzlvzE6xQUBrZuuhSAFTdsr4P2bBBHGZwKFemEfq8gIGyIQCxalYfZW/T2ORbtQx5rU69o+WycP3exY/7T1hGA==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@babel/runtime": "^7.10.4",
+ "classnames": "^2.2.5",
+ "json2mq": "^0.2.0",
+ "resize-observer-polyfill": "^1.5.1",
+ "throttle-debounce": "^5.0.0"
+ },
+ "peerDependencies": {
+ "react": ">=16.9.0"
+ }
+ },
+ "node_modules/@ant-design/react-slick/node_modules/throttle-debounce": {
+ "version": "5.0.2",
+ "resolved": "https://registry.npmjs.org/throttle-debounce/-/throttle-debounce-5.0.2.tgz",
+ "integrity": "sha512-B71/4oyj61iNH0KeCamLuE2rmKuTO5byTOSVwECM5FA7TiAiAW+UqTKZ9ERueC4qvgSttUhdmq1mXC3kJqGX7A==",
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": ">=12.22"
+ }
+ },
"node_modules/@apollo/client": {
"version": "3.11.8",
"resolved": "https://registry.npmjs.org/@apollo/client/-/client-3.11.8.tgz",
@@ -2063,6 +2199,16 @@
"integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==",
"dev": true
},
+ "node_modules/@ctrl/tinycolor": {
+ "version": "3.6.1",
+ "resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz",
+ "integrity": "sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==",
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": ">=10"
+ }
+ },
"node_modules/@dicebear/adventurer": {
"version": "9.2.2",
"resolved": "https://registry.npmjs.org/@dicebear/adventurer/-/adventurer-9.2.2.tgz",
@@ -4761,17 +4907,19 @@
}
},
"node_modules/@pdfme/common": {
- "version": "1.2.6",
- "resolved": "https://registry.npmjs.org/@pdfme/common/-/common-1.2.6.tgz",
- "integrity": "sha512-ROmQ/iMUdmFS2QXD/kKDdcU5T6H3azDs2b1hE/OXs8531BPZ9ABbu9+1NRZQoNK4U/zP2F+Osb/B8ckr9lAmGg==",
- "peer": true,
+ "version": "5.2.11",
+ "resolved": "https://registry.npmjs.org/@pdfme/common/-/common-5.2.11.tgz",
+ "integrity": "sha512-XfVn3UH0LRRzUu9NDJ0rUzxv5Nib+vyTEWiTv3KNUuO/X2553yIpzAAlrn46V+0QhW+491G+zgbr6ark0cJe4w==",
+ "license": "MIT",
"dependencies": {
+ "@pdfme/pdf-lib": "^1.18.3",
+ "acorn": "^8.14.0",
"buffer": "^6.0.3",
- "fontkit": "^2.0.2",
"zod": "^3.20.2"
},
- "engines": {
- "node": ">=14"
+ "peerDependencies": {
+ "antd": "^5.11.2",
+ "form-render": "^2.2.20"
}
},
"node_modules/@pdfme/generator": {
@@ -4855,6 +5003,164 @@
"url": "https://opencollective.com/popperjs"
}
},
+ "node_modules/@rc-component/async-validator": {
+ "version": "5.0.4",
+ "resolved": "https://registry.npmjs.org/@rc-component/async-validator/-/async-validator-5.0.4.tgz",
+ "integrity": "sha512-qgGdcVIF604M9EqjNF0hbUTz42bz/RDtxWdWuU5EQe3hi7M8ob54B6B35rOsvX5eSvIHIzT9iH1R3n+hk3CGfg==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@babel/runtime": "^7.24.4"
+ },
+ "engines": {
+ "node": ">=14.x"
+ }
+ },
+ "node_modules/@rc-component/color-picker": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/@rc-component/color-picker/-/color-picker-2.0.1.tgz",
+ "integrity": "sha512-WcZYwAThV/b2GISQ8F+7650r5ZZJ043E57aVBFkQ+kSY4C6wdofXgB0hBx+GPGpIU0Z81eETNoDUJMr7oy/P8Q==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@ant-design/fast-color": "^2.0.6",
+ "@babel/runtime": "^7.23.6",
+ "classnames": "^2.2.6",
+ "rc-util": "^5.38.1"
+ },
+ "peerDependencies": {
+ "react": ">=16.9.0",
+ "react-dom": ">=16.9.0"
+ }
+ },
+ "node_modules/@rc-component/context": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@rc-component/context/-/context-1.4.0.tgz",
+ "integrity": "sha512-kFcNxg9oLRMoL3qki0OMxK+7g5mypjgaaJp/pkOis/6rVxma9nJBF/8kCIuTYHUQNr0ii7MxqE33wirPZLJQ2w==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@babel/runtime": "^7.10.1",
+ "rc-util": "^5.27.0"
+ },
+ "peerDependencies": {
+ "react": ">=16.9.0",
+ "react-dom": ">=16.9.0"
+ }
+ },
+ "node_modules/@rc-component/mini-decimal": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@rc-component/mini-decimal/-/mini-decimal-1.1.0.tgz",
+ "integrity": "sha512-jS4E7T9Li2GuYwI6PyiVXmxTiM6b07rlD9Ge8uGZSCz3WlzcG5ZK7g5bbuKNeZ9pgUuPK/5guV781ujdVpm4HQ==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@babel/runtime": "^7.18.0"
+ },
+ "engines": {
+ "node": ">=8.x"
+ }
+ },
+ "node_modules/@rc-component/mutate-observer": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@rc-component/mutate-observer/-/mutate-observer-1.1.0.tgz",
+ "integrity": "sha512-QjrOsDXQusNwGZPf4/qRQasg7UFEj06XiCJ8iuiq/Io7CrHrgVi6Uuetw60WAMG1799v+aM8kyc+1L/GBbHSlw==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@babel/runtime": "^7.18.0",
+ "classnames": "^2.3.2",
+ "rc-util": "^5.24.4"
+ },
+ "engines": {
+ "node": ">=8.x"
+ },
+ "peerDependencies": {
+ "react": ">=16.9.0",
+ "react-dom": ">=16.9.0"
+ }
+ },
+ "node_modules/@rc-component/portal": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@rc-component/portal/-/portal-1.1.2.tgz",
+ "integrity": "sha512-6f813C0IsasTZms08kfA8kPAGxbbkYToa8ALaiDIGGECU4i9hj8Plgbx0sNJDrey3EtHO30hmdaxtT0138xZcg==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@babel/runtime": "^7.18.0",
+ "classnames": "^2.3.2",
+ "rc-util": "^5.24.4"
+ },
+ "engines": {
+ "node": ">=8.x"
+ },
+ "peerDependencies": {
+ "react": ">=16.9.0",
+ "react-dom": ">=16.9.0"
+ }
+ },
+ "node_modules/@rc-component/qrcode": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/@rc-component/qrcode/-/qrcode-1.0.0.tgz",
+ "integrity": "sha512-L+rZ4HXP2sJ1gHMGHjsg9jlYBX/SLN2D6OxP9Zn3qgtpMWtO2vUfxVFwiogHpAIqs54FnALxraUy/BCO1yRIgg==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@babel/runtime": "^7.24.7",
+ "classnames": "^2.3.2",
+ "rc-util": "^5.38.0"
+ },
+ "engines": {
+ "node": ">=8.x"
+ },
+ "peerDependencies": {
+ "react": ">=16.9.0",
+ "react-dom": ">=16.9.0"
+ }
+ },
+ "node_modules/@rc-component/tour": {
+ "version": "1.15.1",
+ "resolved": "https://registry.npmjs.org/@rc-component/tour/-/tour-1.15.1.tgz",
+ "integrity": "sha512-Tr2t7J1DKZUpfJuDZWHxyxWpfmj8EZrqSgyMZ+BCdvKZ6r1UDsfU46M/iWAAFBy961Ssfom2kv5f3UcjIL2CmQ==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@babel/runtime": "^7.18.0",
+ "@rc-component/portal": "^1.0.0-9",
+ "@rc-component/trigger": "^2.0.0",
+ "classnames": "^2.3.2",
+ "rc-util": "^5.24.4"
+ },
+ "engines": {
+ "node": ">=8.x"
+ },
+ "peerDependencies": {
+ "react": ">=16.9.0",
+ "react-dom": ">=16.9.0"
+ }
+ },
+ "node_modules/@rc-component/trigger": {
+ "version": "2.2.6",
+ "resolved": "https://registry.npmjs.org/@rc-component/trigger/-/trigger-2.2.6.tgz",
+ "integrity": "sha512-/9zuTnWwhQ3S3WT1T8BubuFTT46kvnXgaERR9f4BTKyn61/wpf/BvbImzYBubzJibU707FxwbKszLlHjcLiv1Q==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@babel/runtime": "^7.23.2",
+ "@rc-component/portal": "^1.1.0",
+ "classnames": "^2.3.2",
+ "rc-motion": "^2.0.0",
+ "rc-resize-observer": "^1.3.1",
+ "rc-util": "^5.44.0"
+ },
+ "engines": {
+ "node": ">=8.x"
+ },
+ "peerDependencies": {
+ "react": ">=16.9.0",
+ "react-dom": ">=16.9.0"
+ }
+ },
"node_modules/@react-aria/ssr": {
"version": "3.9.5",
"resolved": "https://registry.npmjs.org/@react-aria/ssr/-/ssr-3.9.5.tgz",
@@ -6814,10 +7120,10 @@
"dev": true
},
"node_modules/acorn": {
- "version": "8.10.0",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz",
- "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==",
- "devOptional": true,
+ "version": "8.14.0",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz",
+ "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==",
+ "license": "MIT",
"bin": {
"acorn": "bin/acorn"
},
@@ -6866,6 +7172,16 @@
"node": ">=0.4.0"
}
},
+ "node_modules/add-dom-event-listener": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/add-dom-event-listener/-/add-dom-event-listener-1.1.0.tgz",
+ "integrity": "sha512-WCxx1ixHT0GQU9hb0KI/mhgRQhnU+U3GvwY6ZvVjYq8rsihIGoaIOUbY0yMPBxLH5MDtr0kz3fisWGNcbWW7Jw==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "object-assign": "4.x"
+ }
+ },
"node_modules/agent-base": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
@@ -6878,6 +7194,30 @@
"node": ">= 6.0.0"
}
},
+ "node_modules/ahooks": {
+ "version": "3.8.4",
+ "resolved": "https://registry.npmjs.org/ahooks/-/ahooks-3.8.4.tgz",
+ "integrity": "sha512-39wDEw2ZHvypaT14EpMMk4AzosHWt0z9bulY0BeDsvc9PqJEV+Kjh/4TZfftSsotBMq52iYIOFPd3PR56e0ZJg==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@babel/runtime": "^7.21.0",
+ "dayjs": "^1.9.1",
+ "intersection-observer": "^0.12.0",
+ "js-cookie": "^3.0.5",
+ "lodash": "^4.17.21",
+ "react-fast-compare": "^3.2.2",
+ "resize-observer-polyfill": "^1.5.1",
+ "screenfull": "^5.0.0",
+ "tslib": "^2.4.1"
+ },
+ "engines": {
+ "node": ">=8.0.0"
+ },
+ "peerDependencies": {
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
+ }
+ },
"node_modules/air-datepicker": {
"version": "3.5.3",
"resolved": "https://registry.npmjs.org/air-datepicker/-/air-datepicker-3.5.3.tgz",
@@ -6964,6 +7304,82 @@
"node": ">=0.10.0"
}
},
+ "node_modules/antd": {
+ "version": "5.22.6",
+ "resolved": "https://registry.npmjs.org/antd/-/antd-5.22.6.tgz",
+ "integrity": "sha512-ZYURSV3FR8qQgbfpa554thlO07L6PeHwhAM0wmxnobOBogND/HqSnTU+UZTqT2b2y9MxSfAIu5Xn1uEM9UpceQ==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@ant-design/colors": "^7.1.0",
+ "@ant-design/cssinjs": "^1.21.1",
+ "@ant-design/cssinjs-utils": "^1.1.3",
+ "@ant-design/icons": "^5.5.2",
+ "@ant-design/react-slick": "~1.1.2",
+ "@babel/runtime": "^7.25.7",
+ "@ctrl/tinycolor": "^3.6.1",
+ "@rc-component/color-picker": "~2.0.1",
+ "@rc-component/mutate-observer": "^1.1.0",
+ "@rc-component/qrcode": "~1.0.0",
+ "@rc-component/tour": "~1.15.1",
+ "@rc-component/trigger": "^2.2.6",
+ "classnames": "^2.5.1",
+ "copy-to-clipboard": "^3.3.3",
+ "dayjs": "^1.11.11",
+ "rc-cascader": "~3.30.0",
+ "rc-checkbox": "~3.3.0",
+ "rc-collapse": "~3.9.0",
+ "rc-dialog": "~9.6.0",
+ "rc-drawer": "~7.2.0",
+ "rc-dropdown": "~4.2.1",
+ "rc-field-form": "~2.7.0",
+ "rc-image": "~7.11.0",
+ "rc-input": "~1.6.4",
+ "rc-input-number": "~9.3.0",
+ "rc-mentions": "~2.17.0",
+ "rc-menu": "~9.16.0",
+ "rc-motion": "^2.9.5",
+ "rc-notification": "~5.6.2",
+ "rc-pagination": "~5.0.0",
+ "rc-picker": "~4.8.3",
+ "rc-progress": "~4.0.0",
+ "rc-rate": "~2.13.0",
+ "rc-resize-observer": "^1.4.3",
+ "rc-segmented": "~2.5.0",
+ "rc-select": "~14.16.4",
+ "rc-slider": "~11.1.7",
+ "rc-steps": "~6.0.1",
+ "rc-switch": "~4.1.0",
+ "rc-table": "~7.49.0",
+ "rc-tabs": "~15.4.0",
+ "rc-textarea": "~1.8.2",
+ "rc-tooltip": "~6.2.1",
+ "rc-tree": "~5.10.1",
+ "rc-tree-select": "~5.24.5",
+ "rc-upload": "~4.8.1",
+ "rc-util": "^5.44.2",
+ "scroll-into-view-if-needed": "^3.1.0",
+ "throttle-debounce": "^5.0.2"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/ant-design"
+ },
+ "peerDependencies": {
+ "react": ">=16.9.0",
+ "react-dom": ">=16.9.0"
+ }
+ },
+ "node_modules/antd/node_modules/throttle-debounce": {
+ "version": "5.0.2",
+ "resolved": "https://registry.npmjs.org/throttle-debounce/-/throttle-debounce-5.0.2.tgz",
+ "integrity": "sha512-B71/4oyj61iNH0KeCamLuE2rmKuTO5byTOSVwECM5FA7TiAiAW+UqTKZ9ERueC4qvgSttUhdmq1mXC3kJqGX7A==",
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": ">=12.22"
+ }
+ },
"node_modules/anymatch": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
@@ -7181,6 +7597,13 @@
"node": ">=12"
}
},
+ "node_modules/async-validator": {
+ "version": "3.5.2",
+ "resolved": "https://registry.npmjs.org/async-validator/-/async-validator-3.5.2.tgz",
+ "integrity": "sha512-8eLCg00W9pIRZSB781UUX/H6Oskmm8xloZfr09lz5bikRpBVDlJ3hRVuxxP1SxcwsEYfJ4IU8Q19Y8/893r3rQ==",
+ "license": "MIT",
+ "peer": true
+ },
"node_modules/asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
@@ -7571,6 +7994,17 @@
"@babel/core": "^7.0.0"
}
},
+ "node_modules/babel-runtime": {
+ "version": "6.26.0",
+ "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
+ "integrity": "sha512-ITKNuq2wKlW1fJg9sSW52eepoYgZBggvOAHC0u/CYu/qxQ9EVzThCgR69BnSXLHjy2f7SY5zaQ4yt7H9ZVxY2g==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "core-js": "^2.4.0",
+ "regenerator-runtime": "^0.11.0"
+ }
+ },
"node_modules/balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
@@ -7907,7 +8341,6 @@
"url": "https://feross.org/support"
}
],
- "peer": true,
"dependencies": {
"base64-js": "^1.3.1",
"ieee754": "^1.2.1"
@@ -8207,9 +8640,10 @@
"dev": true
},
"node_modules/classnames": {
- "version": "2.3.2",
- "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.2.tgz",
- "integrity": "sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw=="
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz",
+ "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==",
+ "license": "MIT"
},
"node_modules/cli-boxes": {
"version": "2.2.1",
@@ -8455,6 +8889,29 @@
"node": "^12.20.0 || >=14"
}
},
+ "node_modules/component-classes": {
+ "version": "1.2.6",
+ "resolved": "https://registry.npmjs.org/component-classes/-/component-classes-1.2.6.tgz",
+ "integrity": "sha512-hPFGULxdwugu1QWW3SvVOCUHLzO34+a2J6Wqy0c5ASQkfi9/8nZcBB0ZohaEbXOQlCflMAEMmEWk7u7BVs4koA==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "component-indexof": "0.0.3"
+ }
+ },
+ "node_modules/component-indexof": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/component-indexof/-/component-indexof-0.0.3.tgz",
+ "integrity": "sha512-puDQKvx/64HZXb4hBwIcvQLaLgux8o1CbWl39s41hrIIZDl1lJiD5jc22gj3RBeGK0ovxALDYpIbyjqDUUl0rw==",
+ "peer": true
+ },
+ "node_modules/compute-scroll-into-view": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-3.1.0.tgz",
+ "integrity": "sha512-rj8l8pD4bJ1nx+dAkMhV1xB5RuZEyVysfxJqB1pRchh1KVvwOv9b7CGB8ZfjTImVv2oF+sYMUkMZq6Na5Ftmbg==",
+ "license": "MIT",
+ "peer": true
+ },
"node_modules/concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@@ -8585,6 +9042,25 @@
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz",
"integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A=="
},
+ "node_modules/copy-to-clipboard": {
+ "version": "3.3.3",
+ "resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz",
+ "integrity": "sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "toggle-selection": "^1.0.6"
+ }
+ },
+ "node_modules/core-js": {
+ "version": "2.6.12",
+ "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz",
+ "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==",
+ "deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.",
+ "hasInstallScript": true,
+ "license": "MIT",
+ "peer": true
+ },
"node_modules/core-js-compat": {
"version": "3.38.1",
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.38.1.tgz",
@@ -8657,6 +9133,17 @@
"sha.js": "^2.4.8"
}
},
+ "node_modules/create-react-class": {
+ "version": "15.7.0",
+ "resolved": "https://registry.npmjs.org/create-react-class/-/create-react-class-15.7.0.tgz",
+ "integrity": "sha512-QZv4sFWG9S5RUvkTYWbflxeZX+JG7Cz0Tn33rQBJ+WFQTqTfUTjMjiv9tnfXazjsO5r0KhPs+AqCjyrQX6h2ng==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "loose-envify": "^1.3.1",
+ "object-assign": "^4.1.1"
+ }
+ },
"node_modules/create-require": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
@@ -8736,6 +9223,17 @@
"node": ">=8"
}
},
+ "node_modules/css-animation": {
+ "version": "1.6.1",
+ "resolved": "https://registry.npmjs.org/css-animation/-/css-animation-1.6.1.tgz",
+ "integrity": "sha512-/48+/BaEaHRY6kNQ2OIPzKf9A6g8WjZYjhiNDNuIVbsm5tXCGIAsHDjB4Xu1C4vXJtUWZo26O68OQkDpNBaPog==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "babel-runtime": "6.x",
+ "component-classes": "^1.2.5"
+ }
+ },
"node_modules/css-box-model": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/css-box-model/-/css-box-model-1.2.1.tgz",
@@ -9227,6 +9725,13 @@
"dev": true,
"peer": true
},
+ "node_modules/dom-align": {
+ "version": "1.12.4",
+ "resolved": "https://registry.npmjs.org/dom-align/-/dom-align-1.12.4.tgz",
+ "integrity": "sha512-R8LUSEay/68zE5c8/3BDxiTEvgb4xZTF0RKmAHfiEVN3klfIpXfi2/QCoiWPccVQ0J/ZGdz9OjzL4uJEP/MRAw==",
+ "license": "MIT",
+ "peer": true
+ },
"node_modules/dom-helpers": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz",
@@ -10818,8 +11323,131 @@
"node": ">= 6"
}
},
- "node_modules/fs.realpath": {
- "version": "1.0.0",
+ "node_modules/form-render": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/form-render/-/form-render-2.5.1.tgz",
+ "integrity": "sha512-oNbJ+McqB5h1yuyxYAT3ixJF8itmHlnKvqDgQhJT9Tw1c3yGwfRnVXboRxBV+Myz0dkf47zL6lyY1l74yQsWsg==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@ant-design/icons": "^4.0.2",
+ "ahooks": "^3.7.5",
+ "async-validator": "^3.5.1",
+ "classnames": "^2.3.1",
+ "color": "^3.1.2",
+ "dayjs": "^1.11.7",
+ "lodash-es": "^4.17.21",
+ "rc-color-picker": "^1.2.6",
+ "virtualizedtableforantd4": "^1.1.2",
+ "zustand": "^4.1.5"
+ },
+ "peerDependencies": {
+ "antd": "4.x || 5.x",
+ "react": ">=16.9.0",
+ "react-dom": ">=16.9.0"
+ }
+ },
+ "node_modules/form-render/node_modules/@ant-design/colors": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/@ant-design/colors/-/colors-6.0.0.tgz",
+ "integrity": "sha512-qAZRvPzfdWHtfameEGP2Qvuf838NhergR35o+EuVyB5XvSA98xod5r4utvi4TJ3ywmevm290g9nsCG5MryrdWQ==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@ctrl/tinycolor": "^3.4.0"
+ }
+ },
+ "node_modules/form-render/node_modules/@ant-design/icons": {
+ "version": "4.8.3",
+ "resolved": "https://registry.npmjs.org/@ant-design/icons/-/icons-4.8.3.tgz",
+ "integrity": "sha512-HGlIQZzrEbAhpJR6+IGdzfbPym94Owr6JZkJ2QCCnOkPVIWMO2xgIVcOKnl8YcpijIo39V7l2qQL5fmtw56cMw==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@ant-design/colors": "^6.0.0",
+ "@ant-design/icons-svg": "^4.3.0",
+ "@babel/runtime": "^7.11.2",
+ "classnames": "^2.2.6",
+ "lodash": "^4.17.15",
+ "rc-util": "^5.9.4"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "peerDependencies": {
+ "react": ">=16.0.0",
+ "react-dom": ">=16.0.0"
+ }
+ },
+ "node_modules/form-render/node_modules/color": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz",
+ "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "color-convert": "^1.9.3",
+ "color-string": "^1.6.0"
+ }
+ },
+ "node_modules/form-render/node_modules/color-convert": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+ "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "color-name": "1.1.3"
+ }
+ },
+ "node_modules/form-render/node_modules/color-name": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+ "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
+ "license": "MIT",
+ "peer": true
+ },
+ "node_modules/form-render/node_modules/rc-color-picker": {
+ "version": "1.2.6",
+ "resolved": "https://registry.npmjs.org/rc-color-picker/-/rc-color-picker-1.2.6.tgz",
+ "integrity": "sha512-AaC9Pg7qCHSy5M4eVbqDIaNb2FC4SEw82GOHB2C4R/+vF2FVa/r5XA+Igg5+zLPmAvBLhz9tL4MAfkRA8yWNJw==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "classnames": "^2.2.5",
+ "prop-types": "^15.5.8",
+ "rc-trigger": "1.x",
+ "rc-util": "^4.0.2",
+ "tinycolor2": "^1.4.1"
+ },
+ "peerDependencies": {
+ "react": "16.x",
+ "react-dom": "16.x"
+ }
+ },
+ "node_modules/form-render/node_modules/rc-color-picker/node_modules/rc-util": {
+ "version": "4.21.1",
+ "resolved": "https://registry.npmjs.org/rc-util/-/rc-util-4.21.1.tgz",
+ "integrity": "sha512-Z+vlkSQVc1l8O2UjR3WQ+XdWlhj5q9BMQNLk2iOBch75CqPfrJyGtcWMcnhRlNuDu0Ndtt4kLVO8JI8BrABobg==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "add-dom-event-listener": "^1.1.0",
+ "prop-types": "^15.5.10",
+ "react-is": "^16.12.0",
+ "react-lifecycles-compat": "^3.0.4",
+ "shallowequal": "^1.1.0"
+ }
+ },
+ "node_modules/form-render/node_modules/react-is": {
+ "version": "16.13.1",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
+ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
+ "license": "MIT",
+ "peer": true
+ },
+ "node_modules/fs.realpath": {
+ "version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
"dev": true
@@ -11757,6 +12385,13 @@
"node": ">=12"
}
},
+ "node_modules/intersection-observer": {
+ "version": "0.12.2",
+ "resolved": "https://registry.npmjs.org/intersection-observer/-/intersection-observer-0.12.2.tgz",
+ "integrity": "sha512-7m1vEcPCxXYI8HqnL8CKI6siDyD+eIWSwgB3DZA+ZTogxk9I4CDnj4wilt9x/+/QbHI4YG5YZNmC6458/e9Ktg==",
+ "license": "Apache-2.0",
+ "peer": true
+ },
"node_modules/invariant": {
"version": "2.2.4",
"resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
@@ -14064,6 +14699,16 @@
"integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
"dev": true
},
+ "node_modules/json2mq": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/json2mq/-/json2mq-0.2.0.tgz",
+ "integrity": "sha512-SzoRg7ux5DWTII9J2qkrZrqV1gt+rTaoufMxEzXbS26Uid0NwaJd123HcoB80TgubEppxxIGdNxCx50fEoEWQA==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "string-convert": "^0.2.0"
+ }
+ },
"node_modules/json5": {
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
@@ -14585,8 +15230,14 @@
"node_modules/lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
- "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
- "dev": true
+ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
+ },
+ "node_modules/lodash-es": {
+ "version": "4.17.21",
+ "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz",
+ "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==",
+ "license": "MIT",
+ "peer": true
},
"node_modules/lodash._reinterpolate": {
"version": "3.0.0",
@@ -16003,6 +16654,13 @@
"node": ">=0.12"
}
},
+ "node_modules/performance-now": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
+ "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==",
+ "license": "MIT",
+ "peer": true
+ },
"node_modules/picocolors": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz",
@@ -16531,6 +17189,16 @@
}
]
},
+ "node_modules/raf": {
+ "version": "3.4.1",
+ "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz",
+ "integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "performance-now": "^2.1.0"
+ }
+ },
"node_modules/raf-schd": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/raf-schd/-/raf-schd-4.0.3.tgz",
@@ -16589,6 +17257,751 @@
"rc": "cli.js"
}
},
+ "node_modules/rc-align": {
+ "version": "2.4.5",
+ "resolved": "https://registry.npmjs.org/rc-align/-/rc-align-2.4.5.tgz",
+ "integrity": "sha512-nv9wYUYdfyfK+qskThf4BQUSIadeI/dCsfaMZfNEoxm9HwOIioQ+LyqmMK6jWHAZQgOzMLaqawhuBXlF63vgjw==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "babel-runtime": "^6.26.0",
+ "dom-align": "^1.7.0",
+ "prop-types": "^15.5.8",
+ "rc-util": "^4.0.4"
+ }
+ },
+ "node_modules/rc-align/node_modules/rc-util": {
+ "version": "4.21.1",
+ "resolved": "https://registry.npmjs.org/rc-util/-/rc-util-4.21.1.tgz",
+ "integrity": "sha512-Z+vlkSQVc1l8O2UjR3WQ+XdWlhj5q9BMQNLk2iOBch75CqPfrJyGtcWMcnhRlNuDu0Ndtt4kLVO8JI8BrABobg==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "add-dom-event-listener": "^1.1.0",
+ "prop-types": "^15.5.10",
+ "react-is": "^16.12.0",
+ "react-lifecycles-compat": "^3.0.4",
+ "shallowequal": "^1.1.0"
+ }
+ },
+ "node_modules/rc-align/node_modules/react-is": {
+ "version": "16.13.1",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
+ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
+ "license": "MIT",
+ "peer": true
+ },
+ "node_modules/rc-animate": {
+ "version": "2.11.1",
+ "resolved": "https://registry.npmjs.org/rc-animate/-/rc-animate-2.11.1.tgz",
+ "integrity": "sha512-1NyuCGFJG/0Y+9RKh5y/i/AalUCA51opyyS/jO2seELpgymZm2u9QV3xwODwEuzkmeQ1BDPxMLmYLcTJedPlkQ==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "babel-runtime": "6.x",
+ "classnames": "^2.2.6",
+ "css-animation": "^1.3.2",
+ "prop-types": "15.x",
+ "raf": "^3.4.0",
+ "rc-util": "^4.15.3",
+ "react-lifecycles-compat": "^3.0.4"
+ }
+ },
+ "node_modules/rc-animate/node_modules/rc-util": {
+ "version": "4.21.1",
+ "resolved": "https://registry.npmjs.org/rc-util/-/rc-util-4.21.1.tgz",
+ "integrity": "sha512-Z+vlkSQVc1l8O2UjR3WQ+XdWlhj5q9BMQNLk2iOBch75CqPfrJyGtcWMcnhRlNuDu0Ndtt4kLVO8JI8BrABobg==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "add-dom-event-listener": "^1.1.0",
+ "prop-types": "^15.5.10",
+ "react-is": "^16.12.0",
+ "react-lifecycles-compat": "^3.0.4",
+ "shallowequal": "^1.1.0"
+ }
+ },
+ "node_modules/rc-animate/node_modules/react-is": {
+ "version": "16.13.1",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
+ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
+ "license": "MIT",
+ "peer": true
+ },
+ "node_modules/rc-cascader": {
+ "version": "3.30.0",
+ "resolved": "https://registry.npmjs.org/rc-cascader/-/rc-cascader-3.30.0.tgz",
+ "integrity": "sha512-rrzSbk1Bdqbu+pDwiLCLHu72+lwX9BZ28+JKzoi0DWZ4N29QYFeip8Gctl33QVd2Xg3Rf14D3yAOG76ElJw16w==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@babel/runtime": "^7.25.7",
+ "classnames": "^2.3.1",
+ "rc-select": "~14.16.2",
+ "rc-tree": "~5.10.1",
+ "rc-util": "^5.43.0"
+ },
+ "peerDependencies": {
+ "react": ">=16.9.0",
+ "react-dom": ">=16.9.0"
+ }
+ },
+ "node_modules/rc-checkbox": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/rc-checkbox/-/rc-checkbox-3.3.0.tgz",
+ "integrity": "sha512-Ih3ZaAcoAiFKJjifzwsGiT/f/quIkxJoklW4yKGho14Olulwn8gN7hOBve0/WGDg5o/l/5mL0w7ff7/YGvefVw==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@babel/runtime": "^7.10.1",
+ "classnames": "^2.3.2",
+ "rc-util": "^5.25.2"
+ },
+ "peerDependencies": {
+ "react": ">=16.9.0",
+ "react-dom": ">=16.9.0"
+ }
+ },
+ "node_modules/rc-collapse": {
+ "version": "3.9.0",
+ "resolved": "https://registry.npmjs.org/rc-collapse/-/rc-collapse-3.9.0.tgz",
+ "integrity": "sha512-swDdz4QZ4dFTo4RAUMLL50qP0EY62N2kvmk2We5xYdRwcRn8WcYtuetCJpwpaCbUfUt5+huLpVxhvmnK+PHrkA==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@babel/runtime": "^7.10.1",
+ "classnames": "2.x",
+ "rc-motion": "^2.3.4",
+ "rc-util": "^5.27.0"
+ },
+ "peerDependencies": {
+ "react": ">=16.9.0",
+ "react-dom": ">=16.9.0"
+ }
+ },
+ "node_modules/rc-dialog": {
+ "version": "9.6.0",
+ "resolved": "https://registry.npmjs.org/rc-dialog/-/rc-dialog-9.6.0.tgz",
+ "integrity": "sha512-ApoVi9Z8PaCQg6FsUzS8yvBEQy0ZL2PkuvAgrmohPkN3okps5WZ5WQWPc1RNuiOKaAYv8B97ACdsFU5LizzCqg==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@babel/runtime": "^7.10.1",
+ "@rc-component/portal": "^1.0.0-8",
+ "classnames": "^2.2.6",
+ "rc-motion": "^2.3.0",
+ "rc-util": "^5.21.0"
+ },
+ "peerDependencies": {
+ "react": ">=16.9.0",
+ "react-dom": ">=16.9.0"
+ }
+ },
+ "node_modules/rc-drawer": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/rc-drawer/-/rc-drawer-7.2.0.tgz",
+ "integrity": "sha512-9lOQ7kBekEJRdEpScHvtmEtXnAsy+NGDXiRWc2ZVC7QXAazNVbeT4EraQKYwCME8BJLa8Bxqxvs5swwyOepRwg==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@babel/runtime": "^7.23.9",
+ "@rc-component/portal": "^1.1.1",
+ "classnames": "^2.2.6",
+ "rc-motion": "^2.6.1",
+ "rc-util": "^5.38.1"
+ },
+ "peerDependencies": {
+ "react": ">=16.9.0",
+ "react-dom": ">=16.9.0"
+ }
+ },
+ "node_modules/rc-dropdown": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/rc-dropdown/-/rc-dropdown-4.2.1.tgz",
+ "integrity": "sha512-YDAlXsPv3I1n42dv1JpdM7wJ+gSUBfeyPK59ZpBD9jQhK9jVuxpjj3NmWQHOBceA1zEPVX84T2wbdb2SD0UjmA==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@babel/runtime": "^7.18.3",
+ "@rc-component/trigger": "^2.0.0",
+ "classnames": "^2.2.6",
+ "rc-util": "^5.44.1"
+ },
+ "peerDependencies": {
+ "react": ">=16.11.0",
+ "react-dom": ">=16.11.0"
+ }
+ },
+ "node_modules/rc-field-form": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/rc-field-form/-/rc-field-form-2.7.0.tgz",
+ "integrity": "sha512-hgKsCay2taxzVnBPZl+1n4ZondsV78G++XVsMIJCAoioMjlMQR9YwAp7JZDIECzIu2Z66R+f4SFIRrO2DjDNAA==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@babel/runtime": "^7.18.0",
+ "@rc-component/async-validator": "^5.0.3",
+ "rc-util": "^5.32.2"
+ },
+ "engines": {
+ "node": ">=8.x"
+ },
+ "peerDependencies": {
+ "react": ">=16.9.0",
+ "react-dom": ">=16.9.0"
+ }
+ },
+ "node_modules/rc-image": {
+ "version": "7.11.0",
+ "resolved": "https://registry.npmjs.org/rc-image/-/rc-image-7.11.0.tgz",
+ "integrity": "sha512-aZkTEZXqeqfPZtnSdNUnKQA0N/3MbgR7nUnZ+/4MfSFWPFHZau4p5r5ShaI0KPEMnNjv4kijSCFq/9wtJpwykw==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@babel/runtime": "^7.11.2",
+ "@rc-component/portal": "^1.0.2",
+ "classnames": "^2.2.6",
+ "rc-dialog": "~9.6.0",
+ "rc-motion": "^2.6.2",
+ "rc-util": "^5.34.1"
+ },
+ "peerDependencies": {
+ "react": ">=16.9.0",
+ "react-dom": ">=16.9.0"
+ }
+ },
+ "node_modules/rc-input": {
+ "version": "1.6.4",
+ "resolved": "https://registry.npmjs.org/rc-input/-/rc-input-1.6.4.tgz",
+ "integrity": "sha512-lBZhfRD4NSAUW0zOKLUeI6GJuXkxeZYi0hr8VcJgJpyTNOvHw1ysrKWAHcEOAAHj7guxgmWYSi6xWrEdfrSAsA==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@babel/runtime": "^7.11.1",
+ "classnames": "^2.2.1",
+ "rc-util": "^5.18.1"
+ },
+ "peerDependencies": {
+ "react": ">=16.0.0",
+ "react-dom": ">=16.0.0"
+ }
+ },
+ "node_modules/rc-input-number": {
+ "version": "9.3.0",
+ "resolved": "https://registry.npmjs.org/rc-input-number/-/rc-input-number-9.3.0.tgz",
+ "integrity": "sha512-JQ363ywqRyxwgVxpg2z2kja3CehTpYdqR7emJ/6yJjRdbvo+RvfE83fcpBCIJRq3zLp8SakmEXq60qzWyZ7Usw==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@babel/runtime": "^7.10.1",
+ "@rc-component/mini-decimal": "^1.0.1",
+ "classnames": "^2.2.5",
+ "rc-input": "~1.6.0",
+ "rc-util": "^5.40.1"
+ },
+ "peerDependencies": {
+ "react": ">=16.9.0",
+ "react-dom": ">=16.9.0"
+ }
+ },
+ "node_modules/rc-mentions": {
+ "version": "2.17.0",
+ "resolved": "https://registry.npmjs.org/rc-mentions/-/rc-mentions-2.17.0.tgz",
+ "integrity": "sha512-sfHy+qLvc+p8jx8GUsujZWXDOIlIimp6YQz7N5ONQ6bHsa2kyG+BLa5k2wuxgebBbH97is33wxiyq5UkiXRpHA==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@babel/runtime": "^7.22.5",
+ "@rc-component/trigger": "^2.0.0",
+ "classnames": "^2.2.6",
+ "rc-input": "~1.6.0",
+ "rc-menu": "~9.16.0",
+ "rc-textarea": "~1.8.0",
+ "rc-util": "^5.34.1"
+ },
+ "peerDependencies": {
+ "react": ">=16.9.0",
+ "react-dom": ">=16.9.0"
+ }
+ },
+ "node_modules/rc-menu": {
+ "version": "9.16.0",
+ "resolved": "https://registry.npmjs.org/rc-menu/-/rc-menu-9.16.0.tgz",
+ "integrity": "sha512-vAL0yqPkmXWk3+YKRkmIR8TYj3RVdEt3ptG2jCJXWNAvQbT0VJJdRyHZ7kG/l1JsZlB+VJq/VcYOo69VR4oD+w==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@babel/runtime": "^7.10.1",
+ "@rc-component/trigger": "^2.0.0",
+ "classnames": "2.x",
+ "rc-motion": "^2.4.3",
+ "rc-overflow": "^1.3.1",
+ "rc-util": "^5.27.0"
+ },
+ "peerDependencies": {
+ "react": ">=16.9.0",
+ "react-dom": ">=16.9.0"
+ }
+ },
+ "node_modules/rc-motion": {
+ "version": "2.9.5",
+ "resolved": "https://registry.npmjs.org/rc-motion/-/rc-motion-2.9.5.tgz",
+ "integrity": "sha512-w+XTUrfh7ArbYEd2582uDrEhmBHwK1ZENJiSJVb7uRxdE7qJSYjbO2eksRXmndqyKqKoYPc9ClpPh5242mV1vA==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@babel/runtime": "^7.11.1",
+ "classnames": "^2.2.1",
+ "rc-util": "^5.44.0"
+ },
+ "peerDependencies": {
+ "react": ">=16.9.0",
+ "react-dom": ">=16.9.0"
+ }
+ },
+ "node_modules/rc-notification": {
+ "version": "5.6.2",
+ "resolved": "https://registry.npmjs.org/rc-notification/-/rc-notification-5.6.2.tgz",
+ "integrity": "sha512-Id4IYMoii3zzrG0lB0gD6dPgJx4Iu95Xu0BQrhHIbp7ZnAZbLqdqQ73aIWH0d0UFcElxwaKjnzNovTjo7kXz7g==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@babel/runtime": "^7.10.1",
+ "classnames": "2.x",
+ "rc-motion": "^2.9.0",
+ "rc-util": "^5.20.1"
+ },
+ "engines": {
+ "node": ">=8.x"
+ },
+ "peerDependencies": {
+ "react": ">=16.9.0",
+ "react-dom": ">=16.9.0"
+ }
+ },
+ "node_modules/rc-overflow": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/rc-overflow/-/rc-overflow-1.3.2.tgz",
+ "integrity": "sha512-nsUm78jkYAoPygDAcGZeC2VwIg/IBGSodtOY3pMof4W3M9qRJgqaDYm03ZayHlde3I6ipliAxbN0RUcGf5KOzw==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@babel/runtime": "^7.11.1",
+ "classnames": "^2.2.1",
+ "rc-resize-observer": "^1.0.0",
+ "rc-util": "^5.37.0"
+ },
+ "peerDependencies": {
+ "react": ">=16.9.0",
+ "react-dom": ">=16.9.0"
+ }
+ },
+ "node_modules/rc-pagination": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/rc-pagination/-/rc-pagination-5.0.0.tgz",
+ "integrity": "sha512-QjrPvbAQwps93iluvFM62AEYglGYhWW2q/nliQqmvkTi4PXP4HHoh00iC1Sa5LLVmtWQHmG73fBi2x6H6vFHRg==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@babel/runtime": "^7.10.1",
+ "classnames": "^2.3.2",
+ "rc-util": "^5.38.0"
+ },
+ "peerDependencies": {
+ "react": ">=16.9.0",
+ "react-dom": ">=16.9.0"
+ }
+ },
+ "node_modules/rc-picker": {
+ "version": "4.8.3",
+ "resolved": "https://registry.npmjs.org/rc-picker/-/rc-picker-4.8.3.tgz",
+ "integrity": "sha512-hJ45qoEs4mfxXPAJdp1n3sKwADul874Cd0/HwnsEOE60H+tgiJUGgbOD62As3EG/rFVNS5AWRfBCDJJfmRqOVQ==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@babel/runtime": "^7.24.7",
+ "@rc-component/trigger": "^2.0.0",
+ "classnames": "^2.2.1",
+ "rc-overflow": "^1.3.2",
+ "rc-resize-observer": "^1.4.0",
+ "rc-util": "^5.43.0"
+ },
+ "engines": {
+ "node": ">=8.x"
+ },
+ "peerDependencies": {
+ "date-fns": ">= 2.x",
+ "dayjs": ">= 1.x",
+ "luxon": ">= 3.x",
+ "moment": ">= 2.x",
+ "react": ">=16.9.0",
+ "react-dom": ">=16.9.0"
+ },
+ "peerDependenciesMeta": {
+ "date-fns": {
+ "optional": true
+ },
+ "dayjs": {
+ "optional": true
+ },
+ "luxon": {
+ "optional": true
+ },
+ "moment": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/rc-progress": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/rc-progress/-/rc-progress-4.0.0.tgz",
+ "integrity": "sha512-oofVMMafOCokIUIBnZLNcOZFsABaUw8PPrf1/y0ZBvKZNpOiu5h4AO9vv11Sw0p4Hb3D0yGWuEattcQGtNJ/aw==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@babel/runtime": "^7.10.1",
+ "classnames": "^2.2.6",
+ "rc-util": "^5.16.1"
+ },
+ "peerDependencies": {
+ "react": ">=16.9.0",
+ "react-dom": ">=16.9.0"
+ }
+ },
+ "node_modules/rc-rate": {
+ "version": "2.13.0",
+ "resolved": "https://registry.npmjs.org/rc-rate/-/rc-rate-2.13.0.tgz",
+ "integrity": "sha512-oxvx1Q5k5wD30sjN5tqAyWTvJfLNNJn7Oq3IeS4HxWfAiC4BOXMITNAsw7u/fzdtO4MS8Ki8uRLOzcnEuoQiAw==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@babel/runtime": "^7.10.1",
+ "classnames": "^2.2.5",
+ "rc-util": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8.x"
+ },
+ "peerDependencies": {
+ "react": ">=16.9.0",
+ "react-dom": ">=16.9.0"
+ }
+ },
+ "node_modules/rc-resize-observer": {
+ "version": "1.4.3",
+ "resolved": "https://registry.npmjs.org/rc-resize-observer/-/rc-resize-observer-1.4.3.tgz",
+ "integrity": "sha512-YZLjUbyIWox8E9i9C3Tm7ia+W7euPItNWSPX5sCcQTYbnwDb5uNpnLHQCG1f22oZWUhLw4Mv2tFmeWe68CDQRQ==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@babel/runtime": "^7.20.7",
+ "classnames": "^2.2.1",
+ "rc-util": "^5.44.1",
+ "resize-observer-polyfill": "^1.5.1"
+ },
+ "peerDependencies": {
+ "react": ">=16.9.0",
+ "react-dom": ">=16.9.0"
+ }
+ },
+ "node_modules/rc-segmented": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/rc-segmented/-/rc-segmented-2.5.0.tgz",
+ "integrity": "sha512-B28Fe3J9iUFOhFJET3RoXAPFJ2u47QvLSYcZWC4tFYNGPEjug5LAxEasZlA/PpAxhdOPqGWsGbSj7ftneukJnw==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@babel/runtime": "^7.11.1",
+ "classnames": "^2.2.1",
+ "rc-motion": "^2.4.4",
+ "rc-util": "^5.17.0"
+ },
+ "peerDependencies": {
+ "react": ">=16.0.0",
+ "react-dom": ">=16.0.0"
+ }
+ },
+ "node_modules/rc-select": {
+ "version": "14.16.4",
+ "resolved": "https://registry.npmjs.org/rc-select/-/rc-select-14.16.4.tgz",
+ "integrity": "sha512-jP6qf7+vjnxGvPpfPWbGYfFlSl3h8L2XcD4O7g2GYXmEeBC0mw+nPD7i++OOE8v3YGqP8xtYjRKAWCMLfjgxlw==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@babel/runtime": "^7.10.1",
+ "@rc-component/trigger": "^2.1.1",
+ "classnames": "2.x",
+ "rc-motion": "^2.0.1",
+ "rc-overflow": "^1.3.1",
+ "rc-util": "^5.16.1",
+ "rc-virtual-list": "^3.5.2"
+ },
+ "engines": {
+ "node": ">=8.x"
+ },
+ "peerDependencies": {
+ "react": "*",
+ "react-dom": "*"
+ }
+ },
+ "node_modules/rc-slider": {
+ "version": "11.1.7",
+ "resolved": "https://registry.npmjs.org/rc-slider/-/rc-slider-11.1.7.tgz",
+ "integrity": "sha512-ytYbZei81TX7otdC0QvoYD72XSlxvTihNth5OeZ6PMXyEDq/vHdWFulQmfDGyXK1NwKwSlKgpvINOa88uT5g2A==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@babel/runtime": "^7.10.1",
+ "classnames": "^2.2.5",
+ "rc-util": "^5.36.0"
+ },
+ "engines": {
+ "node": ">=8.x"
+ },
+ "peerDependencies": {
+ "react": ">=16.9.0",
+ "react-dom": ">=16.9.0"
+ }
+ },
+ "node_modules/rc-steps": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/rc-steps/-/rc-steps-6.0.1.tgz",
+ "integrity": "sha512-lKHL+Sny0SeHkQKKDJlAjV5oZ8DwCdS2hFhAkIjuQt1/pB81M0cA0ErVFdHq9+jmPmFw1vJB2F5NBzFXLJxV+g==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@babel/runtime": "^7.16.7",
+ "classnames": "^2.2.3",
+ "rc-util": "^5.16.1"
+ },
+ "engines": {
+ "node": ">=8.x"
+ },
+ "peerDependencies": {
+ "react": ">=16.9.0",
+ "react-dom": ">=16.9.0"
+ }
+ },
+ "node_modules/rc-switch": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/rc-switch/-/rc-switch-4.1.0.tgz",
+ "integrity": "sha512-TI8ufP2Az9oEbvyCeVE4+90PDSljGyuwix3fV58p7HV2o4wBnVToEyomJRVyTaZeqNPAp+vqeo4Wnj5u0ZZQBg==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@babel/runtime": "^7.21.0",
+ "classnames": "^2.2.1",
+ "rc-util": "^5.30.0"
+ },
+ "peerDependencies": {
+ "react": ">=16.9.0",
+ "react-dom": ">=16.9.0"
+ }
+ },
+ "node_modules/rc-table": {
+ "version": "7.49.0",
+ "resolved": "https://registry.npmjs.org/rc-table/-/rc-table-7.49.0.tgz",
+ "integrity": "sha512-/FoPLX94muAQOxVpi1jhnpKjOIqUbT81eELQPAzSXOke4ky4oCWYUXOcVpL31ZCO90xScwVSXRd7coqtgtB1Ng==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@babel/runtime": "^7.10.1",
+ "@rc-component/context": "^1.4.0",
+ "classnames": "^2.2.5",
+ "rc-resize-observer": "^1.1.0",
+ "rc-util": "^5.41.0",
+ "rc-virtual-list": "^3.14.2"
+ },
+ "engines": {
+ "node": ">=8.x"
+ },
+ "peerDependencies": {
+ "react": ">=16.9.0",
+ "react-dom": ">=16.9.0"
+ }
+ },
+ "node_modules/rc-tabs": {
+ "version": "15.4.0",
+ "resolved": "https://registry.npmjs.org/rc-tabs/-/rc-tabs-15.4.0.tgz",
+ "integrity": "sha512-llKuyiAVqmXm2z7OrmhX5cNb2ueZaL8ZyA2P4R+6/72NYYcbEgOXibwHiQCFY2RiN3swXl53SIABi2CumUS02g==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@babel/runtime": "^7.11.2",
+ "classnames": "2.x",
+ "rc-dropdown": "~4.2.0",
+ "rc-menu": "~9.16.0",
+ "rc-motion": "^2.6.2",
+ "rc-resize-observer": "^1.0.0",
+ "rc-util": "^5.34.1"
+ },
+ "engines": {
+ "node": ">=8.x"
+ },
+ "peerDependencies": {
+ "react": ">=16.9.0",
+ "react-dom": ">=16.9.0"
+ }
+ },
+ "node_modules/rc-textarea": {
+ "version": "1.8.2",
+ "resolved": "https://registry.npmjs.org/rc-textarea/-/rc-textarea-1.8.2.tgz",
+ "integrity": "sha512-UFAezAqltyR00a8Lf0IPAyTd29Jj9ee8wt8DqXyDMal7r/Cg/nDt3e1OOv3Th4W6mKaZijjgwuPXhAfVNTN8sw==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@babel/runtime": "^7.10.1",
+ "classnames": "^2.2.1",
+ "rc-input": "~1.6.0",
+ "rc-resize-observer": "^1.0.0",
+ "rc-util": "^5.27.0"
+ },
+ "peerDependencies": {
+ "react": ">=16.9.0",
+ "react-dom": ">=16.9.0"
+ }
+ },
+ "node_modules/rc-tooltip": {
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/rc-tooltip/-/rc-tooltip-6.2.1.tgz",
+ "integrity": "sha512-rws0duD/3sHHsD905Nex7FvoUGy2UBQRhTkKxeEvr2FB+r21HsOxcDJI0TzyO8NHhnAA8ILr8pfbSBg5Jj5KBg==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@babel/runtime": "^7.11.2",
+ "@rc-component/trigger": "^2.0.0",
+ "classnames": "^2.3.1"
+ },
+ "peerDependencies": {
+ "react": ">=16.9.0",
+ "react-dom": ">=16.9.0"
+ }
+ },
+ "node_modules/rc-tree": {
+ "version": "5.10.1",
+ "resolved": "https://registry.npmjs.org/rc-tree/-/rc-tree-5.10.1.tgz",
+ "integrity": "sha512-FPXb3tT/u39mgjr6JNlHaUTYfHkVGW56XaGDahDpEFLGsnPxGcVLNTjcqoQb/GNbSCycl7tD7EvIymwOTP0+Yw==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@babel/runtime": "^7.10.1",
+ "classnames": "2.x",
+ "rc-motion": "^2.0.1",
+ "rc-util": "^5.16.1",
+ "rc-virtual-list": "^3.5.1"
+ },
+ "engines": {
+ "node": ">=10.x"
+ },
+ "peerDependencies": {
+ "react": "*",
+ "react-dom": "*"
+ }
+ },
+ "node_modules/rc-tree-select": {
+ "version": "5.24.5",
+ "resolved": "https://registry.npmjs.org/rc-tree-select/-/rc-tree-select-5.24.5.tgz",
+ "integrity": "sha512-PnyR8LZJWaiEFw0SHRqo4MNQWyyZsyMs8eNmo68uXZWjxc7QqeWcjPPoONN0rc90c3HZqGF9z+Roz+GLzY5GXA==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@babel/runtime": "^7.25.7",
+ "classnames": "2.x",
+ "rc-select": "~14.16.2",
+ "rc-tree": "~5.10.1",
+ "rc-util": "^5.43.0"
+ },
+ "peerDependencies": {
+ "react": "*",
+ "react-dom": "*"
+ }
+ },
+ "node_modules/rc-trigger": {
+ "version": "1.11.5",
+ "resolved": "https://registry.npmjs.org/rc-trigger/-/rc-trigger-1.11.5.tgz",
+ "integrity": "sha512-MBuUPw1nFzA4K7jQOwb7uvFaZFjXGd00EofUYiZ+l/fgKVq8wnLC0lkv36kwqM7vfKyftRo2sh7cWVpdPuNnnw==",
+ "peer": true,
+ "dependencies": {
+ "babel-runtime": "6.x",
+ "create-react-class": "15.x",
+ "prop-types": "15.x",
+ "rc-align": "2.x",
+ "rc-animate": "2.x",
+ "rc-util": "4.x"
+ }
+ },
+ "node_modules/rc-trigger/node_modules/rc-util": {
+ "version": "4.21.1",
+ "resolved": "https://registry.npmjs.org/rc-util/-/rc-util-4.21.1.tgz",
+ "integrity": "sha512-Z+vlkSQVc1l8O2UjR3WQ+XdWlhj5q9BMQNLk2iOBch75CqPfrJyGtcWMcnhRlNuDu0Ndtt4kLVO8JI8BrABobg==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "add-dom-event-listener": "^1.1.0",
+ "prop-types": "^15.5.10",
+ "react-is": "^16.12.0",
+ "react-lifecycles-compat": "^3.0.4",
+ "shallowequal": "^1.1.0"
+ }
+ },
+ "node_modules/rc-trigger/node_modules/react-is": {
+ "version": "16.13.1",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
+ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
+ "license": "MIT",
+ "peer": true
+ },
+ "node_modules/rc-upload": {
+ "version": "4.8.1",
+ "resolved": "https://registry.npmjs.org/rc-upload/-/rc-upload-4.8.1.tgz",
+ "integrity": "sha512-toEAhwl4hjLAI1u8/CgKWt30BR06ulPa4iGQSMvSXoHzO88gPCslxqV/mnn4gJU7PDoltGIC9Eh+wkeudqgHyw==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@babel/runtime": "^7.18.3",
+ "classnames": "^2.2.5",
+ "rc-util": "^5.2.0"
+ },
+ "peerDependencies": {
+ "react": ">=16.9.0",
+ "react-dom": ">=16.9.0"
+ }
+ },
+ "node_modules/rc-util": {
+ "version": "5.44.3",
+ "resolved": "https://registry.npmjs.org/rc-util/-/rc-util-5.44.3.tgz",
+ "integrity": "sha512-q6KCcOFk3rv/zD3MckhJteZxb0VjAIFuf622B7ElK4vfrZdAzs16XR5p3VTdy3+U5jfJU5ACz4QnhLSuAGe5dA==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@babel/runtime": "^7.18.3",
+ "react-is": "^18.2.0"
+ },
+ "peerDependencies": {
+ "react": ">=16.9.0",
+ "react-dom": ">=16.9.0"
+ }
+ },
+ "node_modules/rc-virtual-list": {
+ "version": "3.16.1",
+ "resolved": "https://registry.npmjs.org/rc-virtual-list/-/rc-virtual-list-3.16.1.tgz",
+ "integrity": "sha512-algM5UsB7vrlPNr9lsZEH8s9KHkP8XbT/Y0qylyPkiM8mIOlSJLjBNADcmbYPEQCm4zW82mZRJuVHNzqqN0EAQ==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@babel/runtime": "^7.20.0",
+ "classnames": "^2.2.6",
+ "rc-resize-observer": "^1.0.0",
+ "rc-util": "^5.36.0"
+ },
+ "engines": {
+ "node": ">=8.x"
+ },
+ "peerDependencies": {
+ "react": ">=16.9.0",
+ "react-dom": ">=16.9.0"
+ }
+ },
"node_modules/rc/node_modules/strip-json-comments": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
@@ -16751,6 +18164,13 @@
"react": "^18.3.1"
}
},
+ "node_modules/react-fast-compare": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz",
+ "integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==",
+ "license": "MIT",
+ "peer": true
+ },
"node_modules/react-google-recaptcha": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/react-google-recaptcha/-/react-google-recaptcha-3.1.0.tgz",
@@ -17016,6 +18436,13 @@
"node": ">=4"
}
},
+ "node_modules/regenerator-runtime": {
+ "version": "0.11.1",
+ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz",
+ "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==",
+ "license": "MIT",
+ "peer": true
+ },
"node_modules/regenerator-transform": {
"version": "0.15.2",
"resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz",
@@ -17183,6 +18610,13 @@
"resolved": "https://registry.npmjs.org/reselect/-/reselect-5.1.1.tgz",
"integrity": "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w=="
},
+ "node_modules/resize-observer-polyfill": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz",
+ "integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==",
+ "license": "MIT",
+ "peer": true
+ },
"node_modules/resolve": {
"version": "1.22.8",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
@@ -17643,6 +19077,29 @@
"loose-envify": "^1.1.0"
}
},
+ "node_modules/screenfull": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/screenfull/-/screenfull-5.2.0.tgz",
+ "integrity": "sha512-9BakfsO2aUQN2K9Fdbj87RJIEZ82Q9IGim7FqM5OsebfoFC6ZHXgDq/KvniuLTPdeM8wY2o6Dj3WQ7KeQCj3cA==",
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": ">=0.10.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/scroll-into-view-if-needed": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/scroll-into-view-if-needed/-/scroll-into-view-if-needed-3.1.0.tgz",
+ "integrity": "sha512-49oNpRjWRvnU8NyGVmUaYG4jtTkNonFZI86MmGRDqBphEK2EXT9gdEUoQPZhuBM8yWHxCWbobltqYO5M4XrUvQ==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "compute-scroll-into-view": "^3.0.2"
+ }
+ },
"node_modules/semver": {
"version": "7.6.3",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
@@ -17736,6 +19193,13 @@
"sha.js": "bin.js"
}
},
+ "node_modules/shallowequal": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz",
+ "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==",
+ "license": "MIT",
+ "peer": true
+ },
"node_modules/shebang-command": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
@@ -18021,6 +19485,13 @@
"node": ">=0.6.19"
}
},
+ "node_modules/string-convert": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/string-convert/-/string-convert-0.2.1.tgz",
+ "integrity": "sha512-u/1tdPl4yQnPBjnVrmdLo9gtuLvELKsAoRapekWggdiQNvvvum+jYF329d84NAa660KQw7pB2n36KrIKVoXa3A==",
+ "license": "MIT",
+ "peer": true
+ },
"node_modules/string-hash": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/string-hash/-/string-hash-1.1.3.tgz",
@@ -18472,6 +19943,13 @@
"integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==",
"dev": true
},
+ "node_modules/tinycolor2": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.6.0.tgz",
+ "integrity": "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==",
+ "license": "MIT",
+ "peer": true
+ },
"node_modules/tinyexec": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.1.tgz",
@@ -18566,6 +20044,13 @@
"node": ">=8.0"
}
},
+ "node_modules/toggle-selection": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz",
+ "integrity": "sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==",
+ "license": "MIT",
+ "peer": true
+ },
"node_modules/toml": {
"version": "2.3.6",
"resolved": "https://registry.npmjs.org/toml/-/toml-2.3.6.tgz",
@@ -19712,6 +21197,18 @@
"url": "https://opencollective.com/unified"
}
},
+ "node_modules/virtualizedtableforantd4": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/virtualizedtableforantd4/-/virtualizedtableforantd4-1.3.1.tgz",
+ "integrity": "sha512-rW8KoToI2nt1jNtweXIUIiygi74XMzKLzUrrtZbGsQc7m3v68AaedPuf4CZcte+nosgYuPEWnAgjuI/KR8BVbg==",
+ "license": "MIT",
+ "peer": true,
+ "peerDependencies": {
+ "antd": "^4.0.0 || ^5.0.0",
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0",
+ "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0"
+ }
+ },
"node_modules/vite": {
"version": "5.4.8",
"resolved": "https://registry.npmjs.org/vite/-/vite-5.4.8.tgz",
@@ -20592,11 +22089,39 @@
"version": "3.22.4",
"resolved": "https://registry.npmjs.org/zod/-/zod-3.22.4.tgz",
"integrity": "sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==",
- "peer": true,
"funding": {
"url": "https://github.com/sponsors/colinhacks"
}
},
+ "node_modules/zustand": {
+ "version": "4.5.5",
+ "resolved": "https://registry.npmjs.org/zustand/-/zustand-4.5.5.tgz",
+ "integrity": "sha512-+0PALYNJNgK6hldkgDq2vLrw5f6g/jCInz52n9RTpropGgeAf/ioFUCdtsjCqu4gNhW9D01rUQBROoRjdzyn2Q==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "use-sync-external-store": "1.2.2"
+ },
+ "engines": {
+ "node": ">=12.7.0"
+ },
+ "peerDependencies": {
+ "@types/react": ">=16.8",
+ "immer": ">=9.0.6",
+ "react": ">=16.8"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "immer": {
+ "optional": true
+ },
+ "react": {
+ "optional": true
+ }
+ }
+ },
"node_modules/zwitch": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz",
diff --git a/package.json b/package.json
index a922f88205..8e528c2ceb 100644
--- a/package.json
+++ b/package.json
@@ -20,6 +20,7 @@
"@mui/x-charts": "^7.22.2",
"@mui/x-data-grid": "^7.22.1",
"@mui/x-date-pickers": "^7.18.0",
+ "@pdfme/common": "^5.2.11",
"@pdfme/generator": "^5.2.3",
"@pdfme/schemas": "^5.1.6",
"@reduxjs/toolkit": "^2.3.0",
diff --git a/public/images/svg/options-outline.svg b/public/images/svg/options-outline.svg
new file mode 100644
index 0000000000..939935eb11
--- /dev/null
+++ b/public/images/svg/options-outline.svg
@@ -0,0 +1,11 @@
+
diff --git a/public/images/svg/organization.svg b/public/images/svg/organization.svg
new file mode 100644
index 0000000000..9bed28f87e
--- /dev/null
+++ b/public/images/svg/organization.svg
@@ -0,0 +1,16 @@
+
\ No newline at end of file
diff --git a/public/locales/en/translation.json b/public/locales/en/translation.json
index 5f6d319588..50e45906f6 100644
--- a/public/locales/en/translation.json
+++ b/public/locales/en/translation.json
@@ -772,6 +772,17 @@
"loading": "Loading...",
"noAttendees": "Attendees not Found"
},
+ "eventRegistrant": {
+ "sort": "Sort",
+ "allRegistrants": "All Registrants",
+ "eventRegistrantsTable": "Event Registrants Table",
+ "serialNumber": "Serial Number",
+ "registrant": "Registrant",
+ "registeredAt": "Registered At",
+ "createdAt": "Created At",
+ "addRegistrant": "Add Registrant",
+ "noRegistrantsFound": "No Registrants Found."
+ },
"onSpotAttendee": {
"title": "On-spot Attendee",
"enterFirstName": "Enter First Name",
diff --git a/public/locales/fr/translation.json b/public/locales/fr/translation.json
index 8dc5fa888a..454abe6de9 100644
--- a/public/locales/fr/translation.json
+++ b/public/locales/fr/translation.json
@@ -1082,6 +1082,17 @@
"loading": "Chargement...",
"noAttendees": "Aucun participant trouvé"
},
+ "eventRegistrant": {
+ "sort": "Trier",
+ "allRegistrants": "Tous les inscrits",
+ "eventRegistrantsTable": "Table des inscrits à l'événement",
+ "serialNumber": "Numéro de série",
+ "registrant": "Inscrit",
+ "registeredAt": "Enregistré le",
+ "createdAt": "Créé le",
+ "addRegistrant": "Ajouter un inscrit",
+ "noRegistrantsFound": "Aucun inscrit trouvé."
+ },
"onSpotAttendee": {
"title": "Participant sur place",
"enterFirstName": "Entrez le prénom",
diff --git a/public/locales/hi/translation.json b/public/locales/hi/translation.json
index 2865e72e1f..49289fed4f 100644
--- a/public/locales/hi/translation.json
+++ b/public/locales/hi/translation.json
@@ -1082,6 +1082,17 @@
"loading": "लोड हो रहा है",
"noAttendees": "कोई प्रतिभागी नहीं मिला"
},
+ "eventRegistrant": {
+ "sort": "छांटें",
+ "allRegistrants": "सभी पंजीकृत व्यक्ति",
+ "eventRegistrantsTable": "इवेंट पंजीकृत व्यक्ति तालिका",
+ "serialNumber": "सिरियल नंबर",
+ "registrant": "पंजीकृत व्यक्ति",
+ "registeredAt": "पंजीकरण तिथि",
+ "createdAt": "निर्माण तिथि",
+ "addRegistrant": "पंजीकृत व्यक्ति जोड़ें",
+ "noRegistrantsFound": "कोई पंजीकृत व्यक्ति नहीं मिला"
+ },
"onSpotAttendee": {
"title": "ऑन-स्पॉट प्रतिभागी",
"enterFirstName": "प्रथम नाम दर्ज करें",
diff --git a/public/locales/sp/translation.json b/public/locales/sp/translation.json
index da91efb41d..606e5063fd 100644
--- a/public/locales/sp/translation.json
+++ b/public/locales/sp/translation.json
@@ -1084,6 +1084,18 @@
"loading": "Cargando...",
"noAttendees": "No se encontraron asistentes"
},
+
+ "eventRegistrant": {
+ "sort": "Ordenar",
+ "allRegistrants": "Todos los registrados",
+ "eventRegistrantsTable": "Tabla de registrados del evento",
+ "serialNumber": "Número de serie",
+ "registrant": "Registrado",
+ "registeredAt": "Registrado en",
+ "createdAt": "Creado en",
+ "addRegistrant": "Agregar registrado",
+ "noRegistrantsFound": "No se encontraron registrados"
+ },
"onSpotAttendee": {
"title": "Asistente en el lugar",
"enterFirstName": "Ingrese el nombre",
diff --git a/public/locales/zh/translation.json b/public/locales/zh/translation.json
index 5fbbf4b870..1138f3df39 100644
--- a/public/locales/zh/translation.json
+++ b/public/locales/zh/translation.json
@@ -1082,6 +1082,17 @@
"loading": "加载中...",
"noAttendees": "未找到参与者"
},
+ "eventRegistrant": {
+ "sort": "排序",
+ "allRegistrants": "所有注册者",
+ "eventRegistrantsTable": "活动注册者表",
+ "serialNumber": "序列号",
+ "registrant": "注册者",
+ "registeredAt": "注册时间",
+ "createdAt": "创建时间",
+ "addRegistrant": "添加注册者",
+ "noRegistrantsFound": "未找到注册者"
+ },
"onSpotAttendee": {
"title": "现场参与者",
"enterFirstName": "输入名字",
diff --git a/src/GraphQl/Queries/Queries.ts b/src/GraphQl/Queries/Queries.ts
index 81442cbad2..9cf1a92755 100644
--- a/src/GraphQl/Queries/Queries.ts
+++ b/src/GraphQl/Queries/Queries.ts
@@ -328,6 +328,16 @@ export const EVENT_ATTENDEES = gql`
}
`;
+export const EVENT_REGISTRANTS = gql`
+ query GetEventAttendeesByEventId($eventId: ID!) {
+ getEventAttendeesByEventId(eventId: $eventId) {
+ userId
+ isRegistered
+ _id
+ }
+ }
+`;
+
export const EVENT_CHECKINS = gql`
query eventCheckIns($id: ID!) {
event(id: $id) {
diff --git a/src/components/CheckIn/CheckInWrapper.module.css b/src/components/CheckIn/CheckInWrapper.module.css
deleted file mode 100644
index f5f42546c3..0000000000
--- a/src/components/CheckIn/CheckInWrapper.module.css
+++ /dev/null
@@ -1,13 +0,0 @@
-button .iconWrapper {
- width: 32px;
- padding-right: 4px;
- margin-right: 4px;
- transform: translateY(4px);
-}
-
-button .iconWrapperSm {
- width: 32px;
- display: flex;
- justify-content: center;
- align-items: center;
-}
diff --git a/src/components/CheckIn/CheckInWrapper.tsx b/src/components/CheckIn/CheckInWrapper.tsx
index 859ae1f869..7b35ce1483 100644
--- a/src/components/CheckIn/CheckInWrapper.tsx
+++ b/src/components/CheckIn/CheckInWrapper.tsx
@@ -1,8 +1,7 @@
import React, { useState } from 'react';
import { CheckInModal } from './CheckInModal';
import { Button } from 'react-bootstrap';
-import IconComponent from 'components/IconComponent/IconComponent';
-import styles from './CheckInWrapper.module.css';
+import style from '../../style/app.module.css';
type PropType = {
eventId: string;
@@ -21,19 +20,19 @@ export const CheckInWrapper = ({ eventId }: PropType): JSX.Element => {
return (
<>
{
setShowModal(true);
}}
>
-
-
-
+
Check In Registrants
{showModal && (
diff --git a/src/components/CheckIn/tagTemplate.ts b/src/components/CheckIn/tagTemplate.ts
index 4aa4475e02..8f0e9730a3 100644
--- a/src/components/CheckIn/tagTemplate.ts
+++ b/src/components/CheckIn/tagTemplate.ts
@@ -2,8 +2,9 @@ import { Template } from '@pdfme/common';
export const tagTemplate: Template = {
schemas: [
- {
- name: {
+ [
+ {
+ name: 'name',
type: 'text',
position: { x: 14.91, y: 27.03 },
width: 58.55,
@@ -15,7 +16,7 @@ export const tagTemplate: Template = {
fontName: 'Roboto',
fontColor: '#08780b',
},
- },
+ ],
],
basePdf:
'data:application/pdf;base64,JVBERi0xLjQKJfbk/N8KMSAwIG9iago8PAovVHlwZSAvQ2F0YWxvZwovVmVyc2lvbiAvMS40Ci9QYWdlcyAyIDAgUgovU3RydWN0VHJlZVJvb3QgMyAwIFIKL01hcmtJbmZvIDQgMCBSCi9MYW5nIChlbikKL1ZpZXdlclByZWZlcmVuY2VzIDUgMCBSCj4+CmVuZG9iago2IDAgb2JqCjw8Ci9DcmVhdG9yIChDYW52YSkKL1Byb2R1Y2VyIChDYW52YSkKL0NyZWF0aW9uRGF0ZSAoRDoyMDIzMDYyMDA3MjgxMyswMCcwMCcpCi9Nb2REYXRlIChEOjIwMjMwNjIwMDcyODEzKzAwJzAwJykKL0tleXdvcmRzIChEQUZjMjhYSXViTSxCQUUycS01WEdhaykKL0F1dGhvciAoRXNoYWFuIEFnZ2Fyd2FsKQovVGl0bGUgKEJsYW5rIE5hbWUgVGFnIGluIEVtZXJhbGQgTWludCBHcmVlbiBBc3BpcmF0aW9uYWwgRWxlZ2FuY2UgU3R5bGUpCj4+CmVuZG9iagoyIDAgb2JqCjw8Ci9UeXBlIC9QYWdlcwovS2lkcyBbNyAwIFJdCi9Db3VudCAxCj4+CmVuZG9iagozIDAgb2JqCjw8Ci9UeXBlIC9TdHJ1Y3RUcmVlUm9vdAovUGFyZW50VHJlZSA4IDAgUgovUGFyZW50VHJlZU5leHRLZXkgMQovSyBbOSAwIFJdCi9JRFRyZWUgMTAgMCBSCj4+CmVuZG9iago0IDAgb2JqCjw8Ci9NYXJrZWQgdHJ1ZQovU3VzcGVjdHMgZmFsc2UKPj4KZW5kb2JqCjUgMCBvYmoKPDwKL0Rpc3BsYXlEb2NUaXRsZSB0cnVlCj4+CmVuZG9iago3IDAgb2JqCjw8Ci9UeXBlIC9QYWdlCi9SZXNvdXJjZXMgMTEgMCBSCi9NZWRpYUJveCBbMC4wIDcuOTIwMDAyNSAyNTIuMCAxNTEuOTJdCi9Db250ZW50cyAxMiAwIFIKL1N0cnVjdFBhcmVudHMgMAovUGFyZW50IDIgMCBSCi9UYWJzIC9TCi9CbGVlZEJveCBbMC4wIDcuOTIwMDAyNSAyNTIuMCAxNTEuOTJdCi9UcmltQm94IFswLjAgNy45MjAwMDI1IDI1Mi4wIDE1MS45Ml0KL0Nyb3BCb3ggWzAuMCA3LjkyMDAwMjUgMjUyLjAgMTUxLjkyXQovUm90YXRlIDAKL0Fubm90cyBbXQo+PgplbmRvYmoKOCAwIG9iago8PAovTGltaXRzIFswIDBdCi9OdW1zIFswIFsxMyAwIFIgMTQgMCBSIDE1IDAgUiAxNiAwIFIgMTcgMCBSIDE4IDAgUiAxOSAwIFJdCl0KPj4KZW5kb2JqCjkgMCBvYmoKPDwKL1R5cGUgL1N0cnVjdEVsZW0KL1MgL0RvY3VtZW50Ci9MYW5nIChlbikKL1AgMyAwIFIKL0sgWzIwIDAgUl0KL0lEIChub2RlMDAwMDE3MzgpCj4+CmVuZG9iagoxMCAwIG9iago8PAovTmFtZXMgWyhub2RlMDAwMDE3MzgpIDkgMCBSIChub2RlMDAwMDE3MzkpIDEzIDAgUiAobm9kZTAwMDAxNzQwKSAyMCAwIFIgKG5vZGUwMDAwMTc0MSkgMjEgMCBSIChub2RlMDAwMDE3NDIpIDIyIDAgUgoobm9kZTAwMDAxNzQzKSAyMyAwIFIgKG5vZGUwMDAwMTc0NCkgMjQgMCBSIChub2RlMDAwMDE3NDUpIDI1IDAgUiAobm9kZTAwMDAxNzQ2KSAyNiAwIFIgKG5vZGUwMDAwMTc0NykgMjcgMCBSCihub2RlMDAwMDE3NjEpIDI4IDAgUiAobm9kZTAwMDAxNzYyKSAyOSAwIFIgKG5vZGUwMDAwMTc2MykgMzAgMCBSIChub2RlMDAwMDE3NjQpIDMxIDAgUiAobm9kZTAwMDAxNzY1KSAzMiAwIFIKKG5vZGUwMDAwMTc2NikgMzMgMCBSIChub2RlMDAwMDE3NjcpIDE0IDAgUiAobm9kZTAwMDAxNzY4KSAzNCAwIFIgKG5vZGUwMDAwMTc2OSkgMzUgMCBSIChub2RlMDAwMDE3NzApIDM2IDAgUgoobm9kZTAwMDAxNzcxKSAxNSAwIFIgKG5vZGUwMDAwMTc3MikgMzcgMCBSIChub2RlMDAwMDE3NzMpIDM4IDAgUiAobm9kZTAwMDAxNzc0KSAzOSAwIFIgKG5vZGUwMDAwMTc3NSkgMTYgMCBSCihub2RlMDAwMDE3NzYpIDE3IDAgUiAobm9kZTAwMDAxNzc3KSA0MCAwIFIgKG5vZGUwMDAwMTc3OCkgMTggMCBSIChub2Rl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Tm9uU3RydWN0Ci9QIDQwIDAgUgovSyBbNTMgMCBSXQovSUQgKG5vZGUwMDAwMTc3OCkKPj4KZW5kb2JqCjE5IDAgb2JqCjw8Ci9UeXBlIC9TdHJ1Y3RFbGVtCi9TIC9Ob25TdHJ1Y3QKL1AgNDQgMCBSCi9LIFs1NCAwIFJdCi9JRCAobm9kZTAwMDAxNzgzKQo+PgplbmRvYmoKMjAgMCBvYmoKPDwKL1R5cGUgL1N0cnVjdEVsZW0KL1MgL0RpdgovUCA5IDAgUgovSyBbMjEgMCBSXQovSUQgKG5vZGUwMDAwMTc0MCkKPj4KZW5kb2JqCjIxIDAgb2JqCjw8Ci9UeXBlIC9TdHJ1Y3RFbGVtCi9TIC9EaXYKL1AgMjAgMCBSCi9LIFsyMiAwIFJdCi9JRCAobm9kZTAwMDAxNzQxKQo+PgplbmRvYmoKMjIgMCBvYmoKPDwKL1R5cGUgL1N0cnVjdEVsZW0KL1MgL0RpdgovUCAyMSAwIFIKL0sgWzIzIDAgUl0KL0lEIChub2RlMDAwMDE3NDIpCj4+CmVuZG9iagoyMyAwIG9iago8PAovVHlwZSAvU3RydWN0RWxlbQovUyAvRGl2Ci9QIDIyIDAgUgovSyBbMjQgMCBSXQovSUQgKG5vZGUwMDAwMTc0MykKPj4KZW5kb2JqCjI0IDAgb2JqCjw8Ci9UeXBlIC9TdHJ1Y3RFbGVtCi9TIC9EaXYKL1AgMjMgMCBSCi9LIFsyNSAwIFJdCi9JRCAobm9kZTAwMDAxNzQ0KQo+PgplbmRvYmoKMjUgMCBvYmoKPDwKL1R5cGUgL1N0cnVjdEVsZW0KL1MgL0RpdgovUCAyNCAwIFIKL0sgWzI2IDAgUl0KL0lEIChub2RlMDAwMDE3NDUpCj4+CmVuZG9iagoyNiAwIG9iago8PAovVHlwZSAvU3RydWN0RWxlbQovUyAvRGl2Ci9QIDI1IDAgUgovSyBbMjcgMCBSXQovSUQgKG5vZGUwMDAwMTc0NikKPj4KZW5kb2JqCjI3IDAgb2JqCjw8Ci9UeXBlIC9TdHJ1Y3RFbGVtCi9TIC9EaXYKL1AgMjYgMCBSCi9LIFsyOCAwIFIgMzEgMCBSIDM0IDAgUiAzNyAwIFIgNDEgMCBSXQovSUQgKG5vZGUwMDAwMTc0NykKPj4KZW5kb2JqCjI4IDAgb2JqCjw8Ci9UeXBlIC9TdHJ1Y3RFbGVtCi9TIC9EaXYKL1AgMjcgMCBSCi9LIFsyOSAwIFJdCi9JRCAobm9kZTAwMDAxNzYxKQo+PgplbmRvYmoKMjkgMCBvYmoKPDwKL1R5cGUgL1N0cnVjdEVsZW0KL1MgL0RpdgovUCAyOCAwIFIKL0sgWzMwIDAgUl0KL0lEIChub2RlMDAwMDE3NjIpCj4+CmVuZG9iagozMCAwIG9iago8PAovVHlwZSAvU3RydWN0RWxlbQovUyAvRGl2Ci9QIDI5IDAgUgovSyBbMTMgMCBSXQovSUQgKG5vZGUwMDAwMTc2MykKPj4KZW5kb2JqCjMxIDAgb2JqCjw8Ci9UeXBlIC9TdHJ1Y3RFbGVtCi9TIC9EaXYKL1AgMjcgMCBSCi9LIFszMiAwIFJdCi9JRCAobm9kZTAwMDAxNzY0KQo+PgplbmRvYmoKMzIgMCBvYmoKPDwKL1R5cGUgL1N0cnVjdEVsZW0KL1MgL0RpdgovUCAzMSAwIFIKL0sgWzMzIDAgUl0KL0lEIChub2RlMDAwMDE3NjUpCj4+CmVuZG9iagozMyAwIG9iago8PAovVHlwZSAvU3RydWN0RWxlbQovUyAvUAovUCAzMiAwIFIKL0sgWzE0IDAgUl0KL0lEIChub2RlMDAwMDE3NjYpCj4+CmVuZG9iagozNCAwIG9iago8PAovVHlwZSAvU3RydWN0RWxlbQovUyAvRGl2Ci9QIDI3IDAgUgovSyBbMzUgMCBSXQovSUQgKG5vZGUwMDAwMTc2OCkKPj4KZW5kb2JqCjM1IDAgb2JqCjw8Ci9UeXBlIC9TdHJ1Y3RFbGVtCi9TIC9EaXYKL1AgMzQgMCBSCi9LIFszNiAwIFJdCi9JRCAobm9kZTAwMDAxNzY5KQo+PgplbmRvYmoKMzYgMCBvYmoKPDwKL1R5cGUgL1N0cnVjdEVsZW0KL1MgL1AKL1AgMzUgMCBSCi9LIFsxNSAwIFJdCi9JRCAobm9kZTAwMDAxNzcwKQo+PgplbmRvYmoKMzcgMCBvYmoKPDwKL1R5cGUgL1N0cnVjdEVsZW0KL1MgL0RpdgovUCAyNyAwIFIKL0sgWzM4IDAgUl0KL0lEIChub2RlMDAwMDE3NzIpCj4+CmVuZG9iagozOCAwIG9iago8PAovVHlwZSAvU3RydWN0RWxlbQovUyAvRGl2Ci9QIDM3IDAgUgovSyBbMzkgMCBSIDQwIDAgUl0KL0lEIChub2RlMDAwMDE3NzMpCj4+CmVuZG9iagozOSAwIG9iago8PAovVHlwZSAvU3RydWN0RWxlbQovUyAvUAovUCAzOCAwIFIKL0sgWzE2IDAgUiAxNyAwIFJdCi9JRCAobm9kZTAwMDAxNzc0KQo+PgplbmRvYmoKNDAgMCBvYmoKPDwKL1R5cGUgL1N0cnVjdEVsZW0KL1MgL1AKL1AgMzggMCBSCi9LIFsxOCAwIFJdCi9JRCAobm9kZTAwMDAxNzc3KQo+PgplbmRvYmoKNDEgMCBvYmoKPDwKL1R5cGUgL1N0cnVjdEVsZW0KL1MgL0RpdgovUCAyNyAwIFIKL0sgWzQyIDAgUl0KL0lEIChub2RlMDAwMDE3NzkpCj4+CmVuZG9iago0MiAwIG9iago8PAovVHlwZSAvU3RydWN0RWxlbQovUyAvRGl2Ci9QIDQxIDAgUgovSyBbNDMgMCBSXQovSUQgKG5vZGUwMDAwMTc4MCkKPj4KZW5kb2JqCjQzIDAgb2JqCjw8Ci9UeXBlIC9TdHJ1Y3RFbGVtCi9TIC9EaXYKL1AgNDIgMCBSCi9LIFs0NCAwIFJdCi9JRCAobm9kZTAwMDAxNzgxKQo+PgplbmRvYmoKNDQgMCBvYmoKPDwKL1R5cGUgL1N0cnVjdEVsZW0KL1MgL1AKL1AgNDMgMCBSCi9LIFsxOSAwIFJdCi9JRCAobm9kZTAwMDAxNzgyKQo+PgplbmRvYmoKNDUgMCBvYmoKPDwKL0czIDU1IDAgUgovRzQgNTYgMCBSCj4+CmVuZG9iago0NiAwIG9iago8PAovTGVuZ3RoIDMwMTg4Ci9UeXBlIC9YT2JqZWN0Ci9TdWJ0eXBlIC9JbWFnZQovV2lkdGggMzQ3Ci9IZWlnaHQgMjMzCi9Db2xvclNwYWNlIC9EZXZpY2VSR0IKL1NNYXNrIDU3IDAgUgovQml0c1BlckNvbXBvbmVudCA4Ci9GaWx0ZXIgL0ZsYXRlRGVjb2RlCj4+CnN0cmVhbQ0KeJzsfQl4FNeVbgmpN6GuajDYY1tIIpPJm8dbJhkyb5LJTIaZJCaYRRvCwTEOjmNi42DAZjGLpNbGamOMgVgJGGMMxo3QvqKltQsB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arVJSZxajbW01KrRlKs9h/BjZkdpqcM8035UbS3VWNRqi6bMzXLBceLFI+QgnL9QSjQ3F284UObxlJW5XMTrMpvcbpMZXofoP5F+JXQNCmVuZHN0cmVhbQplbmRvYmoKeHJlZgowIDY0CjAwMDAwMDAwMDAgNjU1MzUgZg0KMDAwMDAwMDAxNSAwMDAwMCBuDQowMDAwMDAwNDE5IDAwMDAwIG4NCjAwMDAwMDA0NzYgMDAwMDAgbg0KMDAwMDAwMDU4NCAwMDAwMCBuDQowMDAwMDAwNjM0IDAwMDAwIG4NCjAwMDAwMDAxNTIgMDAwMDAgbg0KMDAwMDAwMDY3NyAwMDAwMCBuDQowMDAwMDAwOTYwIDAwMDAwIG4NCjAwMDAwMDEwNTcgMDAwMDAgbg0KMDAwMDAwMTE2MCAwMDAwMCBuDQowMDAwMDAxOTE2IDAwMDAwIG4NCjAwMDAwMDIwNDEgMDAwMDAgbg0KMDAwMDAwMzA5NCAwMDAwMCBuDQowMDAwMDAzMTg2IDAwMDAwIG4NCjAwMDAwMDMyODEgMDAwMDAgbg0KMDAwMDAwMzM3NiAwMDAwMCBuDQowMDAwMDAzNDcxIDAwMDAwIG4NCjAwMDAwMDM1NjYgMDAwMDAgbg0KMDAwMDAwMzY2MSAwMDAwMCBuDQowMDAwMDAzNzU2IDAwMDAwIG4NCjAwMDAwMDM4NDQgMDAwMDAgbg0KMDAwMDAwMzkzMyAwMDAwMCBuDQowMDAwMDA0MDIyIDAwMDAwIG4NCjAwMDAwMDQxMTEgMDAwMDAgbg0KMDAwMDAwNDIwMCAwMDAwMCBuDQowMDAwMDA0Mjg5IDAwMDAwIG4NCjAwMDAwMDQzNzggMDAwMDAgbg0KMDAwMDAwNDQ5NSAwMDAwMCBuDQowMDAwMDA0NTg0IDAwMDAwIG4NCjAwMDAwMDQ2NzMgMDAwMDAgbg0KMDAwMDAwNDc2MiAwMDAwMCBuDQowMDAwMDA0ODUxIDAwMDAwIG4NCjAwMDAwMDQ5NDAgMDAwMDAgbg0KMDAwMDAwNTAyNyAwMDAwMCBuDQowMDAwMDA1MTE2IDAwMDAwIG4NCjAwMDAwMDUyMDUgMDAwMDAgbg0KMDAwMDAwNTI5MiAwMDAwMCBuDQowMDAwMDA1MzgxIDAwMDAwIG4NCjAwMDAwMDU0NzcgMDAwMDAgbg0KMDAwMDAwNTU3MSAwMDAwMCBuDQowMDAwMDA1NjU4IDAwMDAwIG4NCjAwMDAwMDU3NDcgMDAwMDAgbg0KMDAwMDAwNTgzNiAwMDAwMCBuDQowMDAwMDA1OTI1IDAwMDAwIG4NCjAwMDAwMDYwMTIgMDAwMDAgbg0KMDAwMDAwNjA1NiAwMDAwMCBuDQowMDAwMDM2NDMyIDAwMDAwIG4NCjAwMDAwMzY0NjUgMDAwMDAgbg0KMDAwMDAzNjUxNiAwMDAwMCBuDQowMDAwMDM2NTY3IDAwMDAwIG4NCjAwMDAwMzY2MTggMDAwMDAgbg0KMDAwMDAzNjY2OSAwMDAwMCBuDQowMDAwMDM2NzIwIDAwMDAwIG4NCjAwMDAwMzY3NzEgMDAwMDAgbg0KMDAwMDAzNjgyMiAwMDAwMCBuDQowMDAwMDM2ODYyIDAwMDAwIG4NCjAwMDAwMzY5NDEgMDAwMDAgbg0KMDAwMDA0OTMxNiAwMDAwMCBuDQowMDAwMDQ5NDY5IDAwMDAwIG4NCjAwMDAwNTAwMzcgMDAwMDAgbg0KMDAwMDA1MDQ2NSAwMDAwMCBuDQowMDAwMDUwNzIwIDAwMDAwIG4NCjAwMDAwNTA3OTUgMDAwMDAgbg0KdHJhaWxlcgo8PAovUm9vdCAxIDAgUgovSW5mbyA2IDAgUgovSUQgWzwwQ0M3NzdBRDZENEFBMThFRkFGQ0ExODQ3QjI1QkMxQz4gPDBDQzc3N0FENkQ0QUExOEVGQUZDQTE4NDdCMjVCQzFDPl0KL1NpemUgNjQKPj4Kc3RhcnR4cmVmCjU0MDk2CiUlRU9GCg==',
diff --git a/src/components/EventManagement/EventRegistrant/EventRegistrants.spec.tsx b/src/components/EventManagement/EventRegistrant/EventRegistrants.spec.tsx
new file mode 100644
index 0000000000..828362706a
--- /dev/null
+++ b/src/components/EventManagement/EventRegistrant/EventRegistrants.spec.tsx
@@ -0,0 +1,264 @@
+import React from 'react';
+import { MockedProvider } from '@apollo/react-testing';
+import type { RenderResult } from '@testing-library/react';
+import { render, screen, cleanup, waitFor } from '@testing-library/react';
+import { Provider } from 'react-redux';
+import { BrowserRouter } from 'react-router-dom';
+import { I18nextProvider } from 'react-i18next';
+import EventRegistrants from './EventRegistrants';
+import { store } from 'state/store';
+import { StaticMockLink } from 'utils/StaticMockLink';
+import i18n from 'utils/i18nForTest';
+import { REGISTRANTS_MOCKS } from './Registrations.mocks';
+import { MOCKS as ATTENDEES_MOCKS } from '../EventAttendance/Attendance.mocks';
+import { vi } from 'vitest';
+import { EVENT_REGISTRANTS, EVENT_ATTENDEES } from 'GraphQl/Queries/Queries';
+
+const COMBINED_MOCKS = [...REGISTRANTS_MOCKS, ...ATTENDEES_MOCKS];
+
+const link = new StaticMockLink(COMBINED_MOCKS, true);
+
+async function wait(): Promise {
+ await waitFor(() => {
+ return Promise.resolve();
+ });
+}
+
+const renderEventRegistrants = (): RenderResult => {
+ return render(
+
+
+
+
+
+
+
+
+ ,
+ );
+};
+
+describe('Event Registrants Component', () => {
+ beforeEach(() => {
+ vi.mock('react-router-dom', async () => {
+ const actual = await vi.importActual('react-router-dom');
+ return {
+ ...actual,
+ useParams: () => ({ eventId: 'event123', orgId: 'org123' }),
+ useNavigate: vi.fn(),
+ };
+ });
+ });
+
+ afterEach(() => {
+ vi.clearAllMocks();
+ cleanup();
+ });
+
+ test('Component loads correctly with table headers', async () => {
+ renderEventRegistrants();
+
+ await wait();
+
+ await waitFor(() => {
+ expect(screen.getByTestId('table-header-serial')).toBeInTheDocument();
+ expect(screen.getByTestId('table-header-registrant')).toBeInTheDocument();
+ expect(screen.getByTestId('table-header-created-at')).toBeInTheDocument();
+ expect(
+ screen.getByTestId('table-header-add-registrant'),
+ ).toBeInTheDocument();
+ });
+ });
+
+ test('Renders registrants button correctly', async () => {
+ renderEventRegistrants();
+
+ await waitFor(() => {
+ expect(screen.getByTestId('stats-modal')).toBeInTheDocument();
+ expect(screen.getByTestId('filter-button')).toBeInTheDocument();
+ });
+ });
+
+ test('Handles empty registrants list', async () => {
+ const emptyMocks = [
+ {
+ request: {
+ query: EVENT_REGISTRANTS,
+ variables: { eventId: '660fdf7d2c1ef6c7db1649ad' },
+ },
+ result: {
+ data: {
+ getEventAttendeesByEventId: [],
+ },
+ },
+ },
+ {
+ request: {
+ query: EVENT_ATTENDEES,
+ variables: { id: '660fdf7d2c1ef6c7db1649ad' },
+ },
+ result: {
+ data: {
+ event: {
+ attendees: [],
+ },
+ },
+ },
+ },
+ ];
+
+ const customLink = new StaticMockLink(emptyMocks, true);
+ render(
+
+
+
+
+
+
+
+
+ ,
+ );
+
+ await waitFor(() => {
+ expect(screen.getByTestId('no-registrants')).toBeInTheDocument();
+ });
+ });
+
+ test('Successfully combines and displays registrant and attendee data', async () => {
+ const mockData = [
+ {
+ request: {
+ query: EVENT_REGISTRANTS,
+ variables: { eventId: 'event123' },
+ },
+ result: {
+ data: {
+ getEventAttendeesByEventId: [
+ {
+ _id: '1',
+ userId: 'user1',
+ isRegistered: true,
+ __typename: 'EventAttendee',
+ },
+ ],
+ },
+ },
+ },
+ {
+ request: {
+ query: EVENT_ATTENDEES,
+ variables: { id: 'event123' },
+ },
+ result: {
+ data: {
+ event: {
+ attendees: [
+ {
+ _id: 'user1',
+ firstName: 'John',
+ lastName: 'Doe',
+ createdAt: '2023-09-25T10:00:00.000Z',
+ __typename: 'User',
+ },
+ ],
+ },
+ },
+ },
+ },
+ ];
+
+ const customLink = new StaticMockLink(mockData, true);
+ render(
+
+
+
+
+
+
+
+
+ ,
+ );
+
+ await waitFor(() => {
+ expect(screen.getByTestId('registrant-row-0')).toBeInTheDocument();
+ });
+
+ // Validate mapped data
+ expect(screen.getByTestId('attendee-name-0')).toHaveTextContent('John Doe');
+ expect(screen.getByTestId('registrant-registered-at-0')).toHaveTextContent(
+ '2023-09-25',
+ );
+ expect(screen.getByTestId('registrant-created-at-0')).toHaveTextContent(
+ '10:00:00',
+ );
+ });
+
+ test('Handles missing attendee data with fallback values', async () => {
+ const mocksWithMissingFields = [
+ {
+ request: {
+ query: EVENT_REGISTRANTS,
+ variables: { eventId: 'event123' },
+ },
+ result: {
+ data: {
+ getEventAttendeesByEventId: [
+ {
+ _id: '1',
+ userId: 'user1',
+ isRegistered: true,
+ __typename: 'EventAttendee',
+ },
+ ],
+ },
+ },
+ },
+ {
+ request: {
+ query: EVENT_ATTENDEES,
+ variables: { id: 'event123' },
+ },
+ result: {
+ data: {
+ event: {
+ attendees: [
+ {
+ _id: 'user1',
+ firstName: 'Jane',
+ lastName: 'Doe',
+ createdAt: null,
+ __typename: 'User',
+ },
+ ],
+ },
+ },
+ },
+ },
+ ];
+
+ const customLink = new StaticMockLink(mocksWithMissingFields, true);
+ render(
+
+
+
+
+
+
+
+
+ ,
+ );
+
+ await waitFor(() => {
+ expect(screen.getByTestId('registrant-row-0')).toBeInTheDocument();
+ });
+
+ // Validate fallback values
+ expect(screen.getByTestId('attendee-name-0')).toHaveTextContent('Jane Doe');
+ expect(screen.getByTestId('registrant-created-at-0')).toHaveTextContent(
+ 'N/A',
+ );
+ });
+});
diff --git a/src/components/EventManagement/EventRegistrant/EventRegistrants.tsx b/src/components/EventManagement/EventRegistrant/EventRegistrants.tsx
new file mode 100644
index 0000000000..efcc2e91f7
--- /dev/null
+++ b/src/components/EventManagement/EventRegistrant/EventRegistrants.tsx
@@ -0,0 +1,227 @@
+import React, { useEffect, useState, useCallback } from 'react';
+import {
+ Paper,
+ TableCell,
+ TableContainer,
+ TableHead,
+ TableRow,
+ TableBody,
+} from '@mui/material';
+import { Button, Table } from 'react-bootstrap';
+import { useTranslation } from 'react-i18next';
+import style from '../../../style/app.module.css';
+import { useLazyQuery } from '@apollo/client';
+import { EVENT_ATTENDEES, EVENT_REGISTRANTS } from 'GraphQl/Queries/Queries';
+import { useParams } from 'react-router-dom';
+import type { InterfaceMember } from '../EventAttendance/InterfaceEvents';
+import { EventRegistrantsWrapper } from 'components/EventRegistrantsModal/EventRegistrantsWrapper';
+import { CheckInWrapper } from 'components/CheckIn/CheckInWrapper';
+/**
+ * Interface for user data
+ */
+interface InterfaceUser {
+ _id: string;
+ userId: string;
+ isRegistered: boolean;
+ __typename: string;
+ time: string;
+}
+/**
+ * Component to manage and display event registrant information
+ * Includes adding new registrants and check-in functionality for registrants
+ * @returns JSX element containing the event attendance interface
+ */
+function EventRegistrants(): JSX.Element {
+ const { t } = useTranslation('translation', {
+ keyPrefix: 'eventRegistrant',
+ });
+ const { orgId, eventId } = useParams<{ orgId: string; eventId: string }>();
+ const [registrants, setRegistrants] = useState([]);
+ const [attendees, setAttendees] = useState([]);
+ const [combinedData, setCombinedData] = useState<
+ (InterfaceUser & Partial)[]
+ >([]);
+ // Fetch registrants
+ const [getEventRegistrants] = useLazyQuery(EVENT_REGISTRANTS, {
+ variables: { eventId },
+ fetchPolicy: 'cache-and-network',
+ onCompleted: (data) => {
+ if (data?.getEventAttendeesByEventId) {
+ const mappedData = data.getEventAttendeesByEventId.map(
+ (attendee: InterfaceUser) => ({
+ _id: attendee._id,
+ userId: attendee.userId,
+ isRegistered: attendee.isRegistered,
+ __typename: attendee.__typename,
+ }),
+ );
+ setRegistrants(mappedData);
+ }
+ },
+ });
+ // Fetch attendees
+ const [getEventAttendees] = useLazyQuery(EVENT_ATTENDEES, {
+ variables: { id: eventId },
+ fetchPolicy: 'cache-and-network',
+ onCompleted: (data) => {
+ if (data?.event?.attendees) {
+ setAttendees(data.event.attendees);
+ }
+ },
+ });
+ // callback function to refresh the data
+ const refreshData = useCallback(() => {
+ getEventRegistrants();
+ getEventAttendees();
+ }, [getEventRegistrants, getEventAttendees]);
+ useEffect(() => {
+ refreshData();
+ }, [refreshData]);
+ // Combine registrants and attendees data
+ useEffect(() => {
+ if (registrants.length > 0 && attendees.length > 0) {
+ const mergedData = registrants.map((registrant) => {
+ const matchedAttendee = attendees.find(
+ (attendee) => attendee._id === registrant.userId,
+ );
+ const [date, timeWithMilliseconds] = matchedAttendee?.createdAt
+ ? matchedAttendee.createdAt.split('T')
+ : ['N/A', 'N/A'];
+ const [time] =
+ timeWithMilliseconds !== 'N/A'
+ ? timeWithMilliseconds.split('.')
+ : ['N/A'];
+ return {
+ ...registrant,
+ firstName: matchedAttendee?.firstName || 'N/A',
+ lastName: matchedAttendee?.lastName || 'N/A',
+ createdAt: date,
+ time: time,
+ };
+ });
+ setCombinedData(mergedData);
+ }
+ }, [registrants, attendees]);
+ return (
+
+
+ {eventId ? (
+
+ ) : (
+
+ )}
+
+
+ {t('allRegistrants')}
+
+
+
+
+
+
+
+ {t('serialNumber')}
+
+
+ {t('registrant')}
+
+
+ {t('registeredAt')}
+
+
+ {t('createdAt')}
+
+
+ {t('addRegistrant')}
+
+
+
+
+ {combinedData.length === 0 ? (
+
+
+ {t('noRegistrantsFound')}
+
+
+ ) : (
+ combinedData.map((data, index) => (
+
+
+ {index + 1}
+
+
+ {data.firstName} {data.lastName}
+
+
+ {data.createdAt}
+
+
+ {data.time}
+
+
+ {eventId && orgId && (
+
+ )}
+
+
+ ))
+ )}
+
+
+
+
+ );
+}
+export default EventRegistrants;
diff --git a/src/components/EventManagement/EventRegistrant/Registrations.mocks.ts b/src/components/EventManagement/EventRegistrant/Registrations.mocks.ts
new file mode 100644
index 0000000000..d71714459e
--- /dev/null
+++ b/src/components/EventManagement/EventRegistrant/Registrations.mocks.ts
@@ -0,0 +1,67 @@
+import { EVENT_REGISTRANTS, EVENT_ATTENDEES } from 'GraphQl/Queries/Queries';
+
+export const REGISTRANTS_MOCKS = [
+ {
+ request: {
+ query: EVENT_REGISTRANTS,
+ variables: { eventId: '660fdf7d2c1ef6c7db1649ad' },
+ },
+ result: {
+ data: {
+ getEventAttendeesByEventId: [
+ {
+ _id: '6589386a2caa9d8d69087484',
+ userId: '6589386a2caa9d8d69087484',
+ isRegistered: true,
+ __typename: 'EventAttendee',
+ },
+ {
+ _id: '6589386a2caa9d8d69087485',
+ userId: '6589386a2caa9d8d69087485',
+ isRegistered: true,
+ __typename: 'EventAttendee',
+ },
+ ],
+ },
+ },
+ },
+ {
+ request: {
+ query: EVENT_ATTENDEES,
+ variables: { id: '660fdf7d2c1ef6c7db1649ad' },
+ },
+ result: {
+ data: {
+ event: {
+ attendees: [
+ {
+ _id: '6589386a2caa9d8d69087484',
+ firstName: 'Bruce',
+ lastName: 'Garza',
+ createdAt: '2023-04-13T10:23:17.742Z',
+ __typename: 'User',
+ },
+ {
+ _id: '6589386a2caa9d8d69087485',
+ firstName: 'Jane',
+ lastName: 'Smith',
+ createdAt: '2023-04-13T10:23:17.742Z',
+ __typename: 'User',
+ },
+ ],
+ },
+ },
+ },
+ },
+];
+
+export const REGISTRANTS_MOCKS_ERROR = [
+ {
+ // Error mock for EVENT_REGISTRANTS query
+ request: {
+ query: EVENT_REGISTRANTS,
+ variables: { eventId: 'event123' },
+ },
+ error: new Error('An error occurred while fetching registrants'),
+ },
+];
diff --git a/src/components/EventRegistrantsModal/EventRegistrantsWrapper.module.css b/src/components/EventRegistrantsModal/EventRegistrantsWrapper.module.css
deleted file mode 100644
index 59b31333af..0000000000
--- a/src/components/EventRegistrantsModal/EventRegistrantsWrapper.module.css
+++ /dev/null
@@ -1,13 +0,0 @@
-button .iconWrapper {
- width: 36px;
- padding-right: 4px;
- margin-right: 4px;
- transform: translateY(4px);
-}
-
-button .iconWrapperSm {
- width: 36px;
- display: flex;
- justify-content: center;
- align-items: center;
-}
diff --git a/src/components/EventRegistrantsModal/EventRegistrantsWrapper.test.tsx b/src/components/EventRegistrantsModal/EventRegistrantsWrapper.test.tsx
index d1707e8520..95ac347bc4 100644
--- a/src/components/EventRegistrantsModal/EventRegistrantsWrapper.test.tsx
+++ b/src/components/EventRegistrantsModal/EventRegistrantsWrapper.test.tsx
@@ -77,7 +77,7 @@ describe('Testing Event Registrants Wrapper', () => {
);
// Open the modal
- fireEvent.click(queryByText('Show Registrants') as Element);
+ fireEvent.click(queryByText('Add Registrants') as Element);
await waitFor(() =>
expect(queryByText('Event Registrants')).toBeInTheDocument(),
diff --git a/src/components/EventRegistrantsModal/EventRegistrantsWrapper.tsx b/src/components/EventRegistrantsModal/EventRegistrantsWrapper.tsx
index b198fcdd6d..36b6679a9f 100644
--- a/src/components/EventRegistrantsModal/EventRegistrantsWrapper.tsx
+++ b/src/components/EventRegistrantsModal/EventRegistrantsWrapper.tsx
@@ -1,13 +1,13 @@
import React, { useState } from 'react';
import { EventRegistrantsModal } from './EventRegistrantsModal';
import { Button } from 'react-bootstrap';
-import IconComponent from 'components/IconComponent/IconComponent';
-import styles from './EventRegistrantsWrapper.module.css';
+import style from '../../style/app.module.css';
// Props for the EventRegistrantsWrapper component
type PropType = {
eventId: string;
orgId: string;
+ onUpdate?: () => void;
};
/**
@@ -20,37 +20,37 @@ type PropType = {
export const EventRegistrantsWrapper = ({
eventId,
orgId,
+ onUpdate,
}: PropType): JSX.Element => {
// State to control the visibility of the modal
const [showModal, setShowModal] = useState(false);
+ const handleClose = (): void => {
+ setShowModal(false);
+ // Call onUpdate after modal is closed
+ if (onUpdate) {
+ onUpdate();
+ }
+ };
return (
<>
{/* Button to open the event registrants modal */}
{
setShowModal(true); // Show the modal when button is clicked
}}
>
-
-
-
- Show Registrants
+ Add Registrants
{/* Render the EventRegistrantsModal if showModal is true */}
{showModal && (
{
- setShowModal(false); // Hide the modal when closed
- }}
+ handleClose={handleClose}
eventId={eventId}
orgId={orgId}
/>
diff --git a/src/screens/EventManagement/EventManagement.tsx b/src/screens/EventManagement/EventManagement.tsx
index 2e5cdbd419..e355ac1acc 100644
--- a/src/screens/EventManagement/EventManagement.tsx
+++ b/src/screens/EventManagement/EventManagement.tsx
@@ -17,6 +17,7 @@ import VolunteerContainer from 'screens/EventVolunteers/VolunteerContainer';
import EventAgendaItems from 'components/EventManagement/EventAgendaItems/EventAgendaItems';
import useLocalStorage from 'utils/useLocalstorage';
import EventAttendance from 'components/EventManagement/EventAttendance/EventAttendance';
+import EventRegistrants from 'components/EventManagement/EventRegistrant/EventRegistrants';
/**
* List of tabs for the event dashboard.
*
@@ -231,7 +232,9 @@ const EventManagement = (): JSX.Element => {
);
case 'registrants':
return (
- Event Registrants
+
+
+
);
case 'attendance':
return (
From 91059898f64b7315217c77f63891e1f425a1134f Mon Sep 17 00:00:00 2001
From: Pratap Rathi
Date: Thu, 26 Dec 2024 10:05:31 +0530
Subject: [PATCH 107/133] Refactor: Migrated
src/components/OrgAdminListCard/OrgAdminListCard.test.tsx from Jest to Vitest
(#2908)
---
...ard.test.tsx => OrgAdminListCard.spec.tsx} | 20 ++++++++++---------
1 file changed, 11 insertions(+), 9 deletions(-)
rename src/components/OrgAdminListCard/{OrgAdminListCard.test.tsx => OrgAdminListCard.spec.tsx} (82%)
diff --git a/src/components/OrgAdminListCard/OrgAdminListCard.test.tsx b/src/components/OrgAdminListCard/OrgAdminListCard.spec.tsx
similarity index 82%
rename from src/components/OrgAdminListCard/OrgAdminListCard.test.tsx
rename to src/components/OrgAdminListCard/OrgAdminListCard.spec.tsx
index 7baea946d2..a68b253c0a 100644
--- a/src/components/OrgAdminListCard/OrgAdminListCard.test.tsx
+++ b/src/components/OrgAdminListCard/OrgAdminListCard.spec.tsx
@@ -9,6 +9,7 @@ import OrgAdminListCard from './OrgAdminListCard';
import i18nForTest from 'utils/i18nForTest';
import { MemoryRouter, Route, Routes } from 'react-router-dom';
import { StaticMockLink } from 'utils/StaticMockLink';
+import { vi, beforeEach, afterEach, expect, it, describe } from 'vitest';
const MOCKS = [
{
@@ -57,27 +58,28 @@ const renderOrgAdminListCard = (props: {
,
);
};
-jest.mock('i18next-browser-languagedetector', () => ({
- init: jest.fn(),
+vi.mock('i18next-browser-languagedetector', async () => ({
+ ...(await vi.importActual('i18next-browser-languagedetector')),
+ init: vi.fn(),
type: 'languageDetector',
- detect: jest.fn(() => 'en'),
- cacheUserLanguage: jest.fn(),
+ detect: vi.fn(() => 'en'),
+ cacheUserLanguage: vi.fn(),
}));
describe('Testing Organization Admin List Card', () => {
- global.alert = jest.fn();
+ global.alert = vi.fn();
beforeEach(() => {
Object.defineProperty(window, 'location', {
writable: true,
- value: { reload: jest.fn() },
+ value: { reload: vi.fn() },
});
});
afterEach(() => {
- jest.restoreAllMocks();
+ vi.restoreAllMocks();
});
- 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 = {
toggleRemoveModal: () => true,
id: '456',
@@ -92,7 +94,7 @@ describe('Testing Organization Admin List Card', () => {
await wait(2000);
});
- test('Should not render text elements when props value is not passed', async () => {
+ it('Should not render text elements when props value is not passed', async () => {
const props = {
toggleRemoveModal: () => true,
id: undefined,
From 35cce16eae6fe6fbf55bd43be749020cb631651a Mon Sep 17 00:00:00 2001
From: Pratap Rathi
Date: Thu, 26 Dec 2024 10:51:08 +0530
Subject: [PATCH 108/133] Refactor: Migrated
src/components/ChangeLanguageDropdown/ChangeLanguageDropdown.test.tsx from
Jest to Vitest (#2909)
---
...Dropdown.test.tsx => ChangeLanguageDropdown.spec.tsx} | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
rename src/components/ChangeLanguageDropdown/{ChangeLanguageDropdown.test.tsx => ChangeLanguageDropdown.spec.tsx} (93%)
diff --git a/src/components/ChangeLanguageDropdown/ChangeLanguageDropdown.test.tsx b/src/components/ChangeLanguageDropdown/ChangeLanguageDropdown.spec.tsx
similarity index 93%
rename from src/components/ChangeLanguageDropdown/ChangeLanguageDropdown.test.tsx
rename to src/components/ChangeLanguageDropdown/ChangeLanguageDropdown.spec.tsx
index dc14f6ce17..cbaa628339 100644
--- a/src/components/ChangeLanguageDropdown/ChangeLanguageDropdown.test.tsx
+++ b/src/components/ChangeLanguageDropdown/ChangeLanguageDropdown.spec.tsx
@@ -11,6 +11,7 @@ import { MockedProvider } from '@apollo/react-testing';
import { UPDATE_USER_MUTATION } from 'GraphQl/Mutations/mutations';
import { StaticMockLink } from 'utils/StaticMockLink';
import useLocalStorage from 'utils/useLocalstorage';
+import { describe, expect, it } from 'vitest';
// import { Provider } from 'react-redux';
// import { store } from 'state/store';
const { setItem } = useLocalStorage();
@@ -52,7 +53,7 @@ const MOCKS = [
const link = new StaticMockLink(MOCKS, true);
describe('Testing Change Language Dropdown', () => {
- test('Component Should be rendered properly', async () => {
+ it('Component Should be rendered properly', async () => {
const { getByTestId } = render(
@@ -81,7 +82,7 @@ describe('Testing Change Language Dropdown', () => {
});
});
- test('Component Should accept props properly', async () => {
+ it('Component Should accept props properly', async () => {
const props = {
parentContainerStyle: 'parentContainerStyle',
btnStyle: 'btnStyle',
@@ -103,7 +104,7 @@ describe('Testing Change Language Dropdown', () => {
getByTestId('dropdown-btn-0').className.includes(props.btnTextStyle);
});
- test('Testing when language cookie is not set', async () => {
+ it('Testing when language cookie is not set', async () => {
Object.defineProperty(window.document, 'cookie', {
writable: true,
value: 'i18next=',
@@ -121,7 +122,7 @@ describe('Testing Change Language Dropdown', () => {
expect(cookies.get('i18next')).toBe('');
});
- test('Testing change language functionality', async () => {
+ it('Testing change language functionality', async () => {
Object.defineProperty(window.document, 'cookie', {
writable: true,
value: 'i18next=sp',
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 109/133] 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 110/133] 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 111/133] 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 112/133] 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 113/133] 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 114/133] 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(