@@ -319,7 +321,7 @@ function ManageTag(): JSX.Element {
minWidth: 100,
headerAlign: 'center',
sortable: false,
- headerClassName: `${styles.tableHeader}`,
+ headerClassName: `${styles.tableHeaders}`,
renderCell: (params: GridCellParams) => {
return (
@@ -452,7 +454,7 @@ function ManageTag(): JSX.Element {
>
{tag.name}
{orgUserTagAncestors.length - 1 !== index && (
- /* istanbul ignore next */
+ /* istanbul ignore next -- @preserve */
)}
@@ -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,18 +482,19 @@ 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}`}
+ getRowClassName={() => `${styles.rowBackgrounds}`}
autoHeight
rowHeight={65}
rows={userTagAssignedMembers?.map(
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/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') ? (
)}
}
+ />
+
+
+
+
+
+ ,
+ );
+
+ 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();
- });
- });
-});
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 */}
-
+
-
+
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/screens/SubTags/SubTags.test.tsx b/src/screens/SubTags/SubTags.spec.tsx
similarity index 87%
rename from src/screens/SubTags/SubTags.test.tsx
rename to src/screens/SubTags/SubTags.spec.tsx
index 145d31109d..6db92bcab6 100644
--- a/src/screens/SubTags/SubTags.test.tsx
+++ b/src/screens/SubTags/SubTags.spec.tsx
@@ -11,7 +11,6 @@ import {
waitForElementToBeRemoved,
} from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import 'jest-location-mock';
import { I18nextProvider } from 'react-i18next';
import { Provider } from 'react-redux';
import { MemoryRouter, Route, Routes } from 'react-router-dom';
@@ -22,6 +21,7 @@ import i18n from 'utils/i18nForTest';
import SubTags from './SubTags';
import { MOCKS, MOCKS_ERROR_SUB_TAGS } from './SubTagsMocks';
import { InMemoryCache, type ApolloLink } from '@apollo/client';
+import { vi, beforeEach, afterEach, expect, it } from 'vitest';
const translations = {
...JSON.parse(
@@ -44,10 +44,10 @@ async function wait(ms = 500): Promise {
});
}
-jest.mock('react-toastify', () => ({
+vi.mock('react-toastify', () => ({
toast: {
- success: jest.fn(),
- error: jest.fn(),
+ success: vi.fn(),
+ error: vi.fn(),
},
}));
@@ -107,19 +107,18 @@ const renderSubTags = (link: ApolloLink): RenderResult => {
describe('Organisation Tags Page', () => {
beforeEach(() => {
- 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')),
}));
cache.reset();
});
afterEach(() => {
- jest.clearAllMocks();
+ vi.clearAllMocks();
cleanup();
});
- test('Component loads correctly', async () => {
+ it('Component loads correctly', async () => {
const { getByText } = renderSubTags(link);
await wait();
@@ -129,7 +128,7 @@ describe('Organisation Tags Page', () => {
});
});
- test('render error component on unsuccessful subtags query', async () => {
+ it('render error component on unsuccessful subtags query', async () => {
const { queryByText } = renderSubTags(link2);
await wait();
@@ -139,7 +138,7 @@ describe('Organisation Tags Page', () => {
});
});
- test('opens and closes the create tag modal', async () => {
+ it('opens and closes the create tag modal', async () => {
renderSubTags(link);
await wait();
@@ -161,7 +160,7 @@ describe('Organisation Tags Page', () => {
);
});
- test('navigates to manage tag screen after clicking manage tag option', async () => {
+ it('navigates to manage tag screen after clicking manage tag option', async () => {
renderSubTags(link);
await wait();
@@ -176,7 +175,7 @@ describe('Organisation Tags Page', () => {
});
});
- test('navigates to sub tags screen after clicking on a tag', async () => {
+ it('navigates to sub tags screen after clicking on a tag', async () => {
renderSubTags(link);
await wait();
@@ -191,7 +190,7 @@ describe('Organisation Tags Page', () => {
});
});
- test('navigates to the different sub tag screen screen after clicking a tag in the breadcrumbs', async () => {
+ it('navigates to the different sub tag screen screen after clicking a tag in the breadcrumbs', async () => {
renderSubTags(link);
await wait();
@@ -206,7 +205,7 @@ describe('Organisation Tags Page', () => {
});
});
- test('navigates to organization tags screen screen after clicking tha all tags option in the breadcrumbs', async () => {
+ it('navigates to organization tags screen screen after clicking tha all tags option in the breadcrumbs', async () => {
renderSubTags(link);
await wait();
@@ -221,7 +220,7 @@ describe('Organisation Tags Page', () => {
});
});
- test('navigates to manage tags screen for the current tag after clicking tha manageCurrentTag button', async () => {
+ it('navigates to manage tags screen for the current tag after clicking tha manageCurrentTag button', async () => {
renderSubTags(link);
await wait();
@@ -236,7 +235,7 @@ describe('Organisation Tags Page', () => {
});
});
- test('searchs for tags where the name matches the provided search input', async () => {
+ it('searchs for tags where the name matches the provided search input', async () => {
renderSubTags(link);
await wait();
@@ -257,7 +256,7 @@ describe('Organisation Tags Page', () => {
});
});
- test('fetches the tags by the sort order, i.e. latest or oldest first', async () => {
+ it('fetches the tags by the sort order, i.e. latest or oldest first', async () => {
renderSubTags(link);
await wait();
@@ -314,7 +313,7 @@ describe('Organisation Tags Page', () => {
});
});
- test('Fetches more sub tags with infinite scroll', async () => {
+ it('Fetches more sub tags with infinite scroll', async () => {
const { getByText } = renderSubTags(link);
await wait();
@@ -343,7 +342,7 @@ describe('Organisation Tags Page', () => {
});
});
- test('adds a new sub tag to the current tag', async () => {
+ it('adds a new sub tag to the current tag', async () => {
renderSubTags(link);
await wait();
diff --git a/src/screens/SubTags/SubTags.tsx b/src/screens/SubTags/SubTags.tsx
index 930232aaca..6a20e875ec 100644
--- a/src/screens/SubTags/SubTags.tsx
+++ b/src/screens/SubTags/SubTags.tsx
@@ -93,7 +93,8 @@ function SubTags(): JSX.Element {
fetchMoreResult?: { getChildTags: InterfaceQueryUserTagChildTags };
},
) => {
- if (!fetchMoreResult) /* istanbul ignore next */ return prevResult;
+ /* istanbul ignore next -- @preserve */
+ if (!fetchMoreResult) return prevResult;
return {
getChildTags: {
@@ -126,7 +127,7 @@ function SubTags(): JSX.Element {
},
});
- /* istanbul ignore next */
+ /* istanbul ignore next -- @preserve */
if (data) {
toast.success(t('tagCreationSuccess') as string);
subTagsRefetch();
@@ -134,7 +135,7 @@ function SubTags(): JSX.Element {
setAddSubTagModalIsOpen(false);
}
} catch (error: unknown) {
- /* istanbul ignore next */
+ /* istanbul ignore next -- @preserve */
if (error instanceof Error) {
toast.error(error.message);
}
@@ -155,8 +156,8 @@ function SubTags(): JSX.Element {
}
const subTagsList =
- subTagsData?.getChildTags.childTags.edges.map((edge) => edge.node) ??
- /* istanbul ignore next */ [];
+ /* istanbul ignore next -- @preserve */
+ subTagsData?.getChildTags.childTags.edges.map((edge) => edge.node) ?? [];
const parentTagName = subTagsData?.getChildTags.name;
@@ -394,7 +395,7 @@ function SubTags(): JSX.Element {
next={loadMoreSubTags}
hasMore={
subTagsData?.getChildTags.childTags.pageInfo.hasNextPage ??
- /* istanbul ignore next */
+ /* istanbul ignore next -- @preserve */
false
}
loader={}
@@ -406,15 +407,16 @@ function SubTags(): JSX.Element {
hideFooter={true}
getRowId={(row) => row.id}
slots={{
- noRowsOverlay: /* istanbul ignore next */ () => (
-
- {t('noTagsFound')}
-
- ),
+ noRowsOverlay:
+ /* istanbul ignore next -- @preserve */ () => (
+
+ {t('noTagsFound')}
+
+ ),
}}
sx={dataGridStyle}
getRowClassName={() => `${styles.rowBackground}`}
diff --git a/src/screens/UserPortal/LeaveOrganization/LeaveOrganization.module.css b/src/screens/UserPortal/LeaveOrganization/LeaveOrganization.module.css
new file mode 100644
index 0000000000..428d41e271
--- /dev/null
+++ b/src/screens/UserPortal/LeaveOrganization/LeaveOrganization.module.css
@@ -0,0 +1,27 @@
+.modal-dialog {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ min-height: 100vh;
+ margin: 0;
+}
+
+.modal-content {
+ width: 100%;
+ max-width: 500px;
+}
+
+.modal-body {
+ text-align: center;
+}
+
+.modal-header,
+.modal-footer {
+ justify-content: center;
+ text-align: center;
+}
+
+.confirmation {
+ text-align: center;
+ margin-top: 30px;
+}
diff --git a/src/screens/UserPortal/LeaveOrganization/LeaveOrganization.test.tsx b/src/screens/UserPortal/LeaveOrganization/LeaveOrganization.test.tsx
new file mode 100644
index 0000000000..10a889f26b
--- /dev/null
+++ b/src/screens/UserPortal/LeaveOrganization/LeaveOrganization.test.tsx
@@ -0,0 +1,519 @@
+import React from 'react';
+import { render, screen, fireEvent, waitFor } from '@testing-library/react';
+import { MockedProvider } from '@apollo/react-testing';
+import {
+ BrowserRouter,
+ MemoryRouter,
+ Route,
+ Routes,
+ useNavigate,
+ useParams,
+} from 'react-router-dom';
+import LeaveOrganization from './LeaveOrganization';
+import {
+ ORGANIZATIONS_LIST,
+ USER_ORGANIZATION_CONNECTION,
+} from 'GraphQl/Queries/Queries';
+import { REMOVE_MEMBER_MUTATION } from 'GraphQl/Mutations/mutations';
+import { getItem } from 'utils/useLocalstorage';
+import { toast } from 'react-toastify';
+
+jest.mock('react-toastify', () => ({
+ toast: { success: jest.fn() }, // Mock toast function
+}));
+
+Object.defineProperty(window, 'localStorage', {
+ value: {
+ getItem: jest.fn(),
+ setItem: jest.fn(),
+ removeItem: jest.fn(),
+ clear: jest.fn(),
+ },
+ writable: true,
+});
+
+// Mock useParams to return a test organization ID
+jest.mock('react-router-dom', () => ({
+ ...jest.requireActual('react-router-dom'),
+ useParams: jest.fn(),
+ useNavigate: jest.fn(),
+}));
+
+// Mock the custom hook
+jest.mock('utils/useLocalstorage', () => {
+ return {
+ getItem: jest.fn((prefix: string, key: string) => {
+ if (prefix === 'Talawa-admin' && key === 'email')
+ return 'test@example.com';
+ if (prefix === 'Talawa-admin' && key === 'userId') return '12345';
+ if (prefix === 'Talawa-admin-error' && key === 'user-email-error')
+ throw new Error();
+ return null;
+ }),
+ };
+});
+
+// Define mock data
+const mocks = [
+ {
+ request: {
+ query: ORGANIZATIONS_LIST,
+ variables: { id: 'test-org-id' },
+ },
+ result: {
+ data: {
+ organizations: [
+ {
+ _id: 'test-org-id',
+ image: 'https://example.com/organization-image.png',
+ creator: {
+ firstName: 'John',
+ lastName: 'Doe',
+ email: 'john.doe@example.com',
+ },
+ name: 'Test Organization',
+ description: 'This is a test organization.',
+ address: {
+ city: 'New York',
+ countryCode: 'US',
+ dependentLocality: null,
+ line1: '123 Main Street',
+ line2: 'Suite 456',
+ postalCode: '10001',
+ sortingCode: null,
+ state: 'NY',
+ },
+ userRegistrationRequired: true,
+ visibleInSearch: true,
+ members: [
+ {
+ _id: 'member-001',
+ firstName: 'Alice',
+ lastName: 'Smith',
+ email: 'alice.smith@example.com',
+ },
+ {
+ _id: 'member-002',
+ firstName: 'Bob',
+ lastName: 'Johnson',
+ email: 'bob.johnson@example.com',
+ },
+ ],
+ admins: [
+ {
+ _id: 'admin-001',
+ firstName: 'Jane',
+ lastName: 'Doe',
+ email: 'jane.doe@example.com',
+ createdAt: '2023-01-15T10:00:00Z',
+ },
+ {
+ _id: 'admin-002',
+ firstName: 'Tom',
+ lastName: 'Wilson',
+ email: 'tom.wilson@example.com',
+ createdAt: '2023-02-10T12:30:00Z',
+ },
+ ],
+ membershipRequests: [
+ {
+ _id: 'req-001',
+ user: {
+ firstName: 'Emily',
+ lastName: 'Brown',
+ email: 'emily.brown@example.com',
+ },
+ },
+ ],
+ blockedUsers: [
+ {
+ _id: 'blocked-001',
+ firstName: 'Henry',
+ lastName: 'Clark',
+ email: 'henry.clark@example.com',
+ },
+ ],
+ },
+ ],
+ },
+ },
+ },
+ {
+ request: {
+ query: REMOVE_MEMBER_MUTATION,
+ variables: { orgid: 'test-org-id', userid: '12345' },
+ },
+ result: {
+ data: {
+ removeMember: {
+ _id: 'test-org-id',
+ success: true,
+ },
+ },
+ },
+ },
+ {
+ request: {
+ query: USER_ORGANIZATION_CONNECTION,
+ variables: { id: 'test-org-id' },
+ },
+ result: {
+ data: {
+ organizationsConnection: [
+ {
+ _id: 'org123',
+ name: 'Tech Enthusiasts Club',
+ image: 'https://example.com/org-logo.png',
+ description:
+ 'A community of tech lovers who meet to share ideas and projects.',
+ userRegistrationRequired: true,
+ creator: {
+ firstName: 'Alice',
+ lastName: 'Johnson',
+ },
+ members: [
+ { _id: 'user001' },
+ { _id: 'user002' },
+ { _id: 'user003' },
+ ],
+ admins: [{ _id: 'admin001' }, { _id: 'admin002' }],
+ createdAt: '2024-01-15T12:34:56.789Z',
+ address: {
+ city: 'San Francisco',
+ countryCode: 'US',
+ dependentLocality: null,
+ line1: '123 Tech Ave',
+ line2: 'Suite 100',
+ postalCode: '94105',
+ sortingCode: null,
+ state: 'California',
+ },
+ membershipRequests: [
+ {
+ _id: 'req001',
+ user: {
+ _id: 'user004',
+ },
+ },
+ {
+ _id: 'req002',
+ user: {
+ _id: 'user005',
+ },
+ },
+ ],
+ },
+ ],
+ },
+ },
+ },
+];
+
+const errorMocks = [
+ {
+ request: {
+ query: ORGANIZATIONS_LIST,
+ variables: { id: 'test-org-id' },
+ },
+ error: new Error('Failed to load organization details'),
+ },
+ {
+ request: {
+ query: REMOVE_MEMBER_MUTATION,
+ variables: { orgid: 'test-org-id', userid: '12345' },
+ },
+ error: new Error('Failed to leave organization'),
+ },
+ {
+ request: {
+ query: USER_ORGANIZATION_CONNECTION,
+ variables: { id: 'test-org-id' },
+ },
+ error: new Error('Operation Failed'),
+ },
+];
+
+beforeEach(() => {
+ localStorage.clear();
+ jest.clearAllMocks(); // Clear mocks before each test
+ (useParams as jest.Mock).mockReturnValue({ orgId: 'test-org-id' });
+});
+
+describe('LeaveOrganization Component', () => {
+ test('renders organization details and shows loading spinner', async () => {
+ render(
+
+
+
+
+ ,
+ );
+ const spinner = await screen.findByRole('status');
+ expect(spinner).toBeInTheDocument();
+ await waitFor(() => {
+ expect(screen.getByText('Test Organization')).toBeInTheDocument();
+ expect(
+ screen.getByText('This is a test organization.'),
+ ).toBeInTheDocument();
+ });
+ });
+
+ test('renders organization details and displays content correctly', async () => {
+ render(
+
+
+
+ }
+ />
+
+
+ ,
+ );
+ await waitFor(() => {
+ expect(screen.getByText('Test Organization')).toBeInTheDocument();
+ expect(
+ screen.getByText('This is a test organization.'),
+ ).toBeInTheDocument();
+ });
+ });
+
+ test('shows error message when mutation fails', async () => {
+ render(
+
+
+
+ }
+ />
+
+
+ ,
+ );
+ await waitFor(() => {
+ expect(
+ screen.queryByText('Loading organization details...'),
+ ).not.toBeInTheDocument();
+ });
+ expect(await screen.findByText('Test Organization')).toBeInTheDocument();
+ expect(
+ screen.getByText('This is a test organization.'),
+ ).toBeInTheDocument();
+ const leaveButton = await screen.findByRole('button', {
+ name: 'Leave Organization',
+ });
+ fireEvent.click(leaveButton);
+ expect(screen.queryByText(/An error occurred!/i)).not.toBeInTheDocument();
+ });
+
+ test('logs an error when unable to access localStorage', () => {
+ const consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation();
+ const userEmail = (() => {
+ try {
+ return getItem('Talawa-admin-error', 'user-email-error') ?? '';
+ } catch (e) {
+ console.error('Failed to access localStorage:', e);
+ return '';
+ }
+ })();
+ const userId = (() => {
+ try {
+ return getItem('Talawa-admin-error', 'user-email-error') ?? '';
+ } catch (e) {
+ console.error('Failed to access localStorage:', e);
+ return '';
+ }
+ })();
+ expect(userEmail).toBe('');
+ expect(userId).toBe('');
+ expect(consoleErrorSpy).toHaveBeenCalledWith(
+ 'Failed to access localStorage:',
+ expect.any(Error),
+ );
+ consoleErrorSpy.mockRestore();
+ });
+
+ test('navigates and shows toast when email matches', async () => {
+ const mockNavigate = jest.fn();
+ (useNavigate as jest.Mock).mockReturnValue(mockNavigate);
+ const toastSuccessMock = jest.fn();
+ toast.success = toastSuccessMock;
+ render(
+
+
+
+
+ ,
+ );
+ const leaveButton = await screen.findByRole('button', {
+ name: /Leave Organization/i,
+ });
+ fireEvent.click(leaveButton);
+ await waitFor(() =>
+ expect(
+ screen.getByText(/Are you sure you want to leave this organization?/i),
+ ).toBeInTheDocument(),
+ );
+ const modal = await screen.findByRole('dialog');
+ expect(modal).toBeInTheDocument();
+ await screen.findByText('Continue');
+ fireEvent.click(screen.getByText('Continue'));
+ const emailInput = screen.getByPlaceholderText(/Enter your email/i);
+ fireEvent.change(emailInput, {
+ target: { value: 'test@example.com' },
+ });
+ fireEvent.keyDown(emailInput, { key: 'Enter', code: 'Enter' });
+ await waitFor(() => {
+ expect(mockNavigate).toHaveBeenCalledWith(`/user/organizations`);
+ });
+ await waitFor(() => {
+ expect(toastSuccessMock).toHaveBeenCalledWith(
+ 'You have successfully left the organization!',
+ );
+ });
+ });
+
+ test('shows error when email is missing', async () => {
+ render(
+
+
+
+
+ ,
+ );
+ const leaveButton = await screen.findByRole('button', {
+ name: /Leave Organization/i,
+ });
+ fireEvent.click(leaveButton);
+ await waitFor(() =>
+ expect(
+ screen.getByText(/Are you sure you want to leave this organization?/i),
+ ).toBeInTheDocument(),
+ );
+ const modal = await screen.findByRole('dialog');
+ expect(modal).toBeInTheDocument();
+ await screen.findByText('Continue');
+ fireEvent.click(screen.getByText('Continue'));
+ fireEvent.change(screen.getByPlaceholderText(/Enter your email/i), {
+ target: { value: '' },
+ });
+ fireEvent.click(screen.getByText('Confirm'));
+ await waitFor(() => {
+ expect(
+ screen.getByText('Verification failed: Email does not match.'),
+ ).toBeInTheDocument();
+ });
+ });
+
+ test('shows error when email does not match', async () => {
+ render(
+
+
+
+
+ ,
+ );
+ const leaveButton = await screen.findByRole('button', {
+ name: /Leave Organization/i,
+ });
+ fireEvent.click(leaveButton);
+ await waitFor(() =>
+ expect(
+ screen.getByText(/Are you sure you want to leave this organization?/i),
+ ).toBeInTheDocument(),
+ );
+ const modal = await screen.findByRole('dialog');
+ expect(modal).toBeInTheDocument();
+ await screen.findByText('Continue');
+ fireEvent.click(screen.getByText('Continue'));
+ fireEvent.change(screen.getByPlaceholderText(/Enter your email/i), {
+ target: { value: 'different@example.com' },
+ });
+ fireEvent.click(screen.getByText('Confirm'));
+ await waitFor(() => {
+ expect(
+ screen.getByText('Verification failed: Email does not match.'),
+ ).toBeInTheDocument();
+ });
+ });
+
+ test('resets state when back button pressed', async () => {
+ render(
+
+
+
+
+ ,
+ );
+ const leaveButton = await screen.findByRole('button', {
+ name: /Leave Organization/i,
+ });
+ fireEvent.click(leaveButton);
+ await waitFor(() =>
+ expect(
+ screen.getByText(/Are you sure you want to leave this organization?/i),
+ ).toBeInTheDocument(),
+ );
+ const modal = await screen.findByRole('dialog');
+ expect(modal).toBeInTheDocument();
+ await screen.findByText('Continue');
+ fireEvent.click(screen.getByText('Continue'));
+ const closeButton = screen.getByRole('button', { name: /Back/i });
+ fireEvent.click(closeButton);
+ expect(
+ screen.queryByText(/Are you sure you want to leave this organization?/i),
+ ).toBeInTheDocument();
+ });
+
+ test('resets state when modal is closed', async () => {
+ render(
+
+
+
+
+ ,
+ );
+ const leaveButton = await screen.findByRole('button', {
+ name: /Leave Organization/i,
+ });
+ fireEvent.click(leaveButton);
+ const closeButton = screen.getByRole('button', { name: /Cancel/i });
+ fireEvent.click(closeButton);
+ expect(screen.queryByText(/Leave Organization/i)).toBeInTheDocument();
+ });
+
+ test('closes modal and resets state when Esc key is pressed', async () => {
+ const mockNavigate = jest.fn();
+ (useNavigate as jest.Mock).mockReturnValue(mockNavigate);
+ render(
+
+
+
+
+ ,
+ );
+ const leaveButton = await screen.findByRole('button', {
+ name: /Leave Organization/i,
+ });
+ fireEvent.click(leaveButton);
+ const modal = await screen.findByTestId('leave-organization-modal');
+ expect(modal).toBeInTheDocument();
+ fireEvent.keyDown(modal, { key: 'Escape', code: 'Escape' });
+ await waitFor(() => {
+ expect(screen.queryByTestId('leave-organization-modal')).toBeNull(); // Modal should no longer be present
+ });
+ expect(modal).not.toBeInTheDocument();
+ });
+
+ test('displays an error alert when query fails', async () => {
+ render(
+
+
+ ,
+ );
+ const errorAlert = await screen.findByRole('alert');
+ expect(errorAlert).toHaveTextContent(/Error:/i);
+ });
+});
diff --git a/src/screens/UserPortal/LeaveOrganization/LeaveOrganization.tsx b/src/screens/UserPortal/LeaveOrganization/LeaveOrganization.tsx
new file mode 100644
index 0000000000..91dc3a54bf
--- /dev/null
+++ b/src/screens/UserPortal/LeaveOrganization/LeaveOrganization.tsx
@@ -0,0 +1,248 @@
+import React, { useState } from 'react';
+import { useQuery, useMutation } from '@apollo/client';
+import {
+ ORGANIZATIONS_LIST,
+ USER_ORGANIZATION_CONNECTION,
+} from 'GraphQl/Queries/Queries';
+import { REMOVE_MEMBER_MUTATION } from 'GraphQl/Mutations/mutations';
+import { Button, Modal, Form, Spinner, Alert } from 'react-bootstrap';
+import { useParams, useNavigate } from 'react-router-dom';
+import { getItem } from 'utils/useLocalstorage';
+import { toast } from 'react-toastify';
+
+const userEmail = (() => {
+ try {
+ return getItem('Talawa-admin', 'email') ?? '';
+ } catch (e) {
+ console.error('Failed to access localStorage:', e);
+ return '';
+ }
+})();
+const userId = (() => {
+ try {
+ return getItem('Talawa-admin', 'userId') ?? '';
+ } catch (e) {
+ console.error('Failed to access localStorage:', e);
+ return '';
+ }
+})();
+
+export { userEmail, userId };
+
+const LeaveOrganization = (): JSX.Element => {
+ const navigate = useNavigate();
+ const { orgId: organizationId } = useParams();
+ const [email, setEmail] = useState('');
+ const [error, setError] = useState('');
+ const [loading, setLoading] = useState(false);
+ const [showModal, setShowModal] = useState(false);
+ const [verificationStep, setVerificationStep] = useState(false);
+
+ /**
+ * Query to fetch the organization data.
+ */
+ const {
+ data: orgData,
+ loading: orgLoading,
+ error: orgError,
+ } = useQuery(ORGANIZATIONS_LIST, {
+ variables: { id: organizationId },
+ });
+
+ /**
+ * Mutation to remove the member from the organization.
+ */
+ const [removeMember] = useMutation(REMOVE_MEMBER_MUTATION, {
+ refetchQueries: [
+ {
+ query: USER_ORGANIZATION_CONNECTION,
+ variables: { id: organizationId },
+ },
+ ],
+ onCompleted: () => {
+ // Use a toast notification or in-app message
+ setShowModal(false);
+ toast.success('You have successfully left the organization!');
+ navigate(`/user/organizations`);
+ },
+ onError: (err) => {
+ const isNetworkError = err.networkError !== null;
+ setError(
+ isNetworkError
+ ? 'Unable to process your request. Please check your connection.'
+ : 'Failed to leave organization. Please try again.',
+ );
+ setLoading(false);
+ },
+ });
+
+ /**
+ * Handles the process of leaving the organization.
+ */
+ const handleLeaveOrganization = (): void => {
+ if (!organizationId || !userId) {
+ setError('Unable to process request: Missing required information.');
+ setLoading(false);
+ return;
+ }
+ setError('');
+ setLoading(true);
+ removeMember({
+ variables: { orgid: organizationId, userid: userId },
+ });
+ };
+
+ /**
+ * Verifies the user's email before proceeding.
+ */
+ const handleVerifyAndLeave = (): void => {
+ if (email.trim().toLowerCase() === userEmail.toLowerCase()) {
+ handleLeaveOrganization();
+ } else {
+ setError('Verification failed: Email does not match.');
+ }
+ };
+
+ /**
+ * Handles the 'Enter' key press.
+ */
+ const handleKeyPress = (
+ event: React.KeyboardEvent,
+ ): void => {
+ if (event.key === 'Enter') {
+ event.preventDefault();
+ if (verificationStep) {
+ handleVerifyAndLeave();
+ } else {
+ setVerificationStep(true);
+ }
+ }
+ };
+
+ if (orgLoading) {
+ return (
+
+
+
Loading organization details...
+
+ );
+ }
+ if (orgError)
+ return Error: {orgError.message};
+
+ if (!orgData?.organizations?.length) {
+ return Organization not found
;
+ }
+
+ const organization = orgData?.organizations[0];
+
+ return (
+
+
+
{organization?.name}
+
{organization?.description}
+
+
setShowModal(true)}>
+ Leave Organization
+
+
+
{
+ setShowModal(false);
+ setVerificationStep(false);
+ setEmail('');
+ setError('');
+ }}
+ >
+
+
+ Leave Joined Organization
+
+
+
+ {!verificationStep ? (
+ <>
+ Are you sure you want to leave this organization?
+
+ This action cannot be undone, and you may need to request access
+ again if you reconsider.
+
+ >
+ ) : (
+
+
+ Enter your email to confirm:
+
+ setEmail(e.target.value)}
+ onKeyDown={handleKeyPress}
+ aria-label="confirm-email-input"
+ />
+
+ {error && (
+
+ {error}
+
+ )}
+
+ )}
+
+
+ {!verificationStep ? (
+ <>
+ setShowModal(false)}>
+ Cancel
+
+ setVerificationStep(true)}
+ >
+ Continue
+
+ >
+ ) : (
+ <>
+ {
+ setVerificationStep(false);
+ setEmail('');
+ setError('');
+ }}
+ >
+ Back
+
+
+ {loading ? (
+ <>
+
+ {' Loading...'}
+ >
+ ) : (
+ 'Confirm'
+ )}
+
+ >
+ )}
+
+
+
+ );
+};
+
+export default LeaveOrganization;
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(
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(
diff --git a/src/screens/UserPortal/UserScreen/UserScreen.tsx b/src/screens/UserPortal/UserScreen/UserScreen.tsx
index bcb1d867f3..39b422858f 100644
--- a/src/screens/UserPortal/UserScreen/UserScreen.tsx
+++ b/src/screens/UserPortal/UserScreen/UserScreen.tsx
@@ -20,6 +20,7 @@ const map: InterfaceMapType = {
campaigns: 'userCampaigns',
pledges: 'userPledges',
volunteer: 'userVolunteer',
+ leaveorg: 'leaveOrganization',
};
/**
diff --git a/src/screens/UserPortal/Volunteer/Actions/Actions.tsx b/src/screens/UserPortal/Volunteer/Actions/Actions.tsx
index 36b1f29b83..9bc23969c2 100644
--- a/src/screens/UserPortal/Volunteer/Actions/Actions.tsx
+++ b/src/screens/UserPortal/Volunteer/Actions/Actions.tsx
@@ -9,7 +9,7 @@ import dayjs from 'dayjs';
import { useQuery } from '@apollo/client';
import type { InterfaceActionItemInfo } from 'utils/interfaces';
-import styles from 'screens/OrganizationActionItems/OrganizationActionItems.module.css';
+import styles from '../../../../style/app.module.css';
import Loader from 'components/Loader/Loader';
import {
DataGrid,
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);
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={
({
- 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();
});
});
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/',
);
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();
diff --git a/src/state/reducers/userRoutersReducer.test.ts b/src/state/reducers/userRoutersReducer.test.ts
index e2987dcd38..67f075fd44 100644
--- a/src/state/reducers/userRoutersReducer.test.ts
+++ b/src/state/reducers/userRoutersReducer.test.ts
@@ -18,6 +18,7 @@ describe('Testing Routes reducer', () => {
{ name: 'Donate', url: 'user/donate/undefined' },
{ name: 'Campaigns', url: 'user/campaigns/undefined' },
{ name: 'My Pledges', url: 'user/pledges/undefined' },
+ { name: 'Leave Organization', url: 'user/leaveorg/undefined' },
],
components: [
{
@@ -44,6 +45,11 @@ describe('Testing Routes reducer', () => {
component: 'Campaigns',
},
{ name: 'My Pledges', comp_id: 'pledges', component: 'Pledges' },
+ {
+ name: 'Leave Organization',
+ comp_id: 'leaveorg',
+ component: 'LeaveOrganization',
+ },
],
});
});
@@ -64,6 +70,7 @@ describe('Testing Routes reducer', () => {
{ name: 'Donate', url: 'user/donate/orgId' },
{ name: 'Campaigns', url: 'user/campaigns/orgId' },
{ name: 'My Pledges', url: 'user/pledges/orgId' },
+ { name: 'Leave Organization', url: 'user/leaveorg/orgId' },
],
components: [
{
@@ -90,6 +97,11 @@ describe('Testing Routes reducer', () => {
component: 'Campaigns',
},
{ name: 'My Pledges', comp_id: 'pledges', component: 'Pledges' },
+ {
+ name: 'Leave Organization',
+ comp_id: 'leaveorg',
+ component: 'LeaveOrganization',
+ },
],
});
});
diff --git a/src/state/reducers/userRoutesReducer.ts b/src/state/reducers/userRoutesReducer.ts
index e1bf5de0dc..3e99c51b3f 100644
--- a/src/state/reducers/userRoutesReducer.ts
+++ b/src/state/reducers/userRoutesReducer.ts
@@ -63,6 +63,11 @@ const components: ComponentType[] = [
component: 'Campaigns',
},
{ name: 'My Pledges', comp_id: 'pledges', component: 'Pledges' },
+ {
+ name: 'Leave Organization',
+ comp_id: 'leaveorg',
+ component: 'LeaveOrganization',
+ },
];
const generateRoutes = (
diff --git a/src/style/app.module.css b/src/style/app.module.css
index 6d6413aa86..5bfdef1e66 100644
--- a/src/style/app.module.css
+++ b/src/style/app.module.css
@@ -12,10 +12,16 @@
--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);
--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;
--table-header-color: var(--bs-greyish-black, black);
--table-head-radius: 20px;
@@ -87,6 +93,7 @@
border-bottom: 3px solid #31bb6b;
width: 15%;
}
+
.searchtitle {
color: #707070;
font-weight: 600;
@@ -101,6 +108,7 @@
display: flex;
justify-content: space-between;
}
+
.admindetails > p {
margin-top: -12px;
margin-right: 30px;
@@ -113,10 +121,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;
@@ -144,6 +154,7 @@
}
.closeButton {
+ margin-bottom: 10px;
color: var(--delete-button-color);
margin-right: 5px;
background-color: var(--delete-button-bg);
@@ -204,13 +215,11 @@
.input {
flex: 1;
-
position: relative;
}
.btnsContainer {
display: flex;
- /* Adjust spacing between items */
margin: 2.5rem 0;
align-items: center;
gap: 10px;
@@ -221,21 +230,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 +401,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 +416,6 @@
}
}
-.subTagsLink {
- color: var(--subtle-blue-grey);
- font-weight: 500;
- cursor: pointer;
-}
-
.subTagsLink i {
visibility: hidden;
}
@@ -434,15 +432,9 @@
visibility: visible;
}
-.tagsBreadCrumbs {
- color: var(--bs-gray);
- cursor: pointer;
-}
-
.manageTagScrollableDiv {
scrollbar-width: thin;
scrollbar-color: var(--bs-gray-400) var(--bs-white);
-
max-height: calc(100vh - 18rem);
overflow: auto;
}
@@ -462,15 +454,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;
}
@@ -518,6 +501,7 @@ hr {
display: flex;
justify-content: flex-end;
}
+
.icon {
margin: 1px;
}
@@ -558,10 +542,6 @@ hr {
align-items: center;
}
-.toggleBtn:hover {
- color: var(--bs-primary) !important;
-}
-
.pageNotFound {
position: relative;
bottom: 20px;
@@ -577,10 +557,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;
@@ -588,6 +570,7 @@ hr {
letter-spacing: 25px;
margin: 10px 0 0 0;
}
+
.pageNotFound h1.head span {
position: relative;
display: inline-block;
@@ -604,6 +587,7 @@ hr {
.pageNotFound h1.head span:before {
left: -55%;
}
+
.pageNotFound h1.head span:after {
right: -55%;
}
@@ -831,6 +815,183 @@ 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;
+}
+
+.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;
+}
+
+.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;
+}
+
+.eventAgendaItemContainer h2 {
+ margin: 0.6rem 0;
+}
+
+@media (max-width: 768px) {
+ .btnsContainer {
+ margin-bottom: 0;
+ display: flex;
+ flex-direction: column;
+ }
+
+ .createAgendaItemButton {
+ position: absolute;
+ top: 1rem;
+ right: 2rem;
+ }
+}
+
+.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 {
+ 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;
+}
+
@media (max-width: 1024px) {
.pageNotFound h1.head {
font-size: 200px;
@@ -894,12 +1055,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;
@@ -972,68 +1136,48 @@ hr {
transform: rotate(360deg);
}
}
-
-.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;
+.list_box {
+ height: auto;
+ overflow-y: auto;
+ 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;
- }
+.fundName {
+ font-weight: 600;
+ cursor: pointer;
}
-/* For mobile devices */
-
-@media (max-width: 520px) {
- .btnsContainer {
- margin-bottom: 0;
- }
-
- .btnsContainer .btnsBlock {
- display: block;
- margin-top: 1rem;
- margin-right: 0;
- }
+.modalHeader {
+ border: none;
+ padding-bottom: 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 {
@@ -1044,12 +1188,18 @@ hr {
flex-direction: column;
}
-.tableHeader {
+.tableHeaders {
background-color: var(--bs-primary-text-emphasis);
color: var(--bs-white);
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;
@@ -1065,10 +1215,6 @@ hr {
}
}
-.subTagsLink i {
- visibility: hidden;
-}
-
.tagsBreadCrumbs {
color: var(--bs-gray);
cursor: pointer;
@@ -1093,7 +1239,6 @@ hr {
.subTagsScrollableDiv {
scrollbar-width: auto;
scrollbar-color: var(--bs-gray-400) var(--bs-white);
-
max-height: calc(100vh - 18rem);
overflow: auto;
}
@@ -1105,10 +1250,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;
@@ -1134,13 +1287,32 @@ input[type='radio']:checked + label {
transition:
transform 0.2s,
box-shadow 0.2s;
+ width: 100%;
}
-.removeFilterIcon {
+.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;
-}
-
-.searchForm {
+ width: 45%;
+ transition:
+ transform 0.2s,
+ box-shadow 0.2s;
+}
+
+.removeFilterIcon {
+ cursor: pointer;
+}
+
+.searchForm {
display: inline;
}
@@ -1171,6 +1343,10 @@ input[type='radio']:checked + label {
width: 52px;
}
+.noOutline input {
+ outline: none;
+}
+
.noOutline input:disabled {
-webkit-text-fill-color: black !important;
}
@@ -1180,18 +1356,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;
@@ -1200,18 +1368,6 @@ input[type='radio']:checked + label {
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;
}
@@ -1279,3 +1435,520 @@ 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;
+ }
+}
+
+/* * 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 {
+ 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%;
+ }
+}
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();
});
});
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);