From 8719d53b7dfa5c35b6520bcbe857015a5e5faee7 Mon Sep 17 00:00:00 2001 From: Antriksh Dangi <132576984+antriksh-9@users.noreply.github.com> Date: Sat, 28 Dec 2024 01:09:58 +0530 Subject: [PATCH 01/11] refactored CSS files in src/screens/OrganizationVenues (#2879) * refactored: OrganizationVenues css * resolved issues * fixed issues * issue fixed * changes applied --- src/components/Venues/VenueCard.tsx | 2 +- .../OrganizationVenues.module.css | 879 ------------------ src/style/app.module.css | 71 +- 3 files changed, 58 insertions(+), 894 deletions(-) delete mode 100644 src/screens/OrganizationVenues/OrganizationVenues.module.css diff --git a/src/components/Venues/VenueCard.tsx b/src/components/Venues/VenueCard.tsx index 752ac95139..43da734bd6 100644 --- a/src/components/Venues/VenueCard.tsx +++ b/src/components/Venues/VenueCard.tsx @@ -2,7 +2,7 @@ import React from 'react'; import { Card, Button } from 'react-bootstrap'; import defaultImg from 'assets/images/defaultImg.png'; import PeopleIcon from 'assets/svgs/people.svg?react'; -import styles from 'screens/OrganizationVenues/OrganizationVenues.module.css'; +import styles from '../../style/app.module.css'; import { useTranslation } from 'react-i18next'; import type { InterfaceQueryVenueListItem } from 'utils/interfaces'; diff --git a/src/screens/OrganizationVenues/OrganizationVenues.module.css b/src/screens/OrganizationVenues/OrganizationVenues.module.css deleted file mode 100644 index e4ac9d7575..0000000000 --- a/src/screens/OrganizationVenues/OrganizationVenues.module.css +++ /dev/null @@ -1,879 +0,0 @@ -.navbarbg { - height: 60px; - background-color: white; - display: flex; - margin-bottom: 30px; - z-index: 1; - position: relative; - flex-direction: row; - justify-content: space-between; - box-shadow: 0px 0px 8px 2px #c8c8c8; -} - -.logo { - color: #707070; - margin-left: 0; - display: flex; - align-items: center; - text-decoration: none; -} - -.logo img { - margin-top: 0px; - margin-left: 10px; - height: 64px; - width: 70px; -} - -.logo > strong { - line-height: 1.5rem; - margin-left: -5px; - font-family: sans-serif; - font-size: 19px; - color: #707070; -} -.mainpage { - display: flex; - flex-direction: row; -} - -.sidebar:after { - background-color: #f7f7f7; - position: absolute; - width: 2px; - height: 600px; - top: 10px; - left: 94%; - display: block; -} - -.navitem { - padding-left: 27%; - padding-top: 12px; - padding-bottom: 12px; - cursor: pointer; -} - -.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; - margin-top: 20px; -} - -.addbtn { - border: 1px solid #e8e5e5; - box-shadow: 0 2px 2px #e8e5e5; - border-radius: 5px; - font-size: 16px; - height: 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: 40px 30px; - background: #ffffff; - border-color: #e8e5e5; - border-width: 5px; - border-radius: 10px; - max-height: 86vh; - overflow: auto; -} - -.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%; -} -.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; -} -.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%; -} - -.datediv { - display: flex; - flex-direction: row; - margin-bottom: 15px; -} -.datebox { - width: 90%; - border-radius: 7px; - border-color: #e8e5e5; - outline: none; - box-shadow: none; - padding-top: 2px; - padding-bottom: 2px; - padding-right: 5px; - padding-left: 5px; - margin-right: 5px; - margin-left: 5px; -} -.checkboxdiv > label { - margin-right: 50px; -} -.checkboxdiv > label > input { - margin-left: 10px; -} -.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); - } -} -.dispflex { - display: flex; - align-items: center; -} -.dispflex > input { - border: none; - box-shadow: none; - margin-top: 5px; -} -.checkboxdiv { - display: flex; -} -.checkboxdiv > div { - width: 50%; -} - -@media only screen and (max-width: 600px) { - .form_wrapper { - width: 90%; - top: 45%; - } -} - -.navbarbg { - height: 60px; - background-color: white; - display: flex; - margin-bottom: 30px; - z-index: 1; - position: relative; - flex-direction: row; - justify-content: space-between; - box-shadow: 0px 0px 8px 2px #c8c8c8; -} - -.logo { - color: #707070; - margin-left: 0; - display: flex; - align-items: center; - text-decoration: none; -} - -.logo img { - margin-top: 0px; - margin-left: 10px; - height: 64px; - width: 70px; -} - -.logo > strong { - line-height: 1.5rem; - margin-left: -5px; - font-family: sans-serif; - font-size: 19px; - color: #707070; -} -.mainpage { - display: flex; - flex-direction: row; -} -.sidebar { - display: flex; - width: 100%; - justify-content: space-between; - z-index: 0; - padding-top: 10px; - margin: 0; - height: 100%; -} - -.navitem { - padding-left: 27%; - padding-top: 12px; - padding-bottom: 12px; - cursor: pointer; -} - -.logintitle { - color: #707070; - font-weight: 600; - font-size: 20px; - margin-bottom: 30px; - padding-bottom: 5px; - border-bottom: 3px solid #31bb6b; - width: 15%; -} -.searchtitle { - color: #707070; - font-weight: 600; - font-size: 20px; - margin-bottom: 20px; - padding-bottom: 5px; - border-bottom: 3px solid #31bb6b; - width: 60%; -} -.justifysp { - display: flex; - justify-content: space-between; -} -@media screen and (max-width: 575.5px) { - .justifysp { - padding-left: 55px; - display: flex; - justify-content: space-between; - width: 100%; - } - .mainpageright { - width: 98%; - } -} - -.logintitleadmin { - color: #707070; - font-weight: 600; - font-size: 18px; - margin-top: 50px; - margin-bottom: 40px; - padding-bottom: 5px; - border-bottom: 3px solid #31bb6b; - width: 40%; -} -.admindetails { - display: flex; - justify-content: space-between; -} -.admindetails > p { - margin-top: -12px; - margin-right: 30px; -} -.mainpageright > hr { - margin-top: 10px; - width: 97%; - margin-left: -15px; - margin-right: -15px; - margin-bottom: 20px; -} -.addbtnmain { - width: 60%; - margin-right: 50px; -} -.addbtn { - float: right; - width: 23%; - border: 1px solid #e8e5e5; - box-shadow: 0 2px 2px #e8e5e5; - border-radius: 5px; - background-color: #31bb6b; - height: 40px; - font-size: 16px; - color: white; - outline: none; - font-weight: 600; - cursor: pointer; - margin-left: 30px; - 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: 40px 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%; -} -.cancel > i { - margin-top: 5px; - transform: scale(1.2); - cursor: pointer; - color: #707070; -} -.modalbody { - width: 50px; -} -.greenregbtn { - margin: 1rem 0 0; - margin-top: 10px; - 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%; -} -.dropdown { - background-color: white; - border: 1px solid #31bb6b; - position: relative; - display: inline-block; - margin-top: 10px; - margin-bottom: 10px; - color: #31bb6b; -} -.input { - flex: 1; - position: relative; -} -/* .btnsContainer { - display: flex; - margin: 2.5rem 0 2.5rem 0; - width: 100%; - flex-direction: row; - justify-content: space-between; - } */ - -.btnsContainer { - display: flex; - margin: 2.5rem 0 2.5rem 0; -} - -.btnsContainer .input { - flex: 1; - position: relative; - min-width: 18rem; - width: 25rem; -} - -.btnsContainer .input button { - width: 52px; -} -.searchBtn { - margin-bottom: 10px; -} - -.inputField { - margin-top: 10px; - margin-bottom: 10px; - background-color: white; - box-shadow: 0 1px 1px #31bb6b; -} -.inputField > button { - padding-top: 10px; - padding-bottom: 10px; -} -.TableImage { - background-color: #31bb6b !important; - width: 50px !important; - height: 50px !important; - border-radius: 100% !important; - margin-right: 10px !important; -} -.tableHead { - background-color: #31bb6b !important; - color: white; - border-radius: 20px !important; - padding: 20px; - margin-top: 20px; -} - -.tableHead :nth-first-child() { - border-top-left-radius: 20px; -} - -.mainpageright > hr { - margin-top: 10px; - width: 100%; - margin-left: -15px; - margin-right: -15px; - margin-bottom: 20px; -} - -.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; -} -.radio_buttons { - display: flex; - flex-direction: column; - gap: 0.5rem; - color: #707070; - font-weight: 600; - font-size: 14px; -} -.radio_buttons > input { - transform: scale(1.2); -} -.radio_buttons > label { - margin-top: -4px; - margin-left: 5px; - margin-right: 15px; -} -.preview { - display: flex; - position: relative; - width: 100%; - margin-top: 10px; - justify-content: center; -} -.preview img { - width: 400px; - height: auto; -} -.postimage { - border-radius: 0px; - width: 100%; - height: 12rem; - max-width: 100%; - max-height: 12rem; - object-fit: cover; - position: relative; - color: black; -} -.closeButtonP { - 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; -} -.addbtn { - border: 1px solid #e8e5e5; - box-shadow: 0 2px 2px #e8e5e5; - border-radius: 5px; - font-size: 16px; - height: 60%; - color: white; - outline: none; - font-weight: 600; - cursor: pointer; - transition: - transform 0.2s, - box-shadow 0.2s; -} -@-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: 65vh; - overflow-y: auto; - width: auto; -} - -.cards h2 { - font-size: 20px; -} -.cards > h3 { - font-size: 17px; -} -.card { - width: 100%; - height: 20rem; - margin-bottom: 2rem; -} -.postimage { - border-radius: 0px; - width: 100%; - height: 12rem; - max-width: 100%; - max-height: 12rem; - object-fit: cover; - position: relative; - color: black; -} -.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; -} -.novenueimage { - border-radius: 0px; - width: 100%; - height: 12rem; - max-height: 12rem; - object-fit: cover; - position: relative; -} -.cards:hover { - filter: brightness(0.8); -} -.cards:hover::before { - opacity: 0.5; -} -.knowMoreText { - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - opacity: 0; - color: white; - padding: 10px; - font-weight: bold; - font-size: 1.5rem; - transition: opacity 0.3s ease-in-out; -} - -.cards:hover .knowMoreText { - opacity: 1; -} -.modal { - position: fixed; - top: 0; - left: 0; - width: 100%; - height: 100%; - display: flex; - align-items: center; - justify-content: center; - background-color: rgba( - 0, - 0, - 0, - 0.9 - ); /* Dark grey modal background with transparency */ - z-index: 9999; -} - -.modalContent { - display: flex; - align-items: center; - justify-content: center; - background-color: #fff; - padding: 20px; - max-width: 800px; - max-height: 600px; - overflow: auto; -} - -.modalImage { - flex: 1; - margin-right: 20px; - width: 25rem; - height: 15rem; -} -.nomodalImage { - flex: 1; - margin-right: 20px; - width: 100%; - height: 15rem; -} - -.modalImage img, -.modalImage video { - border-radius: 0px; - width: 100%; - height: 25rem; - max-width: 25rem; - max-height: 15rem; - object-fit: cover; - position: relative; -} -.modalInfo { - flex: 1; -} -.title { - font-size: 16px; - color: #000; - font-weight: 600; -} -.text { - font-size: 13px; - color: #000; - font-weight: 300; -} -.closeButton { - position: relative; - bottom: 5rem; - right: 10px; - padding: 4px; - background-color: red; /* Red close button color */ - color: #fff; - border: none; - cursor: pointer; -} -.closeButtonP { - 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; -} -.cards:hover::after { - opacity: 1; - mix-blend-mode: normal; -} -.cards > p { - font-size: 14px; - margin-top: 0px; - margin-bottom: 7px; -} - -.cards:last-child:nth-last-child(odd) { - grid-column: auto / span 2; -} -.cards:first-child:nth-last-child(even), -.cards:first-child:nth-last-child(even) ~ .box { - grid-column: auto / span 1; -} - -.capacityLabel { - background-color: #31bb6b !important; - color: white; - height: 22.19px; - font-size: 12px; - font-weight: bolder; - padding: 0.1rem 0.3rem; - border-radius: 0.5rem; - position: relative; - overflow: hidden; -} - -.capacityLabel svg { - margin-bottom: 3px; -} - -::-webkit-scrollbar { - width: 20px; -} - -::-webkit-scrollbar-track { - background-color: transparent; -} - -::-webkit-scrollbar-thumb { - background-color: #d6dee1; -} - -::-webkit-scrollbar-thumb { - background-color: #d6dee1; - border-radius: 20px; -} - -::-webkit-scrollbar-thumb { - background-color: #d6dee1; - border-radius: 20px; - border: 6px solid transparent; - background-clip: content-box; -} diff --git a/src/style/app.module.css b/src/style/app.module.css index 448b80bd88..cd55f8c1c0 100644 --- a/src/style/app.module.css +++ b/src/style/app.module.css @@ -38,17 +38,6 @@ font-weight: 600; } -.cards { - width: 45%; - background: #fcfcfc; - margin: 10px 20px; - padding: 20px 30px; - border-radius: 5px; - border: 1px solid #e8e8e8; - box-shadow: 0 3px 5px #c9c9c9; - margin-right: 40px; - color: #737373; -} .cards > h2 { font-size: 19px; } @@ -61,6 +50,43 @@ margin-bottom: 7px; } +.cards:hover { + filter: brightness(0.8); +} +.cards:hover::before { + opacity: 0.5; +} + +.cards:hover::after { + opacity: 1; + mix-blend-mode: normal; +} + +.cards:last-child:nth-last-child(odd) { + grid-column: auto / span 2; +} + +.cards:first-child:nth-last-child(even), +.cards:first-child:nth-last-child(even) ~ .box { + grid-column: auto / span 1; +} + +.capacityLabel { + background-color: var(--bs-primary); + color: white; + height: 22.19px; + font-size: 12px; + font-weight: bolder; + padding: 0.1rem 0.3rem; + border-radius: 0.5rem; + position: relative; + overflow: hidden; +} + +.capacityLabel svg { + margin-bottom: 3px; +} + .sidebar { z-index: 0; padding-top: 5px; @@ -198,19 +224,28 @@ color: var(--brown-color) !important; } +.dropdown:is(:focus, :focus-visible) { + outline: 2px solid var(--highlight-color, #a8c7fa); +} + .dropdownItem { background-color: white !important; color: var(--brown-color) !important; border: none !important; } +.dropdownItem:focus, +.dropdownItem:hover { + outline: 2px solid var(--highlight-color, #a8c7fa); +} + .dropdownItem:hover, .dropdownItem:focus, .dropdownItem:active { - background-color: var(--dropdown-hover-color) !important; + background-color: var(--dropdown-hover-color, #e0e0e0) !important; color: var(--brown-color) !important; outline: none !important; - box-shadow: none !important; + box-shadow: 0 0 4px var(--highlight-color, #a8c7fa); } .input { @@ -339,11 +374,19 @@ align-items: center; } +.searchButton:hover { + background-color: var(--search-button-hover-bg, #286fe0); + border-color: var(--search-button-border); +} + +.searchButton:active { + transform: scale(0.95); +} + .addButton { margin-bottom: 10px; background-color: var(--search-button-bg); border-color: var(--grey-bg-color); - color: #555555; } .addButton:hover { From 2327a4bc6ee8671adaf370d770d1e260c6e0552f Mon Sep 17 00:00:00 2001 From: Mehul Aggarwal <88583647+AceHunterr@users.noreply.github.com> Date: Sat, 28 Dec 2024 01:29:50 +0530 Subject: [PATCH 02/11] Refactored css in src/screens/OrganizationPeople/OrganizationPeople.tsx (#2978) --- .../OrganizationPeople/OrganizationPeople.tsx | 10 +- src/style/app.module.css | 99 ++++++++++--------- 2 files changed, 55 insertions(+), 54 deletions(-) diff --git a/src/screens/OrganizationPeople/OrganizationPeople.tsx b/src/screens/OrganizationPeople/OrganizationPeople.tsx index 36efdba63c..47a2d2a3b2 100644 --- a/src/screens/OrganizationPeople/OrganizationPeople.tsx +++ b/src/screens/OrganizationPeople/OrganizationPeople.tsx @@ -393,21 +393,21 @@ function organizationPeople(): JSX.Element { ), }} sx={{ - borderRadius: '20px', - backgroundColor: '#EAEBEF', + borderRadius: 'var(--table-head-radius)', + backgroundColor: 'var(--grey-bg-color)', '& .MuiDataGrid-row': { - backgroundColor: '#eff1f7', + backgroundColor: 'var(--tablerow-bg-color)', '&:focus-within': { outline: '2px solid #000', outlineOffset: '-2px', }, }, '& .MuiDataGrid-row:hover': { - backgroundColor: '#EAEBEF', + backgroundColor: 'var(--grey-bg-color)', boxShadow: '0 0 0 1px rgba(0, 0, 0, 0.1)', }, '& .MuiDataGrid-row.Mui-hovered': { - backgroundColor: '#EAEBEF', + backgroundColor: 'var(--grey-bg-color)', boxShadow: '0 0 0 1px rgba(0, 0, 0, 0.1)', }, '& .MuiDataGrid-cell:focus': { diff --git a/src/style/app.module.css b/src/style/app.module.css index cd55f8c1c0..6be00d217a 100644 --- a/src/style/app.module.css +++ b/src/style/app.module.css @@ -2,6 +2,7 @@ --brown-color: #555555; --dropdown-hover-color: #eff1f7; --grey-bg-color: #eaebef; + --grey-border-box-color: #e8e5e5; --subtle-blue-grey: #7c9beb; --subtle-blue-grey-hover: #5f7e91; --modal-width: 670px; @@ -15,13 +16,13 @@ --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 --loader-size: 10em; --loader-border-width: 1.1em; --loader-color: - #febc59; + blue ); /* Assuming var(--bs-primary) is defined elsewhere */ - + --loader-size: 10em; + --loader-border-width: 1.1em; + --loader-color: #febc59; --table-head-color: white; --table-header-color: var(--bs-greyish-black, black); --table-head-radius: 20px; @@ -165,7 +166,7 @@ .sidebarsticky > input { text-decoration: none; margin-bottom: 50px; - border-color: #e8e5e5; + border-color: var(--grey-border-box-color); width: 80%; border-radius: 7px; padding-top: 5px; @@ -184,13 +185,13 @@ color: var(--delete-button-color); margin-right: 5px; background-color: var(--delete-button-bg); - border: white; + border: var(--bs-white); } .closeButton:hover { color: var(--delete-button-bg) !important; background-color: var(--delete-button-color) !important; - border: white; + border: var(--bs-white); } .modalContent { @@ -209,7 +210,7 @@ } .dropdown { - background-color: white; + background-color: var(--bs-white); border: 1px solid var(--brown-color); color: var(--brown-color); position: relative; @@ -229,7 +230,7 @@ } .dropdownItem { - background-color: white !important; + background-color: var(--bs-white) !important; color: var(--brown-color) !important; border: none !important; } @@ -346,13 +347,13 @@ .inputField { margin-top: 10px; margin-bottom: 10px; - background-color: white; + background-color: var(--bs-white); box-shadow: 0 1px 1px var(--input-shadow-color); } .inputFieldModal { margin-bottom: 10px; - background-color: white; + background-color: var(--bs-white); box-shadow: 0 1px 1px var(--input-shadow-color); } @@ -652,7 +653,7 @@ hr { .greenregbtnPledge { margin-top: 15px; border: 1px solid var(--bs-gray-300); - box-shadow: 0 2px 2px #e8e5e5; + box-shadow: 0 2px 2px var(--grey-border-box-color); padding: 10px 10px; border-radius: 5px; background-color: var(--bs-primary); @@ -688,12 +689,12 @@ hr { } .inputFieldPledge { - background-color: white; + background-color: var(--bs-white); box-shadow: 0 1px 1px #31bb6b; } .dropdownPledge { - background-color: white; + background-color: var(--bs-white); border: 1px solid var(--bs-primary); position: relative; display: inline-block; @@ -827,7 +828,7 @@ hr { margin-top: 0.5rem; padding: 0.75rem; border: 1px solid #e2e8f0; - background-color: white; + background-color: var(--bs-white); color: #1e293b; box-shadow: 0 0.5rem 1rem rgb(0 0 0 / 0.15); display: flex; @@ -1007,7 +1008,7 @@ hr { .customcell { background-color: #31bb6b !important; - color: white !important; + color: var(--bs-white) !important; font-size: medium !important; font-weight: 500 !important; padding-top: 10px !important; @@ -1054,13 +1055,13 @@ hr { margin: 1rem 0 0; margin-top: 15px; border: 1px solid var(--bs-gray-300); - box-shadow: 0 2px 2px #e8e5e5; + box-shadow: 0 2px 2px var(--grey-border-box-color); padding: 10px 10px; border-radius: 5px; background-color: var(--bs-primary); width: 100%; font-size: 16px; - color: white; + color: var(--bs-white); outline: none; font-weight: 600; cursor: pointer; @@ -1071,7 +1072,7 @@ hr { } .goalButtonOrganizationFundCampaign { - border: 1px solid #e8e5e5 !important; + border: 1px solid var(--grey-border-box-color) !important; color: #707070 !important; width: 75%; padding: 10px; @@ -1084,13 +1085,13 @@ hr { .redregbtn { margin: 1rem 0 0; margin-top: 15px; - border: 1px solid #e8e5e5; - box-shadow: 0 2px 2px #e8e5e5; + border: 1px solid var(--grey-border-box-color); + box-shadow: 0 2px 2px var(--grey-border-box-color); padding: 10px 10px; border-radius: 5px; width: 100%; font-size: 16px; - color: white; + color: var(--bs-white); outline: none; font-weight: 600; cursor: pointer; @@ -1111,13 +1112,13 @@ hr { } .inputFieldOrganizationFundCampaign { - background-color: white; + background-color: var(--bs-white); box-shadow: 0 1px 1px var(--search-button-bg); } .dropdownOrganizationFundCampaign { - background-color: white; - border: 1px solid #e8e5e5; + background-color: var(--bs-white); + border: 1px solid var(--grey-border-box-color); position: relative; display: inline-block; color: #707070; @@ -1510,12 +1511,12 @@ input[type='radio']:checked + label:hover { .manageBtn { margin: 1rem 0 0; margin-top: 15px; - border: 1px solid #e8e5e5; - box-shadow: 0 2px 2px #e8e5e5; + border: 1px solid var(--grey-border-box-color); + box-shadow: 0 2px 2px var(--grey-border-box-color); padding: 10px 10px; border-radius: 5px; font-size: 16px; - color: white; + color: var(--bs-white); outline: none; font-weight: 600; cursor: pointer; @@ -1578,7 +1579,7 @@ input[type='radio']:checked + label:hover { } .dropdowns { - background-color: white; + background-color: var(--bs-white); border: 1px solid #31bb6b; position: relative; display: inline-block; @@ -1676,7 +1677,7 @@ input[type='radio']:checked + label:hover { .pluginStoreBtn { width: 100%; - background-color: white; + background-color: var(--bs-white); color: var(--brown-color); border: 0.5px solid var(--brown-color); } @@ -1845,7 +1846,7 @@ input[type='radio']:checked + label:hover { .sidebarstickyMemberDetail > input { text-decoration: none; margin-bottom: 50px; - border-color: #e8e5e5; + border-color: var(--grey-border-box-color); width: 80%; border-radius: 7px; padding-top: 5px; @@ -1918,12 +1919,12 @@ input[type='radio']:checked + label:hover { } .invitebtn { - border: 1px solid #e8e5e5; - box-shadow: 0 2px 2px #e8e5e5; + border: 1px solid var(--grey-border-box-color); + box-shadow: 0 2px 2px var(--grey-border-box-color); border-radius: 5px; font-size: 16px; height: 60%; - color: white; + color: var(--bs-white); outline: none; font-weight: 600; cursor: pointer; @@ -1952,7 +1953,7 @@ input[type='radio']:checked + label:hover { width: 30%; padding: 40px 30px; background: #ffffff; - border-color: #e8e5e5; + border-color: var(--grey-border-box-color); border-width: 5px; border-radius: 10px; max-height: 86vh; @@ -2004,13 +2005,13 @@ input[type='radio']:checked + label:hover { .greenregbtnMemberDetail { margin: 1rem 0 0; margin-top: 10px; - border: 1px solid #e8e5e5; - box-shadow: 0 2px 2px #e8e5e5; + border: 1px solid var(--grey-border-box-color); + box-shadow: 0 2px 2px var(--grey-border-box-color); padding: 10px 10px; border-radius: 5px; background-color: #eaebef; font-size: 16px; - color: white; + color: var(--bs-white); outline: none; font-weight: 600; cursor: pointer; @@ -2026,7 +2027,7 @@ input[type='radio']:checked + label:hover { border: 1px solid #eaebef; padding: 10px 10px; border-radius: 5px; - background-color: white; + background-color: var(--bs-white); font-size: 16px; color: #707070; outline: none; @@ -2112,9 +2113,9 @@ input[type='radio']:checked + label:hover { .memberfontcreatedbtn { border-radius: 7px; - border-color: #e8e5e5; + border-color: var(--grey-border-box-color); background-color: #eaebef; - color: white; + color: var(--bs-white); box-shadow: none; height: 2.5rem; width: max-content; @@ -2266,7 +2267,7 @@ input[type='radio']:checked + label:hover { .dateboxMemberDetail { border-radius: 7px; - border-color: #e8e5e5; + border-color: var(--grey-border-box-color); outline: none; box-shadow: none; padding-top: 2px; @@ -2301,7 +2302,7 @@ input[type='radio']:checked + label:hover { input::file-selector-button { background-color: black; - color: white; + color: var(--bs-white); } .Outline { @@ -2484,8 +2485,8 @@ form label { form > input { display: block; margin-bottom: 20px; - border: 1px solid #e8e5e5; - box-shadow: 2px 1px #e8e5e5; + border: 1px solid var(--grey-border-box-color); + box-shadow: 2px 1px var(--grey-border-box-color); padding: 10px 20px; border-radius: 5px; background: none; @@ -2647,7 +2648,7 @@ form > input { background-color: var(--dropdown-border-color); border-color: var(--dropdown-border-color); margin-top: 1rem; - color: white; + color: var(--bs-white); margin-bottom: 1rem; width: 100%; transition: background-color 0.2s ease; @@ -3014,13 +3015,13 @@ form > input { } } .addbtnOrgPost { - border: 1px solid #e8e5e5; - box-shadow: 0 2px 2px #e8e5e5; + border: 1px solid var(--grey-border-box-color); + box-shadow: 0 2px 2px var(--grey-border-box-color); border-radius: 5px; font-size: 16px; height: 60%; width: 60%; - color: white; + color: var(--bs-white); outline: none; font-weight: 600; cursor: pointer; From e73d61df3f502c7336a63ea7b15ad97c353459b5 Mon Sep 17 00:00:00 2001 From: Abhishek Raj <113784630+abbi4code@users.noreply.github.com> Date: Sat, 28 Dec 2024 04:09:34 +0530 Subject: [PATCH 03/11] Refactor src/components/UserPortal/* from Jest to Vitest (#2982) * chatroom tests migrated from jest to vitest * chore: fixed undefined typescript _id error in chatroom component & add missing mutation in orginizationCard_ * chore: createDirectChat tests migrated from jest to vitest * chore: creategroupchat tests migrated from jest to vitest * chore: donationcard,orgcard, orgnavbar, orgsidebar tests migrated from jest to vitest * chore: peoplecard, postcard, promotedPost, register, securedrouteforuser tests migrated from jest to vitest * chore: startPostModal, usernavbar, userprofile, usersidebar, usersidebarorg tests migrated from jest to vitest --- .../{ChatRoom.test.tsx => ChatRoom.spec.tsx} | 25 ++++--- .../UserPortal/ChatRoom/ChatRoom.tsx | 15 ++-- ...mentCard.test.tsx => CommentCard.spec.tsx} | 27 ++++--- ...tactCard.test.tsx => ContactCard.spec.tsx} | 26 +++++-- ...hat.test.tsx => CreateDirectChat.spec.tsx} | 35 ++++++--- ...Chat.test.tsx => CreateGroupChat.spec.tsx} | 38 +++++++--- ...ionCard.test.tsx => DonationCard.spec.tsx} | 15 +++- ...{EventCard.test.tsx => EventCard.spec.tsx} | 10 ++- ...ard.test.tsx => OrganizationCard.spec.tsx} | 61 +++++++++++++--- ...r.test.tsx => OrganizationNavbar.spec.tsx} | 68 ++++++++++++------ ....test.tsx => OrganizationSidebar.spec.tsx} | 32 +++++++-- ...eopleCard.test.tsx => PeopleCard.spec.tsx} | 16 ++++- .../{PostCard.test.tsx => PostCard.spec.tsx} | 71 ++++++++++++------- ...tedPost.test.tsx => PromotedPost.spec.tsx} | 22 ++++-- .../{Register.test.tsx => Register.spec.tsx} | 40 +++++++---- ....test.tsx => SecuredRouteForUser.spec.tsx} | 16 ++++- ...Modal.test.tsx => StartPostModal.spec.tsx} | 42 +++++++---- ...serNavbar.test.tsx => UserNavbar.spec.tsx} | 32 ++++++--- ...test.tsx => EventsAttendedByUser.spec.tsx} | 16 ++++- ...ds.test.tsx => UserAddressFields.spec.tsx} | 31 +++++--- ...rSidebar.test.tsx => UserSidebar.spec.tsx} | 47 ++++++++---- ...arOrg.test.tsx => UserSidebarOrg.spec.tsx} | 47 +++++++----- 22 files changed, 523 insertions(+), 209 deletions(-) rename src/components/UserPortal/ChatRoom/{ChatRoom.test.tsx => ChatRoom.spec.tsx} (98%) rename src/components/UserPortal/CommentCard/{CommentCard.test.tsx => CommentCard.spec.tsx} (85%) rename src/components/UserPortal/ContactCard/{ContactCard.test.tsx => ContactCard.spec.tsx} (73%) rename src/components/UserPortal/CreateDirectChat/{CreateDirectChat.test.tsx => CreateDirectChat.spec.tsx} (97%) rename src/components/UserPortal/CreateGroupChat/{CreateGroupChat.test.tsx => CreateGroupChat.spec.tsx} (97%) rename src/components/UserPortal/DonationCard/{DonationCard.test.tsx => DonationCard.spec.tsx} (64%) rename src/components/UserPortal/EventCard/{EventCard.test.tsx => EventCard.spec.tsx} (94%) rename src/components/UserPortal/OrganizationCard/{OrganizationCard.test.tsx => OrganizationCard.spec.tsx} (77%) rename src/components/UserPortal/OrganizationNavbar/{OrganizationNavbar.test.tsx => OrganizationNavbar.spec.tsx} (81%) rename src/components/UserPortal/OrganizationSidebar/{OrganizationSidebar.test.tsx => OrganizationSidebar.spec.tsx} (74%) rename src/components/UserPortal/PeopleCard/{PeopleCard.test.tsx => PeopleCard.spec.tsx} (65%) rename src/components/UserPortal/PostCard/{PostCard.test.tsx => PostCard.spec.tsx} (90%) rename src/components/UserPortal/PromotedPost/{PromotedPost.test.tsx => PromotedPost.spec.tsx} (77%) rename src/components/UserPortal/Register/{Register.test.tsx => Register.spec.tsx} (80%) rename src/components/UserPortal/SecuredRouteForUser/{SecuredRouteForUser.test.tsx => SecuredRouteForUser.spec.tsx} (77%) rename src/components/UserPortal/StartPostModal/{StartPostModal.test.tsx => StartPostModal.spec.tsx} (71%) rename src/components/UserPortal/UserNavbar/{UserNavbar.test.tsx => UserNavbar.spec.tsx} (74%) rename src/components/UserPortal/UserProfile/{EventsAttendedByUser.test.tsx => EventsAttendedByUser.spec.tsx} (76%) rename src/components/UserPortal/UserProfile/{UserAddressFields.test.tsx => UserAddressFields.spec.tsx} (69%) rename src/components/UserPortal/UserSidebar/{UserSidebar.test.tsx => UserSidebar.spec.tsx} (86%) rename src/components/UserPortal/UserSidebarOrg/{UserSidebarOrg.test.tsx => UserSidebarOrg.spec.tsx} (86%) diff --git a/src/components/UserPortal/ChatRoom/ChatRoom.test.tsx b/src/components/UserPortal/ChatRoom/ChatRoom.spec.tsx similarity index 98% rename from src/components/UserPortal/ChatRoom/ChatRoom.test.tsx rename to src/components/UserPortal/ChatRoom/ChatRoom.spec.tsx index c808485132..fef1b67fa5 100644 --- a/src/components/UserPortal/ChatRoom/ChatRoom.test.tsx +++ b/src/components/UserPortal/ChatRoom/ChatRoom.spec.tsx @@ -21,6 +21,15 @@ import { import ChatRoom from './ChatRoom'; import { useLocalStorage } from 'utils/useLocalstorage'; import { StaticMockLink } from 'utils/StaticMockLink'; +import { vi } from 'vitest'; + +/** + * Unit tests for the ChatRoom component + * + * Tests cover component rendering, message functionality (sending/replying), + * user interactions, GraphQL integration, and provider integrations + * (Router, Redux, i18n) for both direct and group chats. + */ const { setItem } = useLocalStorage(); @@ -1188,9 +1197,9 @@ const SEND_MESSAGE_TO_CHAT_MOCK = [ ]; describe('Testing Chatroom Component [User Portal]', () => { - window.HTMLElement.prototype.scrollIntoView = jest.fn(); + window.HTMLElement.prototype.scrollIntoView = vi.fn(); - test('Chat room should display fallback content if no chat is active', async () => { + it('Chat room should display fallback content if no chat is active', async () => { const mocks = [ ...MESSAGE_SENT_TO_CHAT_MOCK, ...CHAT_BY_ID_QUERY_MOCK, @@ -1212,7 +1221,7 @@ describe('Testing Chatroom Component [User Portal]', () => { expect(await screen.findByTestId('noChatSelected')).toBeInTheDocument(); }); - test('Selected contact is direct chat', async () => { + it('Selected contact is direct chat', async () => { const link = new MockSubscriptionLink(); const mocks = [ ...MESSAGE_SENT_TO_CHAT_MOCK, @@ -1234,7 +1243,7 @@ describe('Testing Chatroom Component [User Portal]', () => { await wait(); }); - test('send message direct chat', async () => { + it('send message direct chat', async () => { setItem('userId', '2'); const mocks = [ ...MESSAGE_SENT_TO_CHAT_MOCK, @@ -1319,7 +1328,7 @@ describe('Testing Chatroom Component [User Portal]', () => { await wait(400); }); - test('send message direct chat when userId is different', async () => { + it('send message direct chat when userId is different', async () => { setItem('userId', '8'); const mocks = [ ...GROUP_CHAT_BY_ID_QUERY_MOCK, @@ -1404,7 +1413,7 @@ describe('Testing Chatroom Component [User Portal]', () => { await wait(400); }); - test('Selected contact is group chat', async () => { + it('Selected contact is group chat', async () => { const mocks = [ ...MESSAGE_SENT_TO_CHAT_MOCK, ...CHAT_BY_ID_QUERY_MOCK, @@ -1425,7 +1434,7 @@ describe('Testing Chatroom Component [User Portal]', () => { await wait(); }); - test('send message group chat', async () => { + it('send message group chat', async () => { const mocks = [ ...MESSAGE_SENT_TO_CHAT_MOCK, ...CHAT_BY_ID_QUERY_MOCK, @@ -1505,7 +1514,7 @@ describe('Testing Chatroom Component [User Portal]', () => { await wait(500); }); - test('reply to message', async () => { + it('reply to message', async () => { const mocks = [ ...MESSAGE_SENT_TO_CHAT_MOCK, ...CHAT_BY_ID_QUERY_MOCK, diff --git a/src/components/UserPortal/ChatRoom/ChatRoom.tsx b/src/components/UserPortal/ChatRoom/ChatRoom.tsx index c23244a314..27768dce5a 100644 --- a/src/components/UserPortal/ChatRoom/ChatRoom.tsx +++ b/src/components/UserPortal/ChatRoom/ChatRoom.tsx @@ -159,17 +159,14 @@ export default function chatRoom(props: InterfaceChatRoomProps): JSX.Element { userId: userId, }, onData: (messageSubscriptionData) => { - if ( - messageSubscriptionData?.data.data.messageSentToChat && - messageSubscriptionData?.data.data.messageSentToChat - .chatMessageBelongsTo['_id'] == props.selectedContact - ) { + const chatMessage = messageSubscriptionData.data?.data?.messageSentToChat; + const chatId = chatMessage?.chatMessageBelongsTo?._id; + + if (!chatId) return; + if (chatId === props.selectedContact) { chatRefetch(); } else { - chatRefetch({ - id: messageSubscriptionData?.data.data.messageSentToChat - .chatMessageBelongsTo['_id'], - }); + chatRefetch({ id: chatId }); } }, }); diff --git a/src/components/UserPortal/CommentCard/CommentCard.test.tsx b/src/components/UserPortal/CommentCard/CommentCard.spec.tsx similarity index 85% rename from src/components/UserPortal/CommentCard/CommentCard.test.tsx rename to src/components/UserPortal/CommentCard/CommentCard.spec.tsx index f02e5a606a..112fd1bcf5 100644 --- a/src/components/UserPortal/CommentCard/CommentCard.test.tsx +++ b/src/components/UserPortal/CommentCard/CommentCard.spec.tsx @@ -7,12 +7,23 @@ import { BrowserRouter } from 'react-router-dom'; import { store } from 'state/store'; import i18nForTest from 'utils/i18nForTest'; import { StaticMockLink } from 'utils/StaticMockLink'; - import CommentCard from './CommentCard'; import userEvent from '@testing-library/user-event'; import { LIKE_COMMENT, UNLIKE_COMMENT } from 'GraphQl/Mutations/mutations'; import useLocalStorage from 'utils/useLocalstorage'; - +import { vi } from 'vitest'; + +/** + * Unit tests for the CommentCard component. + * + * These tests ensure the CommentCard component renders and behaves as expected + * under different scenarios. They cover various functionalities like: + * - Initial rendering with comment liked/not liked by user + * - User liking a comment + * - User unliking a comment + * Mocked dependencies like `useLocalStorage` and Apollo Client mocks are used + * to isolate the component and test its behavior independently. + */ const { getItem, setItem } = useLocalStorage(); async function wait(ms = 100): Promise { @@ -56,8 +67,8 @@ const MOCKS = [ }, ]; -const handleLikeComment = jest.fn(); -const handleDislikeComment = jest.fn(); +const handleLikeComment = vi.fn(); +const handleDislikeComment = vi.fn(); const link = new StaticMockLink(MOCKS, true); describe('Testing CommentCard Component [User Portal]', () => { @@ -67,7 +78,7 @@ describe('Testing CommentCard Component [User Portal]', () => { }); }); - test('Component should be rendered properly if comment is already liked by the user.', async () => { + it('Component should be rendered properly if comment is already liked by the user.', async () => { const cardProps = { id: '1', creator: { @@ -108,7 +119,7 @@ describe('Testing CommentCard Component [User Portal]', () => { } }); - test('Component should be rendered properly if comment is not already liked by the user.', async () => { + it('Component should be rendered properly if comment is not already liked by the user.', async () => { const cardProps = { id: '1', creator: { @@ -149,7 +160,7 @@ describe('Testing CommentCard Component [User Portal]', () => { } }); - test('Component renders as expected if user likes the comment.', async () => { + it('Component renders as expected if user likes the comment.', async () => { const cardProps = { id: '1', creator: { @@ -195,7 +206,7 @@ describe('Testing CommentCard Component [User Portal]', () => { } }); - test('Component renders as expected if user unlikes the comment.', async () => { + it('Component renders as expected if user unlikes the comment.', async () => { const cardProps = { id: '1', creator: { diff --git a/src/components/UserPortal/ContactCard/ContactCard.test.tsx b/src/components/UserPortal/ContactCard/ContactCard.spec.tsx similarity index 73% rename from src/components/UserPortal/ContactCard/ContactCard.test.tsx rename to src/components/UserPortal/ContactCard/ContactCard.spec.tsx index 05a6a0a530..1d32360301 100644 --- a/src/components/UserPortal/ContactCard/ContactCard.test.tsx +++ b/src/components/UserPortal/ContactCard/ContactCard.spec.tsx @@ -10,7 +10,19 @@ import i18nForTest from 'utils/i18nForTest'; import { StaticMockLink } from 'utils/StaticMockLink'; import ContactCard from './ContactCard'; import userEvent from '@testing-library/user-event'; - +import { vi } from 'vitest'; + +/** + * Unit tests for the ContactCard component. + * + * These tests ensure the ContactCard component renders and behaves as expected + * under different scenarios. They cover various functionalities like: + * - Rendering the contact card with and without a profile image + * - Selecting a contact by clicking on the card + * - Applying a grey background color to the selected contact card (for groups) + * Mocked dependencies like StaticMockLink are used + * to isolate the component and test its behavior independently. + */ const link = new StaticMockLink([], true); async function wait(ms = 100): Promise { @@ -30,12 +42,12 @@ let props = { image: '', selectedContact: '', type: '', - setSelectedContact: jest.fn(), - setSelectedChatType: jest.fn(), + setSelectedContact: vi.fn(), + setSelectedChatType: vi.fn(), }; describe('Testing ContactCard Component [User Portal]', () => { - test('Component should be rendered properly if person image is undefined', async () => { + it('Component should be rendered properly if person image is undefined', async () => { render( @@ -51,7 +63,7 @@ describe('Testing ContactCard Component [User Portal]', () => { await wait(); }); - test('Component should be rendered properly if person image is not undefined', async () => { + it('Component should be rendered properly if person image is not undefined', async () => { props = { ...props, image: 'personImage', @@ -72,7 +84,7 @@ describe('Testing ContactCard Component [User Portal]', () => { await wait(); }); - test('Contact gets selectected when component is clicked', async () => { + it('Contact gets selectected when component is clicked', async () => { render( @@ -92,7 +104,7 @@ describe('Testing ContactCard Component [User Portal]', () => { await wait(); }); - test('Component is rendered with background color grey if the contact is selected', async () => { + it('Component is rendered with background color grey if the contact is selected', async () => { props = { ...props, selectedContact: '1', diff --git a/src/components/UserPortal/CreateDirectChat/CreateDirectChat.test.tsx b/src/components/UserPortal/CreateDirectChat/CreateDirectChat.spec.tsx similarity index 97% rename from src/components/UserPortal/CreateDirectChat/CreateDirectChat.test.tsx rename to src/components/UserPortal/CreateDirectChat/CreateDirectChat.spec.tsx index d8b3466207..5526206708 100644 --- a/src/components/UserPortal/CreateDirectChat/CreateDirectChat.test.tsx +++ b/src/components/UserPortal/CreateDirectChat/CreateDirectChat.spec.tsx @@ -20,9 +20,24 @@ import { } from 'GraphQl/Mutations/OrganizationMutations'; import { CHATS_LIST, CHAT_BY_ID } from 'GraphQl/Queries/PlugInQueries'; import useLocalStorage from 'utils/useLocalstorage'; - +import { vi } from 'vitest'; const { setItem } = useLocalStorage(); +/** + * Unit tests for the Create Direct Chat Modal functionality in the User Portal + * + * These tests cover the following scenarios: + * 1. Opening and closing the create new direct chat modal, ensuring proper UI elements + * like dropdown, search input, and submit button are displayed and functional. + * 2. Creating a new direct chat, which includes testing the interaction with the add button, + * submitting the chat, and closing the modal. + * + * Tests involve interacting with the modal's UI elements, performing actions like + * opening the dropdown, searching for users, clicking on the submit button, and closing + * the modal. GraphQL mocks are used for testing chat-related queries and mutations, + * ensuring that the modal behaves as expected when interacting with the GraphQL API. + */ + const UserConnectionListMock = [ { request: { @@ -1380,23 +1395,23 @@ async function wait(ms = 100): Promise { } describe('Testing Create Direct Chat Modal [User Portal]', () => { - window.HTMLElement.prototype.scrollIntoView = jest.fn(); + window.HTMLElement.prototype.scrollIntoView = vi.fn(); 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('Open and close create new direct chat modal', async () => { + it('Open and close create new direct chat modal', async () => { const mock = [ ...GROUP_CHAT_BY_ID_QUERY_MOCK, ...MESSAGE_SENT_TO_CHAT_MOCK, @@ -1446,7 +1461,7 @@ describe('Testing Create Direct Chat Modal [User Portal]', () => { fireEvent.click(closeButton); }); - test('create new direct chat', async () => { + it('create new direct chat', async () => { setItem('userId', '1'); const mock = [ ...GROUP_CHAT_BY_ID_QUERY_MOCK, diff --git a/src/components/UserPortal/CreateGroupChat/CreateGroupChat.test.tsx b/src/components/UserPortal/CreateGroupChat/CreateGroupChat.spec.tsx similarity index 97% rename from src/components/UserPortal/CreateGroupChat/CreateGroupChat.test.tsx rename to src/components/UserPortal/CreateGroupChat/CreateGroupChat.spec.tsx index 055985d5fb..711bb29a93 100644 --- a/src/components/UserPortal/CreateGroupChat/CreateGroupChat.test.tsx +++ b/src/components/UserPortal/CreateGroupChat/CreateGroupChat.spec.tsx @@ -26,6 +26,24 @@ import { import { CHATS_LIST, CHAT_BY_ID } from 'GraphQl/Queries/PlugInQueries'; import useLocalStorage from 'utils/useLocalstorage'; import userEvent from '@testing-library/user-event'; +import { vi } from 'vitest'; + +/** + * Unit tests for the Create Group Chat Modal functionality in the User Portal + * + * These tests cover the following scenarios: + * 1. Opening and closing the create new group chat modal, ensuring proper UI elements + * like the dropdown, new group chat button, and close button are displayed and functional. + * 2. Creating a new group chat by interacting with the group name input field, organization + * selection, and submission process. It also ensures that the create button is properly + * triggered after filling out the required fields. + * 3. Adding and removing users from the group chat, testing the interactions with the add + * and remove buttons, and verifying the submit button and search functionality for user selection. + * + * GraphQL mocks are used to simulate chat-related queries and mutations. The tests ensure that + * the modal behaves correctly in various user interaction scenarios, including handling of form + * fields, user management, and modal navigation. + */ const { setItem } = useLocalStorage(); @@ -2212,23 +2230,23 @@ async function wait(ms = 100): Promise { } describe('Testing Create Group Chat Modal [User Portal]', () => { - window.HTMLElement.prototype.scrollIntoView = jest.fn(); + window.HTMLElement.prototype.scrollIntoView = vi.fn(); 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('open and close create new direct chat modal', async () => { + it('open and close create new direct chat modal', async () => { const mock = [ ...USER_JOINED_ORG_MOCK, ...GROUP_CHAT_BY_ID_QUERY_MOCK, @@ -2266,7 +2284,7 @@ describe('Testing Create Group Chat Modal [User Portal]', () => { fireEvent.click(closeButton); }); - test('create new group chat', async () => { + it('create new group chat', async () => { const mock = [ ...USER_JOINED_ORG_MOCK, ...GROUP_CHAT_BY_ID_QUERY_MOCK, @@ -2366,7 +2384,7 @@ describe('Testing Create Group Chat Modal [User Portal]', () => { // }); }, 3000); - test('add and remove user', async () => { + it('add and remove user', async () => { setItem('userId', '1'); const mock = [ ...USER_JOINED_ORG_MOCK, diff --git a/src/components/UserPortal/DonationCard/DonationCard.test.tsx b/src/components/UserPortal/DonationCard/DonationCard.spec.tsx similarity index 64% rename from src/components/UserPortal/DonationCard/DonationCard.test.tsx rename to src/components/UserPortal/DonationCard/DonationCard.spec.tsx index cddf62dd6c..f4d8473dd1 100644 --- a/src/components/UserPortal/DonationCard/DonationCard.test.tsx +++ b/src/components/UserPortal/DonationCard/DonationCard.spec.tsx @@ -11,6 +11,19 @@ import { StaticMockLink } from 'utils/StaticMockLink'; import DonationCard from './DonationCard'; import { type InterfaceDonationCardProps } from 'screens/UserPortal/Donate/Donate'; +/** + * Unit test for the DonationCard component in the User Portal + * + * This test ensures that the DonationCard component renders correctly when provided with + * the required props. It uses the MockedProvider to mock any GraphQL queries and the + * StaticMockLink to simulate the network layer. The component is wrapped with necessary + * providers such as BrowserRouter, Redux store, and i18n provider to simulate the environment + * in which the component operates. + * + * The test specifically checks if the component renders without errors, though more tests + * can be added in the future to validate interactions and state changes based on user actions. + */ + const link = new StaticMockLink([], true); async function wait(ms = 100): Promise { @@ -31,7 +44,7 @@ const props: InterfaceDonationCardProps = { }; describe('Testing ContactCard Component [User Portal]', () => { - test('Component should be rendered properly', async () => { + it('Component should be rendered properly', async () => { render( diff --git a/src/components/UserPortal/EventCard/EventCard.test.tsx b/src/components/UserPortal/EventCard/EventCard.spec.tsx similarity index 94% rename from src/components/UserPortal/EventCard/EventCard.test.tsx rename to src/components/UserPortal/EventCard/EventCard.spec.tsx index 78aa32abcf..150f676447 100644 --- a/src/components/UserPortal/EventCard/EventCard.test.tsx +++ b/src/components/UserPortal/EventCard/EventCard.spec.tsx @@ -11,7 +11,6 @@ import { Provider } from 'react-redux'; import { store } from 'state/store'; import { StaticMockLink } from 'utils/StaticMockLink'; import userEvent from '@testing-library/user-event'; -import { debug } from 'jest-preview'; import useLocalStorage from 'utils/useLocalstorage'; const { setItem } = useLocalStorage(); @@ -66,7 +65,7 @@ describe('Testing Event Card In User portal', () => { ], }; - test('The card should be rendered properly, and all the details should be displayed correct', async () => { + it('The card should be rendered properly, and all the details should be displayed correct', async () => { const { queryByText } = render( @@ -79,7 +78,6 @@ describe('Testing Event Card In User portal', () => { , ); - debug(); await waitFor(() => expect(queryByText('Test Event')).toBeInTheDocument()); await waitFor(() => expect(queryByText('This is a test event')).toBeInTheDocument(), @@ -105,7 +103,7 @@ describe('Testing Event Card In User portal', () => { await waitFor(() => expect(queryByText('Register')).toBeInTheDocument()); }); - test('When the user is already registered', async () => { + it('When the user is already registered', async () => { setItem('userId', '234'); const { queryByText } = render( @@ -124,7 +122,7 @@ describe('Testing Event Card In User portal', () => { ); }); - test('Handle register should work properly', async () => { + it('Handle register should work properly', async () => { setItem('userId', '456'); const { queryByText } = render( @@ -173,7 +171,7 @@ describe('Event card when start and end time are not given', () => { ], }; - test('Card is rendered correctly', async () => { + it('Card is rendered correctly', async () => { const { container } = render( diff --git a/src/components/UserPortal/OrganizationCard/OrganizationCard.test.tsx b/src/components/UserPortal/OrganizationCard/OrganizationCard.spec.tsx similarity index 77% rename from src/components/UserPortal/OrganizationCard/OrganizationCard.test.tsx rename to src/components/UserPortal/OrganizationCard/OrganizationCard.spec.tsx index 77516ddc7a..1aa8c8462a 100644 --- a/src/components/UserPortal/OrganizationCard/OrganizationCard.test.tsx +++ b/src/components/UserPortal/OrganizationCard/OrganizationCard.spec.tsx @@ -18,15 +18,33 @@ import useLocalStorage from 'utils/useLocalstorage'; import { SEND_MEMBERSHIP_REQUEST, JOIN_PUBLIC_ORGANIZATION, + CANCEL_MEMBERSHIP_REQUEST, } from 'GraphQl/Mutations/OrganizationMutations'; import { toast } from 'react-toastify'; - +import { vi } from 'vitest'; + +/** + * Unit tests for the OrganizationCard component in the User Portal + * + * These tests validate the behavior and rendering of the OrganizationCard component. + * The tests ensure the component displays properly with various states and that interactions + * such as sending membership requests and visiting organizations work as expected. + * + * 1. **Component should be rendered properly**: Tests if the component renders correctly with the provided props. + * 2. **Component should render properly with an image**: Verifies the component's behavior when an organization image is available. + * 3. **Visit organization**: Simulates a click on the "manage" button and verifies that the user is redirected to the correct organization page. + * 4. **Send membership request**: Tests if the membership request is successfully sent and verifies the success toast message. + * 5. **Send membership request to a public organization**: Validates sending a membership request to a public organization and verifies multiple success toast messages. + * 6. **Withdraw membership request**: Simulates withdrawing a membership request and verifies that the button works as expected. + * + * Mocked GraphQL queries and mutations are used to simulate the backend behavior for testing. + */ const { getItem } = useLocalStorage(); -jest.mock('react-toastify', () => ({ +vi.mock('react-toastify', () => ({ toast: { - success: jest.fn(), - error: jest.fn(), + success: vi.fn(), + error: vi.fn(), }, })); @@ -146,6 +164,21 @@ const MOCKS = [ }, }, }, + { + request: { + query: CANCEL_MEMBERSHIP_REQUEST, + variables: { + membershipRequestId: '56gheqyr7deyfuiwfewifruy8', + }, + }, + result: { + data: { + cancelMembershipRequest: { + _id: '56gheqyr7deyfuiwfewifruy8', + }, + }, + }, + }, ]; const link = new StaticMockLink(MOCKS, true); @@ -189,7 +222,7 @@ let props = { }; describe('Testing OrganizationCard Component [User Portal]', () => { - test('Component should be rendered properly', async () => { + it('Component should be rendered properly', async () => { render( @@ -205,7 +238,7 @@ describe('Testing OrganizationCard Component [User Portal]', () => { await wait(); }); - test('Component should be rendered properly if organization Image is not undefined', async () => { + it('Component should be rendered properly if organization Image is not undefined', async () => { props = { ...props, image: 'organizationImage', @@ -226,7 +259,7 @@ describe('Testing OrganizationCard Component [User Portal]', () => { await wait(); }); - test('Visit organization', async () => { + it('Visit organization', async () => { const cardProps = { ...props, id: '3', @@ -258,7 +291,7 @@ describe('Testing OrganizationCard Component [User Portal]', () => { expect(window.location.pathname).toBe(`/user/organization/${cardProps.id}`); }); - test('Send membership request', async () => { + it('Send membership request', async () => { props = { ...props, image: 'organizationImage', @@ -286,7 +319,7 @@ describe('Testing OrganizationCard Component [User Portal]', () => { expect(toast.success).toHaveBeenCalledWith('MembershipRequestSent'); }); - test('send membership request to public org', async () => { + it('send membership request to public org', async () => { const cardProps = { ...props, id: '2', @@ -316,13 +349,21 @@ describe('Testing OrganizationCard Component [User Portal]', () => { expect(toast.success).toHaveBeenCalledTimes(2); }); - test('withdraw membership request', async () => { + it('withdraw membership request', async () => { const cardProps = { ...props, id: '3', image: 'organizationImage', userRegistrationRequired: true, membershipRequestStatus: 'pending', + membershipRequests: [ + { + _id: '56gheqyr7deyfuiwfewifruy8', + user: { + _id: getItem('userId'), + }, + }, + ], }; render( diff --git a/src/components/UserPortal/OrganizationNavbar/OrganizationNavbar.test.tsx b/src/components/UserPortal/OrganizationNavbar/OrganizationNavbar.spec.tsx similarity index 81% rename from src/components/UserPortal/OrganizationNavbar/OrganizationNavbar.test.tsx rename to src/components/UserPortal/OrganizationNavbar/OrganizationNavbar.spec.tsx index 038ff626df..7f9e8e52bb 100644 --- a/src/components/UserPortal/OrganizationNavbar/OrganizationNavbar.test.tsx +++ b/src/components/UserPortal/OrganizationNavbar/OrganizationNavbar.spec.tsx @@ -1,6 +1,5 @@ import React, { act } from 'react'; import { MockedProvider } from '@apollo/react-testing'; -import 'jest-localstorage-mock'; import { render, screen } from '@testing-library/react'; import { I18nextProvider } from 'react-i18next'; import { Provider } from 'react-redux'; @@ -17,6 +16,28 @@ import { PLUGIN_SUBSCRIPTION } from 'GraphQl/Mutations/mutations'; import { createMemoryHistory } from 'history'; import useLocalStorage from 'utils/useLocalstorage'; +import { vi } from 'vitest'; + +/** + * Unit tests for the OrganizationNavbar component. + * + * These tests validate the rendering and behavior of the component, ensuring it renders correctly, + * handles user interactions, and manages language and plugin updates. + * + * 1. **Component rendering**: Verifies correct rendering with provided props and organization details. + * 2. **Navigation on plugin click**: Simulates navigation when a plugin link is clicked. + * 3. **Language switch to English**: Tests if the language changes to English. + * 4. **Language switch to French**: Tests if the language changes to French. + * 5. **Language switch to Hindi**: Tests if the language changes to Hindi. + * 6. **Language switch to Spanish**: Tests if the language changes to Spanish. + * 7. **Language switch to Chinese**: Tests if the language changes to Chinese. + * 8. **Rendering plugins from localStorage**: Verifies correct rendering of plugins from localStorage. + * 9. **Plugin removal on uninstallation**: Ensures plugins are removed when uninstalled for the organization. + * 10. **Rendering plugins when not uninstalled**: Ensures plugins render if not uninstalled. + * 11. **No changes for unmatched plugin**: Ensures no changes when an unrecognized plugin update occurs. + * + * Mocked GraphQL queries and subscriptions simulate backend behavior. + */ const { setItem, removeItem } = useLocalStorage(); @@ -167,23 +188,26 @@ const navbarProps = { currentPage: 'home', }; -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useParams: () => ({ orgId: organizationId }), -})); +vi.mock('react-router-dom', async () => { + const actual = await vi.importActual('react-router-dom'); + return { + ...actual, + useParams: () => ({ orgId: organizationId }), + }; +}); describe('Testing OrganizationNavbar Component [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(), })), }); @@ -193,7 +217,7 @@ describe('Testing OrganizationNavbar Component [User Portal]', () => { }); }); - test('Component should be rendered properly', async () => { + it('Component should be rendered properly', async () => { render( @@ -217,7 +241,7 @@ describe('Testing OrganizationNavbar Component [User Portal]', () => { // expect(screen.getByText('Chat')).toBeInTheDocument(); }); - test('should navigate correctly on clicking a plugin', async () => { + it('should navigate correctly on clicking a plugin', async () => { const history = createMemoryHistory(); render( @@ -240,7 +264,7 @@ describe('Testing OrganizationNavbar Component [User Portal]', () => { expect(history.location.pathname).toBe(`/user/people/${organizationId}`); }); - test('The language is switched to English', async () => { + it('The language is switched to English', async () => { render( @@ -270,7 +294,7 @@ describe('Testing OrganizationNavbar Component [User Portal]', () => { // expect(screen.getByText('Chat')).toBeInTheDocument(); }); - test('The language is switched to fr', async () => { + it('The language is switched to fr', async () => { render( @@ -294,7 +318,7 @@ describe('Testing OrganizationNavbar Component [User Portal]', () => { expect(cookies.get('i18next')).toBe('fr'); }); - test('The language is switched to hi', async () => { + it('The language is switched to hi', async () => { render( @@ -318,7 +342,7 @@ describe('Testing OrganizationNavbar Component [User Portal]', () => { expect(cookies.get('i18next')).toBe('hi'); }); - test('The language is switched to sp', async () => { + it('The language is switched to sp', async () => { render( @@ -342,7 +366,7 @@ describe('Testing OrganizationNavbar Component [User Portal]', () => { expect(cookies.get('i18next')).toBe('sp'); }); - test('The language is switched to zh', async () => { + it('The language is switched to zh', async () => { render( @@ -366,7 +390,7 @@ describe('Testing OrganizationNavbar Component [User Portal]', () => { expect(cookies.get('i18next')).toBe('zh'); }); - test('Component should be rendered properly if plugins are present in localStorage', async () => { + it('Component should be rendered properly if plugins are present in localStorage', async () => { setItem('talawaPlugins', JSON.stringify(testPlugins)); render( @@ -390,7 +414,7 @@ describe('Testing OrganizationNavbar Component [User Portal]', () => { removeItem('talawaPlugins'); }); - test('should remove plugin if uninstalledOrgs contains organizationId', async () => { + it('should remove plugin if uninstalledOrgs contains organizationId', async () => { setItem('talawaPlugins', JSON.stringify(testPlugins)); render( @@ -412,7 +436,7 @@ describe('Testing OrganizationNavbar Component [User Portal]', () => { }); }); - test('should render plugin if uninstalledOrgs does not contain organizationId', async () => { + it('should render plugin if uninstalledOrgs does not contain organizationId', async () => { setItem('talawaPlugins', JSON.stringify(testPlugins)); render( @@ -434,7 +458,7 @@ describe('Testing OrganizationNavbar Component [User Portal]', () => { }); }); - test('should do nothing if pluginName is not found in the rendered plugins', async () => { + it('should do nothing if pluginName is not found in the rendered plugins', async () => { render( diff --git a/src/components/UserPortal/OrganizationSidebar/OrganizationSidebar.test.tsx b/src/components/UserPortal/OrganizationSidebar/OrganizationSidebar.spec.tsx similarity index 74% rename from src/components/UserPortal/OrganizationSidebar/OrganizationSidebar.test.tsx rename to src/components/UserPortal/OrganizationSidebar/OrganizationSidebar.spec.tsx index cddac285fd..2559eaae14 100644 --- a/src/components/UserPortal/OrganizationSidebar/OrganizationSidebar.test.tsx +++ b/src/components/UserPortal/OrganizationSidebar/OrganizationSidebar.spec.tsx @@ -13,6 +13,20 @@ import { store } from 'state/store'; import i18nForTest from 'utils/i18nForTest'; import { StaticMockLink } from 'utils/StaticMockLink'; import OrganizationSidebar from './OrganizationSidebar'; +import { vi } from 'vitest'; + +/** + * Unit tests for the OrganizationSidebar component in the User Portal. + * + * These tests validate the rendering and behavior of the OrganizationSidebar component, + * ensuring that it displays correct content based on the availability of members and events. + * + * 1. **Component renders properly when members and events lists are empty**: Verifies the correct display of "No Members to show" and "No Events to show" when both lists are empty. + * 2. **Component renders properly when events list is not empty**: Tests that the events section is rendered correctly when events are available, and "No Events to show" is not displayed. + * 3. **Component renders properly when members list is not empty**: Verifies the correct display of members when available, ensuring "No Members to show" is not displayed. + * + * Mocked GraphQL queries simulate backend responses for members and events lists. + */ const MOCKS = [ { @@ -94,13 +108,17 @@ async function wait(ms = 100): Promise { }); } let mockId = ''; -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useParams: () => ({ orgId: mockId }), -})); + +vi.mock('react-router-dom', async () => { + const actual = await vi.importActual('react-router-dom'); + return { + ...actual, + useParams: () => ({ orgId: mockId }), + }; +}); describe('Testing OrganizationSidebar Component [User Portal]', () => { - test('Component should be rendered properly when members and events list is empty', async () => { + it('Component should be rendered properly when members and events list is empty', async () => { render( @@ -119,7 +137,7 @@ describe('Testing OrganizationSidebar Component [User Portal]', () => { expect(screen.queryByText('No Events to show')).toBeInTheDocument(); }); - test('Component should be rendered properly when events list is not empty', async () => { + it('Component should be rendered properly when events list is not empty', async () => { mockId = 'events'; render( @@ -139,7 +157,7 @@ describe('Testing OrganizationSidebar Component [User Portal]', () => { expect(screen.queryByText('Event')).toBeInTheDocument(); }); - test('Component should be rendered properly when members list is not empty', async () => { + it('Component should be rendered properly when members list is not empty', async () => { mockId = 'members'; render( diff --git a/src/components/UserPortal/PeopleCard/PeopleCard.test.tsx b/src/components/UserPortal/PeopleCard/PeopleCard.spec.tsx similarity index 65% rename from src/components/UserPortal/PeopleCard/PeopleCard.test.tsx rename to src/components/UserPortal/PeopleCard/PeopleCard.spec.tsx index fd5d6c7f93..c725a8d45a 100644 --- a/src/components/UserPortal/PeopleCard/PeopleCard.test.tsx +++ b/src/components/UserPortal/PeopleCard/PeopleCard.spec.tsx @@ -10,6 +10,18 @@ import i18nForTest from 'utils/i18nForTest'; import { StaticMockLink } from 'utils/StaticMockLink'; import PeopleCard from './PeopleCard'; +/** + * Unit tests for the PeopleCard component in the User Portal. + * + * These tests ensure that the PeopleCard component renders correctly with and without an image, + * validating that all information (name, role, email, etc.) is displayed as expected. + * + * 1. **Component renders properly**: Verifies that the component renders correctly with the given props (name, email, role, etc.). + * 2. **Component renders properly if the person image is provided**: Ensures the component correctly displays the image when a valid image URL is passed in the props. + * + * Mocked GraphQL queries are used to simulate backend behavior, though no queries are required for these tests. + */ + const link = new StaticMockLink([], true); async function wait(ms = 100): Promise { @@ -30,7 +42,7 @@ let props = { }; describe('Testing PeopleCard Component [User Portal]', () => { - test('Component should be rendered properly', async () => { + it('Component should be rendered properly', async () => { render( @@ -46,7 +58,7 @@ describe('Testing PeopleCard Component [User Portal]', () => { await wait(); }); - test('Component should be rendered properly if person image is not undefined', async () => { + it('Component should be rendered properly if person image is not undefined', async () => { props = { ...props, image: 'personImage', diff --git a/src/components/UserPortal/PostCard/PostCard.test.tsx b/src/components/UserPortal/PostCard/PostCard.spec.tsx similarity index 90% rename from src/components/UserPortal/PostCard/PostCard.test.tsx rename to src/components/UserPortal/PostCard/PostCard.spec.tsx index 1b7708b384..fe3fcf3dc1 100644 --- a/src/components/UserPortal/PostCard/PostCard.test.tsx +++ b/src/components/UserPortal/PostCard/PostCard.spec.tsx @@ -21,14 +21,33 @@ import { UPDATE_POST_MUTATION, } from 'GraphQl/Mutations/mutations'; import useLocalStorage from 'utils/useLocalstorage'; +import { vi } from 'vitest'; + +/** + * Unit tests for the PostCard component in the User Portal. + * + * These tests ensure the PostCard component behaves as expected: + * + * 1. **Component rendering**: Verifies correct rendering with props like title, text, and creator info. + * 2. **Dropdown functionality**: Tests the dropdown for editing and deleting posts. + * 3. **Edit post**: Ensures the post can be edited with a success message. + * 4. **Delete post**: Verifies post deletion works with a success message. + * 5. **Like/unlike post**: Ensures the UI updates when a user likes or unlikes a post. + * 6. **Post image**: Verifies post image rendering. + * 7. **Create comment**: Ensures a comment is created successfully. + * 8. **Like/unlike comment**: Tests liking/unliking comments. + * 9. **Comment modal**: Verifies the comment modal appears when clicked. + * + * Mocked GraphQL data is used for simulating backend behavior. + */ const { setItem, getItem } = useLocalStorage(); -jest.mock('react-toastify', () => ({ +vi.mock('react-toastify', () => ({ toast: { - error: jest.fn(), - info: jest.fn(), - success: jest.fn(), + error: vi.fn(), + info: vi.fn(), + success: vi.fn(), }, })); @@ -164,7 +183,7 @@ async function wait(ms = 100): Promise { const link = new StaticMockLink(MOCKS, true); describe('Testing PostCard Component [User Portal]', () => { - test('Component should be rendered properly', async () => { + it('Component should be rendered properly', async () => { const cardProps = { id: 'postId', userImage: 'image.png', @@ -218,7 +237,7 @@ describe('Testing PostCard Component [User Portal]', () => { id: '2', }, ], - fetchPosts: jest.fn(), + fetchPosts: vi.fn(), }; render( @@ -236,7 +255,7 @@ describe('Testing PostCard Component [User Portal]', () => { await wait(); }); - test('Dropdown component should be rendered properly', async () => { + it('Dropdown component should be rendered properly', async () => { setItem('userId', '2'); const cardProps = { @@ -263,7 +282,7 @@ describe('Testing PostCard Component [User Portal]', () => { id: '2', }, ], - fetchPosts: jest.fn(), + fetchPosts: vi.fn(), }; render( @@ -285,7 +304,7 @@ describe('Testing PostCard Component [User Portal]', () => { expect(screen.getByText('Delete')).toBeInTheDocument(); }); - test('Edit post should work properly', async () => { + it('Edit post should work properly', async () => { setItem('userId', '2'); const cardProps = { @@ -312,7 +331,7 @@ describe('Testing PostCard Component [User Portal]', () => { id: '2', }, ], - fetchPosts: jest.fn(), + fetchPosts: vi.fn(), }; render( @@ -341,7 +360,7 @@ describe('Testing PostCard Component [User Portal]', () => { expect(toast.success).toHaveBeenCalledWith('Post updated Successfully'); }); - test('Delete post should work properly', async () => { + it('Delete post should work properly', async () => { setItem('userId', '2'); const cardProps = { @@ -368,7 +387,7 @@ describe('Testing PostCard Component [User Portal]', () => { id: '2', }, ], - fetchPosts: jest.fn(), + fetchPosts: vi.fn(), }; render( @@ -393,7 +412,7 @@ describe('Testing PostCard Component [User Portal]', () => { ); }); - test('Component should be rendered properly if user has liked the post', async () => { + it('Component should be rendered properly if user has liked the post', async () => { const beforeUserId = getItem('userId'); setItem('userId', '2'); @@ -421,7 +440,7 @@ describe('Testing PostCard Component [User Portal]', () => { id: '2', }, ], - fetchPosts: jest.fn(), + fetchPosts: vi.fn(), }; render( @@ -443,7 +462,7 @@ describe('Testing PostCard Component [User Portal]', () => { } }); - test('Component should be rendered properly if user unlikes a post', async () => { + it('Component should be rendered properly if user unlikes a post', async () => { const beforeUserId = getItem('userId'); setItem('userId', '2'); @@ -471,7 +490,7 @@ describe('Testing PostCard Component [User Portal]', () => { id: '2', }, ], - fetchPosts: jest.fn(), + fetchPosts: vi.fn(), }; render( @@ -496,7 +515,7 @@ describe('Testing PostCard Component [User Portal]', () => { } }); - test('Component should be rendered properly if user likes a post', async () => { + it('Component should be rendered properly if user likes a post', async () => { const beforeUserId = getItem('userId'); setItem('userId', '2'); @@ -524,7 +543,7 @@ describe('Testing PostCard Component [User Portal]', () => { id: '1', }, ], - fetchPosts: jest.fn(), + fetchPosts: vi.fn(), }; render( @@ -549,7 +568,7 @@ describe('Testing PostCard Component [User Portal]', () => { } }); - test('Component should be rendered properly if post image is defined', async () => { + it('Component should be rendered properly if post image is defined', async () => { const cardProps = { id: '', userImage: 'image.png', @@ -574,7 +593,7 @@ describe('Testing PostCard Component [User Portal]', () => { id: '1', }, ], - fetchPosts: jest.fn(), + fetchPosts: vi.fn(), }; render( @@ -592,7 +611,7 @@ describe('Testing PostCard Component [User Portal]', () => { await wait(); }); - test('Comment is created successfully after create comment button is clicked.', async () => { + it('Comment is created successfully after create comment button is clicked.', async () => { const cardProps = { id: '1', userImage: 'image.png', @@ -617,7 +636,7 @@ describe('Testing PostCard Component [User Portal]', () => { id: '1', }, ], - fetchPosts: jest.fn(), + fetchPosts: vi.fn(), }; render( @@ -701,7 +720,7 @@ describe('Testing PostCard Component [User Portal]', () => { id: '1', }, ], - fetchPosts: jest.fn(), + fetchPosts: vi.fn(), }; const beforeUserId = getItem('userId'); setItem('userId', '2'); @@ -788,7 +807,7 @@ describe('Testing PostCard Component [User Portal]', () => { id: '1', }, ], - fetchPosts: jest.fn(), + fetchPosts: vi.fn(), }; const beforeUserId = getItem('userId'); setItem('userId', '1'); @@ -815,7 +834,7 @@ describe('Testing PostCard Component [User Portal]', () => { setItem('userId', beforeUserId); } }); - test('Comment modal pops when show comments button is clicked.', async () => { + it('Comment modal pops when show comments button is clicked.', async () => { const cardProps = { id: '', userImage: 'image.png', @@ -840,7 +859,7 @@ describe('Testing PostCard Component [User Portal]', () => { id: '1', }, ], - fetchPosts: jest.fn(), + fetchPosts: vi.fn(), }; render( diff --git a/src/components/UserPortal/PromotedPost/PromotedPost.test.tsx b/src/components/UserPortal/PromotedPost/PromotedPost.spec.tsx similarity index 77% rename from src/components/UserPortal/PromotedPost/PromotedPost.test.tsx rename to src/components/UserPortal/PromotedPost/PromotedPost.spec.tsx index 6ec8ec5de7..dc8bb14e2d 100644 --- a/src/components/UserPortal/PromotedPost/PromotedPost.test.tsx +++ b/src/components/UserPortal/PromotedPost/PromotedPost.spec.tsx @@ -10,6 +10,18 @@ import i18nForTest from 'utils/i18nForTest'; import { StaticMockLink } from 'utils/StaticMockLink'; import PromotedPost from './PromotedPost'; +/** + * Unit tests for the PromotedPost component. + * + * 1. **Render check**: Verifies the component renders correctly with props like title and image. + * 2. **Image prop check**: Tests if the component renders correctly with an image. + * 3. **Icon display**: Ensures the icon (StarPurple500Icon) is displayed. + * 4. **Text display**: Checks that the post title is displayed correctly. + * 5. **Image display**: Verifies the correct image is displayed when the image prop is set. + * + * GraphQL data is mocked for backend simulation. + */ + const link = new StaticMockLink([], true); async function wait(ms = 100): Promise { @@ -27,7 +39,7 @@ let props = { }; describe('Testing PromotedPost Test', () => { - test('Component should be rendered properly', async () => { + it('Component should be rendered properly', async () => { render( @@ -43,7 +55,7 @@ describe('Testing PromotedPost Test', () => { await wait(); }); - test('Component should be rendered properly if prop image is not undefined', async () => { + it('Component should be rendered properly if prop image is not undefined', async () => { props = { ...props, image: 'promotedPostImage', @@ -65,7 +77,7 @@ describe('Testing PromotedPost Test', () => { }); }); -test('Component should display the icon correctly', async () => { +it('Component should display the icon correctly', async () => { const { queryByTestId } = render( @@ -84,7 +96,7 @@ test('Component should display the icon correctly', async () => { }); }); -test('Component should display the text correctly', async () => { +it('Component should display the text correctly', async () => { const { queryAllByText } = render( @@ -103,7 +115,7 @@ test('Component should display the text correctly', async () => { }); }); -test('Component should display the image correctly', async () => { +it('Component should display the image correctly', async () => { props = { ...props, image: 'promotedPostImage', diff --git a/src/components/UserPortal/Register/Register.test.tsx b/src/components/UserPortal/Register/Register.spec.tsx similarity index 80% rename from src/components/UserPortal/Register/Register.test.tsx rename to src/components/UserPortal/Register/Register.spec.tsx index 1883d60da3..7ca65f8f0d 100644 --- a/src/components/UserPortal/Register/Register.test.tsx +++ b/src/components/UserPortal/Register/Register.spec.tsx @@ -12,6 +12,22 @@ import i18nForTest from 'utils/i18nForTest'; import { StaticMockLink } from 'utils/StaticMockLink'; import Register from './Register'; import { toast } from 'react-toastify'; +import { vi } from 'vitest'; + +/** + * Unit tests for the Register component. + * + * 1. **Render test**: Verifies proper rendering of the Register component. + * 2. **Mode switch to Login**: Ensures that clicking the "setLoginBtn" changes mode to 'login'. + * 3. **Empty email validation**: Checks if toast.error is triggered for empty email. + * 4. **Empty password validation**: Ensures toast.error is called for empty password. + * 5. **Empty first name validation**: Ensures toast.error is called if first name is missing. + * 6. **Empty last name validation**: Verifies toast.error is triggered if last name is missing. + * 7. **Password mismatch validation**: Verifies toast.error is shown if confirm password doesn't match. + * 8. **Successful registration**: Confirms that toast.success is called when valid credentials are entered. + * + * GraphQL mock data is used for testing user registration functionality. + */ const MOCKS = [ { @@ -56,22 +72,22 @@ async function wait(ms = 100): Promise { }); } -jest.mock('react-toastify', () => ({ +vi.mock('react-toastify', () => ({ toast: { - success: jest.fn(), - warn: jest.fn(), - error: jest.fn(), + success: vi.fn(), + warn: vi.fn(), + error: vi.fn(), }, })); -const setCurrentMode: React.Dispatch> = jest.fn(); +const setCurrentMode: React.Dispatch> = vi.fn(); const props = { setCurrentMode, }; describe('Testing Register Component [User Portal]', () => { - test('Component should be rendered properly', async () => { + it('Component should be rendered properly', async () => { render( @@ -87,7 +103,7 @@ describe('Testing Register Component [User Portal]', () => { await wait(); }); - test('Expect the mode to be changed to Login', async () => { + it('Expect the mode to be changed to Login', async () => { render( @@ -107,7 +123,7 @@ describe('Testing Register Component [User Portal]', () => { expect(setCurrentMode).toHaveBeenCalledWith('login'); }); - test('Expect toast.error to be called if email input is empty', async () => { + it('Expect toast.error to be called if email input is empty', async () => { render( @@ -127,7 +143,7 @@ describe('Testing Register Component [User Portal]', () => { expect(toast.error).toHaveBeenCalledWith('Please enter valid details.'); }); - test('Expect toast.error to be called if password input is empty', async () => { + it('Expect toast.error to be called if password input is empty', async () => { render( @@ -148,7 +164,7 @@ describe('Testing Register Component [User Portal]', () => { expect(toast.error).toHaveBeenCalledWith('Please enter valid details.'); }); - test('Expect toast.error to be called if first name input is empty', async () => { + it('Expect toast.error to be called if first name input is empty', async () => { render( @@ -172,7 +188,7 @@ describe('Testing Register Component [User Portal]', () => { expect(toast.error).toHaveBeenCalledWith('Please enter valid details.'); }); - test('Expect toast.error to be called if last name input is empty', async () => { + it('Expect toast.error to be called if last name input is empty', async () => { render( @@ -228,7 +244,7 @@ describe('Testing Register Component [User Portal]', () => { ); }); - test('Expect toast.success to be called if valid credentials are entered.', async () => { + it('Expect toast.success to be called if valid credentials are entered.', async () => { render( diff --git a/src/components/UserPortal/SecuredRouteForUser/SecuredRouteForUser.test.tsx b/src/components/UserPortal/SecuredRouteForUser/SecuredRouteForUser.spec.tsx similarity index 77% rename from src/components/UserPortal/SecuredRouteForUser/SecuredRouteForUser.test.tsx rename to src/components/UserPortal/SecuredRouteForUser/SecuredRouteForUser.spec.tsx index 93b71b14f1..98459b930a 100644 --- a/src/components/UserPortal/SecuredRouteForUser/SecuredRouteForUser.test.tsx +++ b/src/components/UserPortal/SecuredRouteForUser/SecuredRouteForUser.spec.tsx @@ -4,10 +4,20 @@ import { render, screen, waitFor } from '@testing-library/react'; import SecuredRouteForUser from './SecuredRouteForUser'; import useLocalStorage from 'utils/useLocalstorage'; +/** + * Unit tests for SecuredRouteForUser component: + * + * 1. **Logged-in user**: Verifies that the route renders when 'IsLoggedIn' is set to 'TRUE'. + * 2. **Not logged-in user**: Ensures redirection to the login page when 'IsLoggedIn' is 'FALSE'. + * 3. **Logged-in user with admin access**: Checks that the route renders for a logged-in user with 'AdminFor' set (i.e., admin of an organization). + * + * LocalStorage values like 'IsLoggedIn' and 'AdminFor' are set to simulate different user states. + */ + const { setItem } = useLocalStorage(); describe('SecuredRouteForUser', () => { - test('renders the route when the user is logged in', () => { + it('renders the route when the user is logged in', () => { // Set the 'IsLoggedIn' value to 'TRUE' in localStorage to simulate a logged-in user and do not set 'AdminFor' so that it remains undefined. setItem('IsLoggedIn', 'TRUE'); @@ -31,7 +41,7 @@ describe('SecuredRouteForUser', () => { expect(screen.getByTestId('organizations-content')).toBeInTheDocument(); }); - test('redirects to /user when the user is not logged in', async () => { + it('redirects to /user when the user is not logged in', async () => { // Set the user as not logged in in local storage setItem('IsLoggedIn', 'FALSE'); @@ -58,7 +68,7 @@ describe('SecuredRouteForUser', () => { }); }); - test('renders the route when the user is logged in and user is ADMIN', () => { + it('renders the route when the user is logged in and user is ADMIN', () => { // Set the 'IsLoggedIn' value to 'TRUE' in localStorage to simulate a logged-in user and set 'AdminFor' to simulate ADMIN of some Organization. setItem('IsLoggedIn', 'TRUE'); setItem('AdminFor', [ diff --git a/src/components/UserPortal/StartPostModal/StartPostModal.test.tsx b/src/components/UserPortal/StartPostModal/StartPostModal.spec.tsx similarity index 71% rename from src/components/UserPortal/StartPostModal/StartPostModal.test.tsx rename to src/components/UserPortal/StartPostModal/StartPostModal.spec.tsx index c34f3a2e9e..2d9024bcd3 100644 --- a/src/components/UserPortal/StartPostModal/StartPostModal.test.tsx +++ b/src/components/UserPortal/StartPostModal/StartPostModal.spec.tsx @@ -12,12 +12,26 @@ import { store } from 'state/store'; import { StaticMockLink } from 'utils/StaticMockLink'; import i18nForTest from 'utils/i18nForTest'; import StartPostModal from './StartPostModal'; - -jest.mock('react-toastify', () => ({ +import { vi } from 'vitest'; + +/** + * Unit tests for StartPostModal component: + * + * 1. **Rendering StartPostModal**: Verifies that the modal renders correctly when the `show` prop is set to `true`. + * 2. **Invalid post submission**: Ensures that when the post body is empty, an error toast is shown with the appropriate message ("Can't create a post with an empty body"). + * 3. **Valid post submission**: Checks that a post with valid text triggers an info toast, and simulates the creation of a post with the message "Processing your post. Please wait." + * 4. **User image null**: Confirms that when the user image is null, a default image is displayed instead. + * 5. **User image not null**: Verifies that when the user image is provided, the correct user image is shown. + * + * Mocked GraphQL mutation (`CREATE_POST_MUTATION`) and toast notifications are used to simulate the post creation process. + * The `renderStartPostModal` function is used to render the modal with different user states and input values. + */ + +vi.mock('react-toastify', () => ({ toast: { - error: jest.fn(), - info: jest.fn(), - success: jest.fn(), + error: vi.fn(), + info: vi.fn(), + success: vi.fn(), }, })); @@ -62,8 +76,8 @@ const renderStartPostModal = ( ): RenderResult => { const cardProps = { show: visibility, - onHide: jest.fn(), - fetchPosts: jest.fn(), + onHide: vi.fn(), + fetchPosts: vi.fn(), userData: { user: { __typename: 'User', @@ -113,18 +127,18 @@ const renderStartPostModal = ( describe('Testing StartPostModal Component: User Portal', () => { afterAll(() => { - jest.clearAllMocks(); + vi.clearAllMocks(); }); - test('Check if StartPostModal renders properly', async () => { + it('Check if StartPostModal renders properly', async () => { renderStartPostModal(true, null); const modal = await screen.findByTestId('startPostModal'); expect(modal).toBeInTheDocument(); }); - test('On invalid post submission with empty body Error toast should be shown', async () => { - const toastSpy = jest.spyOn(toast, 'error'); + it('On invalid post submission with empty body Error toast should be shown', async () => { + const toastSpy = vi.spyOn(toast, 'error'); renderStartPostModal(true, null); await wait(); @@ -134,7 +148,7 @@ describe('Testing StartPostModal Component: User Portal', () => { ); }); - test('On valid post submission Info toast should be shown', async () => { + it('On valid post submission Info toast should be shown', async () => { renderStartPostModal(true, null); await wait(); @@ -154,7 +168,7 @@ describe('Testing StartPostModal Component: User Portal', () => { // ); }); - test('If user image is null then default image should be shown', async () => { + it('If user image is null then default image should be shown', async () => { renderStartPostModal(true, null); await wait(); @@ -165,7 +179,7 @@ describe('Testing StartPostModal Component: User Portal', () => { ); }); - test('If user image is not null then user image should be shown', async () => { + it('If user image is not null then user image should be shown', async () => { renderStartPostModal(true, 'image.png'); await wait(); diff --git a/src/components/UserPortal/UserNavbar/UserNavbar.test.tsx b/src/components/UserPortal/UserNavbar/UserNavbar.spec.tsx similarity index 74% rename from src/components/UserPortal/UserNavbar/UserNavbar.test.tsx rename to src/components/UserPortal/UserNavbar/UserNavbar.spec.tsx index 8c3447f25a..6173871dbb 100644 --- a/src/components/UserPortal/UserNavbar/UserNavbar.test.tsx +++ b/src/components/UserPortal/UserNavbar/UserNavbar.spec.tsx @@ -13,6 +13,22 @@ import UserNavbar from './UserNavbar'; import userEvent from '@testing-library/user-event'; import { REVOKE_REFRESH_TOKEN } from 'GraphQl/Mutations/mutations'; +/** + * Unit tests for UserNavbar component [User Portal]: + * + * 1. **Rendering UserNavbar**: Verifies that the `UserNavbar` component renders correctly. + * 2. **Switching language to English**: Ensures that clicking the language dropdown and selecting 'English' updates the language cookie to 'en'. + * 3. **Switching language to French**: Verifies that selecting 'French' updates the language cookie to 'fr'. + * 4. **Switching language to Hindi**: Confirms that choosing 'Hindi' updates the language cookie to 'hi'. + * 5. **Switching language to Spanish**: Ensures that selecting 'Spanish' sets the language cookie to 'sp'. + * 6. **Switching language to Chinese**: Verifies that selecting 'Chinese' changes the language cookie to 'zh'. + * 7. **Interacting with the dropdown menu**: Ensures the user can open the dropdown and see available options like 'Settings' and 'Logout'. + * 8. **Navigating to the 'Settings' page**: Confirms that clicking 'Settings' in the dropdown correctly navigates the user to the "/user/settings" page. + * + * The tests simulate interactions with the language dropdown and the user dropdown menu to ensure proper functionality of language switching and navigation. + * Mocked GraphQL mutation (`REVOKE_REFRESH_TOKEN`) and mock store are used to test the component in an isolated environment. + */ + async function wait(ms = 100): Promise { await act(() => { return new Promise((resolve) => { @@ -39,7 +55,7 @@ describe('Testing UserNavbar Component [User Portal]', () => { }); }); - test('Component should be rendered properly', async () => { + it('Component should be rendered properly', async () => { render( @@ -55,7 +71,7 @@ describe('Testing UserNavbar Component [User Portal]', () => { await wait(); }); - test('The language is switched to English', async () => { + it('The language is switched to English', async () => { render( @@ -79,7 +95,7 @@ describe('Testing UserNavbar Component [User Portal]', () => { expect(cookies.get('i18next')).toBe('en'); }); - test('The language is switched to fr', async () => { + it('The language is switched to fr', async () => { render( @@ -103,7 +119,7 @@ describe('Testing UserNavbar Component [User Portal]', () => { expect(cookies.get('i18next')).toBe('fr'); }); - test('The language is switched to hi', async () => { + it('The language is switched to hi', async () => { render( @@ -127,7 +143,7 @@ describe('Testing UserNavbar Component [User Portal]', () => { expect(cookies.get('i18next')).toBe('hi'); }); - test('The language is switched to sp', async () => { + it('The language is switched to sp', async () => { render( @@ -151,7 +167,7 @@ describe('Testing UserNavbar Component [User Portal]', () => { expect(cookies.get('i18next')).toBe('sp'); }); - test('The language is switched to zh', async () => { + it('The language is switched to zh', async () => { render( @@ -175,7 +191,7 @@ describe('Testing UserNavbar Component [User Portal]', () => { expect(cookies.get('i18next')).toBe('zh'); }); - test('User can see and interact with the dropdown menu', async () => { + it('User can see and interact with the dropdown menu', async () => { render( @@ -195,7 +211,7 @@ describe('Testing UserNavbar Component [User Portal]', () => { expect(screen.getByTestId('logoutBtn')).toBeInTheDocument(); }); - test('User can navigate to the "Settings" page', async () => { + it('User can navigate to the "Settings" page', async () => { render( diff --git a/src/components/UserPortal/UserProfile/EventsAttendedByUser.test.tsx b/src/components/UserPortal/UserProfile/EventsAttendedByUser.spec.tsx similarity index 76% rename from src/components/UserPortal/UserProfile/EventsAttendedByUser.test.tsx rename to src/components/UserPortal/UserProfile/EventsAttendedByUser.spec.tsx index 82b173e399..dfdeb5523e 100644 --- a/src/components/UserPortal/UserProfile/EventsAttendedByUser.test.tsx +++ b/src/components/UserPortal/UserProfile/EventsAttendedByUser.spec.tsx @@ -4,6 +4,18 @@ import { EventsAttendedByUser } from './EventsAttendedByUser'; import { MockedProvider } from '@apollo/client/testing'; import { EVENT_DETAILS } from 'GraphQl/Queries/Queries'; +/** + * Unit tests for EventsAttendedByUser component: + * + * 1. **Rendering with events**: Verifies that the component renders properly when the user has attended events. + * - It checks for the presence of a title ('eventAttended') and ensures the correct number of event cards are rendered (2 events in this case). + * 2. **Rendering without events**: Ensures that when the user has not attended any events, a message indicating no events attended is displayed. + * - It checks for the presence of a 'noeventsAttended' message and ensures no event cards are rendered. + * + * Mock GraphQL queries (using `MockedProvider`) simulate the fetching of event details. + * The tests check the proper handling of different user event attendance scenarios. + */ + const mockT = (key: string, params?: Record): string => { if (params) { return Object.entries(params).reduce( @@ -96,7 +108,7 @@ describe('EventsAttendedByUser Component', () => { t: mockT, }; - test('renders the component with events', () => { + it('renders the component with events', () => { render( @@ -107,7 +119,7 @@ describe('EventsAttendedByUser Component', () => { expect(screen.getAllByTestId('usereventsCard')).toHaveLength(2); }); - test('renders no events message when user has no events', () => { + it('renders no events message when user has no events', () => { render( diff --git a/src/components/UserPortal/UserProfile/UserAddressFields.test.tsx b/src/components/UserPortal/UserProfile/UserAddressFields.spec.tsx similarity index 69% rename from src/components/UserPortal/UserProfile/UserAddressFields.test.tsx rename to src/components/UserPortal/UserProfile/UserAddressFields.spec.tsx index 7aff734bc6..9c0a6609e4 100644 --- a/src/components/UserPortal/UserProfile/UserAddressFields.test.tsx +++ b/src/components/UserPortal/UserProfile/UserAddressFields.spec.tsx @@ -2,12 +2,25 @@ import React from 'react'; import { render, screen, fireEvent } from '@testing-library/react'; import { UserAddressFields } from './UserAddressFields'; import { countryOptions } from 'utils/formEnumFields'; +import { vi } from 'vitest'; + +/** + * Unit tests for UserAddressFields component: + * + * 1. **Rendering form fields**: Ensures address, state, and country fields are rendered. + * 2. **Displaying translated labels**: Verifies correct translations for labels. + * 3. **Handling input changes**: Tests if `handleFieldChange` is called with correct values for address, state, and country. + * 4. **Rendering country options**: Checks if all country options are displayed. + * 5. **Displaying initial values**: Ensures initial values (address, state, country) are correctly shown. + * + * `fireEvent` simulates user actions, and `vi.fn()` mocks callback functions. + */ describe('UserAddressFields', () => { const mockProps = { tCommon: (key: string) => `translated_${key}`, t: (key: string) => `translated_${key}`, - handleFieldChange: jest.fn(), + handleFieldChange: vi.fn(), userDetails: { address: '123 Test Street', state: 'Test State', @@ -16,10 +29,10 @@ describe('UserAddressFields', () => { }; beforeEach(() => { - jest.clearAllMocks(); + vi.clearAllMocks(); }); - test('renders all form fields correctly', () => { + it('renders all form fields correctly', () => { render(); expect(screen.getByTestId('inputAddress')).toBeInTheDocument(); @@ -27,7 +40,7 @@ describe('UserAddressFields', () => { expect(screen.getByTestId('inputCountry')).toBeInTheDocument(); }); - test('displays correct labels with translations', () => { + it('displays correct labels with translations', () => { render(); expect(screen.getByText('translated_address')).toBeInTheDocument(); @@ -35,7 +48,7 @@ describe('UserAddressFields', () => { expect(screen.getByText('translated_country')).toBeInTheDocument(); }); - test('handles address input change', () => { + it('handles address input change', () => { render(); const addressInput = screen.getByTestId('inputAddress'); @@ -47,7 +60,7 @@ describe('UserAddressFields', () => { ); }); - test('handles state input change', () => { + it('handles state input change', () => { render(); const stateInput = screen.getByTestId('inputState'); @@ -59,7 +72,7 @@ describe('UserAddressFields', () => { ); }); - test('handles country selection change', () => { + it('handles country selection change', () => { render(); const countrySelect = screen.getByTestId('inputCountry'); @@ -68,7 +81,7 @@ describe('UserAddressFields', () => { expect(mockProps.handleFieldChange).toHaveBeenCalledWith('country', 'CA'); }); - test('renders all country options', () => { + it('renders all country options', () => { render(); const countrySelect = screen.getByTestId('inputCountry'); @@ -77,7 +90,7 @@ describe('UserAddressFields', () => { expect(options.length).toBe(countryOptions.length + 1); // +1 for disabled option }); - test('displays initial values correctly', () => { + it('displays initial values correctly', () => { render(); expect(screen.getByTestId('inputAddress')).toHaveValue('123 Test Street'); diff --git a/src/components/UserPortal/UserSidebar/UserSidebar.test.tsx b/src/components/UserPortal/UserSidebar/UserSidebar.spec.tsx similarity index 86% rename from src/components/UserPortal/UserSidebar/UserSidebar.test.tsx rename to src/components/UserPortal/UserSidebar/UserSidebar.spec.tsx index 79d603614f..ac6465a3e6 100644 --- a/src/components/UserPortal/UserSidebar/UserSidebar.test.tsx +++ b/src/components/UserPortal/UserSidebar/UserSidebar.spec.tsx @@ -15,6 +15,25 @@ import i18nForTest from 'utils/i18nForTest'; import { StaticMockLink } from 'utils/StaticMockLink'; import UserSidebar from './UserSidebar'; import useLocalStorage from 'utils/useLocalstorage'; +import { vi } from 'vitest'; + +/** + * Unit tests for UserSidebar component: + * + * 1. **Rendering with user data**: Verifies correct rendering when user data is fetched. + * 2. **Logo and title**: Ensures logo, title, and left drawer are visible. + * 3. **Empty organizations list**: Tests rendering when the user has no joined organizations. + * 4. **Organization image rendering**: Verifies rendering when organizations have an image. + * 5. **User profile and links**: Ensures user details and links like 'My Organizations' and 'Settings' are visible. + * 6. **Responsive rendering**: Tests correct rendering and drawer toggle on smaller screens. + * 7. **Active button style**: Verifies button style changes when clicked. + * 8. **Translation display**: Ensures translated text is shown. + * 9. **Sidebar closure on mobile**: Verifies sidebar closes when a link is clicked on mobile view. + * 10. **Drawer visibility on small screens**: Tests drawer visibility toggle based on `hideDrawer` prop. + * 11. **Drawer state change**: Verifies drawer visibility changes when `hideDrawer` prop changes. + * + * `fireEvent` simulates user actions, and `vi.fn()` mocks callback functions. + */ const { setItem } = useLocalStorage(); @@ -27,7 +46,7 @@ const resizeWindow = (width: number): void => { const props = { hideDrawer: true, - setHideDrawer: jest.fn(), + setHideDrawer: vi.fn(), }; const MOCKS = [ @@ -365,10 +384,10 @@ const renderUserSidebar = ( describe('UserSidebar Component Tests in User Portal', () => { beforeEach(() => { - jest.clearAllMocks(); + vi.clearAllMocks(); }); - test('UserSidebar component renders correctly with user data present', async () => { + it('UserSidebar component renders correctly with user data present', async () => { await act(async () => { renderUserSidebar('properId', link); await wait(); @@ -376,7 +395,7 @@ describe('UserSidebar Component Tests in User Portal', () => { expect(screen.getByText('Talawa User Portal')).toBeInTheDocument(); }); - test('Displays the logo and title text of the User Portal', async () => { + it('Displays the logo and title text of the User Portal', async () => { await act(async () => { renderUserSidebar('properId', link); await wait(); @@ -385,7 +404,7 @@ describe('UserSidebar Component Tests in User Portal', () => { expect(screen.getByTestId('leftDrawerContainer')).toBeVisible(); }); - test('UserSidebar renders correctly when joinedOrganizations list is empty', async () => { + it('UserSidebar renders correctly when joinedOrganizations list is empty', async () => { await act(async () => { renderUserSidebar('orgEmpty', link); await wait(); @@ -393,7 +412,7 @@ describe('UserSidebar Component Tests in User Portal', () => { expect(screen.getByText('My Organizations')).toBeInTheDocument(); }); - test('Renders UserSidebar component with organization image when present', async () => { + it('Renders UserSidebar component with organization image when present', async () => { await act(async () => { renderUserSidebar('imagePresent', link); await wait(); @@ -401,7 +420,7 @@ describe('UserSidebar Component Tests in User Portal', () => { expect(screen.getByText('Settings')).toBeInTheDocument(); }); - test('User profile data renders with all expected navigation links visible', async () => { + it('User profile data renders with all expected navigation links visible', async () => { await act(async () => { renderUserSidebar('properId', link); await wait(); @@ -413,7 +432,7 @@ describe('UserSidebar Component Tests in User Portal', () => { }); }); - test('UserSidebar renders correctly on smaller screens and toggles drawer visibility', async () => { + it('UserSidebar renders correctly on smaller screens and toggles drawer visibility', async () => { await act(async () => { resizeWindow(800); render( @@ -433,7 +452,7 @@ describe('UserSidebar Component Tests in User Portal', () => { expect(props.setHideDrawer).toHaveBeenCalledWith(true); }); - test('Active route button style changes correctly upon click', async () => { + it('Active route button style changes correctly upon click', async () => { await act(async () => { renderUserSidebar('properId', link); await wait(); @@ -448,7 +467,7 @@ describe('UserSidebar Component Tests in User Portal', () => { expect(settingsBtn).toHaveClass('text-white btn btn-success'); }); - test('Translation hook displays expected text in UserSidebar', async () => { + it('Translation hook displays expected text in UserSidebar', async () => { await act(async () => { renderUserSidebar('properId', link); await wait(); @@ -458,7 +477,7 @@ describe('UserSidebar Component Tests in User Portal', () => { ).toBeInTheDocument(); }); - test('handleLinkClick function closes the sidebar on mobile view when a link is clicked', async () => { + it('handleLinkClick function closes the sidebar on mobile view when a link is clicked', async () => { resizeWindow(800); await act(async () => { renderUserSidebar('properId', link); @@ -471,10 +490,10 @@ describe('UserSidebar Component Tests in User Portal', () => { describe('UserSidebar Drawer Visibility Tests on Smaller Screens', () => { beforeEach(() => { - jest.clearAllMocks(); + vi.clearAllMocks(); }); - test('Clicking a link closes the drawer when window width is 820px or less', () => { + it('Clicking a link closes the drawer when window width is 820px or less', () => { act(() => { window.innerWidth = 820; window.dispatchEvent(new Event('resize')); @@ -499,7 +518,7 @@ describe('UserSidebar Component Tests in User Portal', () => { }); describe('UserSidebar Drawer State Tests', () => { - test('Drawer visibility changes based on hideDrawer prop', () => { + it('Drawer visibility changes based on hideDrawer prop', () => { const { rerender } = render( diff --git a/src/components/UserPortal/UserSidebarOrg/UserSidebarOrg.test.tsx b/src/components/UserPortal/UserSidebarOrg/UserSidebarOrg.spec.tsx similarity index 86% rename from src/components/UserPortal/UserSidebarOrg/UserSidebarOrg.test.tsx rename to src/components/UserPortal/UserSidebarOrg/UserSidebarOrg.spec.tsx index 2f28d9afd1..f26997f572 100644 --- a/src/components/UserPortal/UserSidebarOrg/UserSidebarOrg.test.tsx +++ b/src/components/UserPortal/UserSidebarOrg/UserSidebarOrg.spec.tsx @@ -1,10 +1,8 @@ import React, { act } from 'react'; import { fireEvent, render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; -import 'jest-localstorage-mock'; import { I18nextProvider } from 'react-i18next'; import { BrowserRouter } from 'react-router-dom'; - import i18nForTest from 'utils/i18nForTest'; import type { InterfaceUserSidebarOrgProps } from './UserSidebarOrg'; import UserSidebarOrg from './UserSidebarOrg'; @@ -15,7 +13,24 @@ import { ORGANIZATIONS_LIST } from 'GraphQl/Queries/Queries'; import { StaticMockLink } from 'utils/StaticMockLink'; import { REVOKE_REFRESH_TOKEN } from 'GraphQl/Mutations/mutations'; import useLocalStorage from 'utils/useLocalstorage'; +import { vi } from 'vitest'; +/** + * Unit tests for UserSidebarOrg component: + * + * 1. **Rendering with organization data**: Verifies correct rendering when data is fetched. + * 2. **Profile Page & Modal**: Ensures profile button and organization details modal appear. + * 3. **Menu Navigation**: Tests correct navigation when menu buttons like 'People' are clicked. + * 4. **Responsive Design**: Verifies sidebar behavior on screens. + * 5. **Organization Image**: Ensures correct rendering of organization image. + * 6. **Empty Organizations**: Verifies error message when no organizations exist. + * 7. **Drawer Visibility**: Tests drawer visibility with `hideDrawer` prop values. + * 8. **User Profile Rendering**: Confirms user details are displayed. + * 9. **Translation Display**: Ensures proper translation of UI text. + * 10. **Toast Notifications Mocking**: Mocks toast notifications during tests. + * + * `fireEvent` simulates user actions, and `vi.fn()` mocks callback functions. + */ const { setItem } = useLocalStorage(); const props: InterfaceUserSidebarOrgProps = { @@ -47,7 +62,7 @@ const props: InterfaceUserSidebarOrgProps = { }, ], hideDrawer: false, - setHideDrawer: jest.fn(), + setHideDrawer: vi.fn(), }; const MOCKS = [ @@ -213,11 +228,11 @@ const defaultScreens = [ 'All Organizations', ]; -jest.mock('react-toastify', () => ({ +vi.mock('react-toastify', () => ({ toast: { - success: jest.fn(), - warn: jest.fn(), - error: jest.fn(), + success: vi.fn(), + warn: vi.fn(), + error: vi.fn(), }, })); @@ -244,7 +259,7 @@ beforeEach(() => { }); afterEach(() => { - jest.clearAllMocks(); + vi.clearAllMocks(); localStorage.clear(); }); @@ -253,7 +268,7 @@ const linkImage = new StaticMockLink(MOCKS_WITH_IMAGE, true); const linkEmpty = new StaticMockLink(MOCKS_EMPTY, true); describe('Testing LeftDrawerOrg component for SUPERADMIN', () => { - test('Component should be rendered properly', async () => { + it('Component should be rendered properly', async () => { setItem('UserImage', ''); setItem('SuperAdmin', true); setItem('FirstName', 'John'); @@ -275,7 +290,7 @@ describe('Testing LeftDrawerOrg component for SUPERADMIN', () => { }); }); - test('Testing Profile Page & Organization Detail Modal', async () => { + it('Testing Profile Page & Organization Detail Modal', async () => { setItem('UserImage', ''); setItem('SuperAdmin', true); setItem('FirstName', 'John'); @@ -295,7 +310,7 @@ describe('Testing LeftDrawerOrg component for SUPERADMIN', () => { expect(screen.getByTestId(/orgBtn/i)).toBeInTheDocument(); }); - test('Testing Menu Buttons', async () => { + it('Testing Menu Buttons', async () => { setItem('UserImage', ''); setItem('SuperAdmin', true); setItem('FirstName', 'John'); @@ -316,7 +331,7 @@ describe('Testing LeftDrawerOrg component for SUPERADMIN', () => { expect(global.window.location.pathname).toContain('/user/people/123'); }); - test('Testing when screen size is less than 820px', async () => { + it('Testing when screen size is less than 820px', async () => { setItem('SuperAdmin', true); render( @@ -339,7 +354,7 @@ describe('Testing LeftDrawerOrg component for SUPERADMIN', () => { expect(window.location.pathname).toContain('user/people/123'); }); - test('Testing when image is present for Organization', async () => { + it('Testing when image is present for Organization', async () => { setItem('UserImage', ''); setItem('SuperAdmin', true); setItem('FirstName', 'John'); @@ -358,7 +373,7 @@ describe('Testing LeftDrawerOrg component for SUPERADMIN', () => { await wait(); }); - test('Testing when Organization does not exists', async () => { + it('Testing when Organization does not exists', async () => { setItem('UserImage', ''); setItem('SuperAdmin', true); setItem('FirstName', 'John'); @@ -380,7 +395,7 @@ describe('Testing LeftDrawerOrg component for SUPERADMIN', () => { ).toBeInTheDocument(); }); - test('Testing Drawer when hideDrawer is null', () => { + it('Testing Drawer when hideDrawer is null', () => { setItem('UserImage', ''); setItem('SuperAdmin', true); setItem('FirstName', 'John'); @@ -398,7 +413,7 @@ describe('Testing LeftDrawerOrg component for SUPERADMIN', () => { ); }); - test('Testing Drawer when hideDrawer is true', () => { + it('Testing Drawer when hideDrawer is true', () => { setItem('UserImage', ''); setItem('SuperAdmin', true); setItem('FirstName', 'John'); From c5a300092585d5b8ff09e601148ef219a71750c7 Mon Sep 17 00:00:00 2001 From: IITI-tushar <165766280+IITI-tushar@users.noreply.github.com> Date: Sat, 28 Dec 2024 10:48:07 +0530 Subject: [PATCH 04/11] updated tagtemplate and app.module (#2976) --- src/components/CheckIn/tagTemplate.ts | 11 ++--------- src/style/app.module.css | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/components/CheckIn/tagTemplate.ts b/src/components/CheckIn/tagTemplate.ts index a10dbca083..611dff7b83 100644 --- a/src/components/CheckIn/tagTemplate.ts +++ b/src/components/CheckIn/tagTemplate.ts @@ -1,4 +1,5 @@ import { Template } from '@pdfme/common'; +import styles from '../../style/app.module.css'; export const tagTemplate: Template = { schemas: [ @@ -6,15 +7,7 @@ export const tagTemplate: Template = { { name: 'name', type: 'text', - position: { x: 14.91, y: 27.03 }, - width: 58.55, - height: 5.67, - alignment: 'center', - fontSize: 16, - characterSpacing: 0, - lineHeight: 1, - fontName: 'Roboto', - fontColor: '#08780b', + className: `${styles['tag-template-name']}`, } , ], ] as any, diff --git a/src/style/app.module.css b/src/style/app.module.css index 6be00d217a..9480b80d20 100644 --- a/src/style/app.module.css +++ b/src/style/app.module.css @@ -460,6 +460,20 @@ } } +.tag-template-name { + position: absolute; + left: 14.91px; + top: 27.03px; + width: 58.55px; + height: 5.67px; + text-align: center; + font-family: 'Roboto', sans-serif; + font-size: 16px; + letter-spacing: 0; + line-height: 1; + color: #08780b; +} + .subTagsLink i { visibility: hidden; } From c310730fdf93d2eacb3f1a63594a38071a46a9de Mon Sep 17 00:00:00 2001 From: Pratap Rathi Date: Sat, 28 Dec 2024 20:48:51 +0530 Subject: [PATCH 05/11] Migrated src/components/EventStats/* from Jest to Vitest (#2997) * Refactor: Migrated src/components/EventStats/* from Jest to Vitest * Refactor: Removed duplicate mock implementation in EventStatsWrapper.spec.tsx --- ...ventStats.test.tsx => EventStats.spec.tsx} | 16 +++++++------ ...er.test.tsx => EventStatsWrapper.spec.tsx} | 23 ++++++++----------- ...Rating.test.tsx => AverageRating.spec.tsx} | 3 ++- .../{Feedback.test.tsx => Feedback.spec.tsx} | 16 +++++++------ .../{Review.test.tsx => Review.spec.tsx} | 5 ++-- 5 files changed, 32 insertions(+), 31 deletions(-) rename src/components/EventStats/{EventStats.test.tsx => EventStats.spec.tsx} (75%) rename src/components/EventStats/{EventStatsWrapper.test.tsx => EventStatsWrapper.spec.tsx} (73%) rename src/components/EventStats/Statistics/{AverageRating.test.tsx => AverageRating.spec.tsx} (91%) rename src/components/EventStats/Statistics/{Feedback.test.tsx => Feedback.spec.tsx} (81%) rename src/components/EventStats/Statistics/{Review.test.tsx => Review.spec.tsx} (89%) diff --git a/src/components/EventStats/EventStats.test.tsx b/src/components/EventStats/EventStats.spec.tsx similarity index 75% rename from src/components/EventStats/EventStats.test.tsx rename to src/components/EventStats/EventStats.spec.tsx index e2496fa5af..058913c6e7 100644 --- a/src/components/EventStats/EventStats.test.tsx +++ b/src/components/EventStats/EventStats.spec.tsx @@ -4,13 +4,15 @@ import { MockedProvider } from '@apollo/react-testing'; import { EventStats } from './EventStats'; import { BrowserRouter } from 'react-router-dom'; import { EVENT_FEEDBACKS } from 'GraphQl/Queries/Queries'; +import { vi, describe, expect, it } from 'vitest'; -// Mock the modules for PieChart rendering as they require a trasformer being used (which is not done by Jest) +// Mock the modules for PieChart rendering as they require a trasformer being used (which is not done by Vitest) // These modules are used by the Feedback component -jest.mock('@mui/x-charts/PieChart', () => ({ - pieArcLabelClasses: jest.fn(), - PieChart: jest.fn().mockImplementation(() => <>Test), - pieArcClasses: jest.fn(), +vi.mock('@mui/x-charts/PieChart', async () => ({ + ...(await vi.importActual('@mui/x-charts/PieChart')), + pieArcLabelClasses: vi.fn(), + PieChart: vi.fn().mockImplementation(() => <>Test), + pieArcClasses: vi.fn(), })); const mockData = [ @@ -43,10 +45,10 @@ describe('Testing Event Stats', () => { const props = { eventId: 'eventStats123', show: true, - handleClose: jest.fn(), + handleClose: vi.fn(), }; - test('The stats should be rendered properly', async () => { + it('The stats should be rendered properly', async () => { const { queryByText } = render( diff --git a/src/components/EventStats/EventStatsWrapper.test.tsx b/src/components/EventStats/EventStatsWrapper.spec.tsx similarity index 73% rename from src/components/EventStats/EventStatsWrapper.test.tsx rename to src/components/EventStats/EventStatsWrapper.spec.tsx index 0e64ac13cc..7a94aea5ef 100644 --- a/src/components/EventStats/EventStatsWrapper.test.tsx +++ b/src/components/EventStats/EventStatsWrapper.spec.tsx @@ -4,12 +4,15 @@ import { MockedProvider } from '@apollo/react-testing'; import { EventStatsWrapper } from './EventStatsWrapper'; import { BrowserRouter } from 'react-router-dom'; import { EVENT_FEEDBACKS } from 'GraphQl/Queries/Queries'; +import { vi, describe, expect, it } from 'vitest'; -// Mock the modules for PieChart rendering as they require a trasformer being used (which is not done by Jest) -jest.mock('@mui/x-charts/PieChart', () => ({ - pieArcLabelClasses: jest.fn(), - PieChart: jest.fn().mockImplementation(() => <>Test), - pieArcClasses: jest.fn(), +// Mock the modules for PieChart rendering as they require a trasformer being used (which is not done by Vitest) +// These modules are used by the Feedback component +vi.mock('@mui/x-charts/PieChart', async () => ({ + ...(await vi.importActual('@mui/x-charts/PieChart')), + pieArcLabelClasses: vi.fn(), + PieChart: vi.fn().mockImplementation(() => <>Test), + pieArcClasses: vi.fn(), })); const mockData = [ @@ -38,20 +41,12 @@ const mockData = [ }, ]; -// Mock the modules for PieChart rendering as they require a trasformer being used (which is not done by Jest) -// These modules are used by the Feedback component -jest.mock('@mui/x-charts/PieChart', () => ({ - pieArcLabelClasses: jest.fn(), - PieChart: jest.fn().mockImplementation(() => <>Test), - pieArcClasses: jest.fn(), -})); - describe('Testing Event Stats Wrapper', () => { const props = { eventId: 'eventStats123', }; - test('The button to open and close the modal should work properly', async () => { + it('The button to open and close the modal should work properly', async () => { const { queryByText, queryByRole } = render( diff --git a/src/components/EventStats/Statistics/AverageRating.test.tsx b/src/components/EventStats/Statistics/AverageRating.spec.tsx similarity index 91% rename from src/components/EventStats/Statistics/AverageRating.test.tsx rename to src/components/EventStats/Statistics/AverageRating.spec.tsx index 01cf6461e3..c5a6b91925 100644 --- a/src/components/EventStats/Statistics/AverageRating.test.tsx +++ b/src/components/EventStats/Statistics/AverageRating.spec.tsx @@ -7,6 +7,7 @@ import { store } from 'state/store'; import { I18nextProvider } from 'react-i18next'; import i18nForTest from 'utils/i18nForTest'; import { ToastContainer } from 'react-toastify'; +import { describe, expect, it } from 'vitest'; const props = { data: { @@ -35,7 +36,7 @@ const props = { }; describe('Testing Average Rating Card', () => { - test('The component should be rendered and the Score should be shown', async () => { + it('The component should be rendered and the Score should be shown', async () => { const { queryByText } = render( diff --git a/src/components/EventStats/Statistics/Feedback.test.tsx b/src/components/EventStats/Statistics/Feedback.spec.tsx similarity index 81% rename from src/components/EventStats/Statistics/Feedback.test.tsx rename to src/components/EventStats/Statistics/Feedback.spec.tsx index 9abdee4c57..4fb020a70e 100644 --- a/src/components/EventStats/Statistics/Feedback.test.tsx +++ b/src/components/EventStats/Statistics/Feedback.spec.tsx @@ -7,12 +7,14 @@ import { store } from 'state/store'; import { I18nextProvider } from 'react-i18next'; import i18nForTest from 'utils/i18nForTest'; import { ToastContainer } from 'react-toastify'; +import { vi, describe, expect, it } from 'vitest'; -// Mock the modules for PieChart rendering as they require a trasformer being used (which is not done by Jest) -jest.mock('@mui/x-charts/PieChart', () => ({ - pieArcLabelClasses: jest.fn(), - PieChart: jest.fn().mockImplementation(() => <>Test), - pieArcClasses: jest.fn(), +// Mock the modules for PieChart rendering as they require a trasformer being used (which is not done by Vitest) +vi.mock('@mui/x-charts/PieChart', async () => ({ + ...(await vi.importActual('@mui/x-charts/PieChart')), + pieArcLabelClasses: vi.fn(), + PieChart: vi.fn().mockImplementation(() => <>Test), + pieArcClasses: vi.fn(), })); const nonEmptyProps = { @@ -52,7 +54,7 @@ const emptyProps = { }; describe('Testing Feedback Statistics Card', () => { - test('The component should be rendered and the feedback should be shown if present', async () => { + it('The component should be rendered and the feedback should be shown if present', async () => { const { queryByText } = render( @@ -79,7 +81,7 @@ describe('Testing Feedback Statistics Card', () => { }); }); - test('The component should be rendered and message should be shown if no feedback is present', async () => { + it('The component should be rendered and message should be shown if no feedback is present', async () => { const { queryByText } = render( diff --git a/src/components/EventStats/Statistics/Review.test.tsx b/src/components/EventStats/Statistics/Review.spec.tsx similarity index 89% rename from src/components/EventStats/Statistics/Review.test.tsx rename to src/components/EventStats/Statistics/Review.spec.tsx index 9093444ab2..5777c32c27 100644 --- a/src/components/EventStats/Statistics/Review.test.tsx +++ b/src/components/EventStats/Statistics/Review.spec.tsx @@ -7,6 +7,7 @@ import { store } from 'state/store'; import { I18nextProvider } from 'react-i18next'; import i18nForTest from 'utils/i18nForTest'; import { ToastContainer } from 'react-toastify'; +import { describe, expect, it } from 'vitest'; const nonEmptyReviewProps = { data: { @@ -51,7 +52,7 @@ const emptyReviewProps = { }; describe('Testing Review Statistics Card', () => { - test('The component should be rendered and the reviews should be shown if present', async () => { + it('The component should be rendered and the reviews should be shown if present', async () => { const { queryByText } = render( @@ -72,7 +73,7 @@ describe('Testing Review Statistics Card', () => { await waitFor(() => expect(queryByText('review2')).toBeInTheDocument()); }); - test('The component should be rendered and message should be shown if no review is present', async () => { + it('The component should be rendered and message should be shown if no review is present', async () => { const { queryByText } = render( From e819baabad9d0b4133edda859750a174bb75e81b Mon Sep 17 00:00:00 2001 From: Pranav Nathe <93403830+pranavnathe@users.noreply.github.com> Date: Sat, 28 Dec 2024 21:01:06 +0530 Subject: [PATCH 06/11] fix avatar alignment (#2989) --- src/screens/OrganizationActionItems/ItemViewModal.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/screens/OrganizationActionItems/ItemViewModal.tsx b/src/screens/OrganizationActionItems/ItemViewModal.tsx index 98f2f6fd7f..97c962524f 100644 --- a/src/screens/OrganizationActionItems/ItemViewModal.tsx +++ b/src/screens/OrganizationActionItems/ItemViewModal.tsx @@ -146,7 +146,7 @@ const ItemViewModal: FC = ({ isOpen, hide, item }) => { className={styles.TableImage} /> ) : ( -
+
Date: Sat, 28 Dec 2024 21:02:19 +0530 Subject: [PATCH 07/11] Refactor/use session jest to vitest (#2990) * refactored useSession from jest to vitest * refactor useSession.spec.tsx to vitest * format fixed --- src/utils/useSession.spec.tsx | 688 ++++++++++++++++++++++++++++++++++ src/utils/useSession.test.tsx | 544 --------------------------- 2 files changed, 688 insertions(+), 544 deletions(-) create mode 100644 src/utils/useSession.spec.tsx delete mode 100644 src/utils/useSession.test.tsx diff --git a/src/utils/useSession.spec.tsx b/src/utils/useSession.spec.tsx new file mode 100644 index 0000000000..9b50039ba2 --- /dev/null +++ b/src/utils/useSession.spec.tsx @@ -0,0 +1,688 @@ +import type { ReactNode } from 'react'; +import React from 'react'; +import { renderHook } from '@testing-library/react'; +import { MockedProvider } from '@apollo/client/testing'; +import { toast } from 'react-toastify'; +import { describe, beforeEach, afterEach, test, expect, vi } from 'vitest'; +import useSession from './useSession'; +import { GET_COMMUNITY_SESSION_TIMEOUT_DATA } from 'GraphQl/Queries/Queries'; +import { REVOKE_REFRESH_TOKEN } from 'GraphQl/Mutations/mutations'; +import { errorHandler } from 'utils/errorHandler'; +import { BrowserRouter } from 'react-router-dom'; + +vi.mock('react-toastify', () => ({ + toast: { + info: vi.fn(), + warning: vi.fn(), + error: vi.fn(), + }, +})); + +vi.mock('utils/errorHandler', () => ({ + errorHandler: vi.fn(), +})); + +vi.mock('react-i18next', () => ({ + useTranslation: () => ({ + t: (key: string) => key, + }), +})); + +const MOCKS = [ + { + request: { + query: GET_COMMUNITY_SESSION_TIMEOUT_DATA, + }, + result: { + data: { + getCommunityData: { + timeout: 30, + }, + }, + }, + delay: 100, + }, + { + request: { + query: REVOKE_REFRESH_TOKEN, + }, + result: { + data: { + revokeRefreshTokenForUser: true, + }, + }, + }, +]; +describe('useSession Hook', () => { + beforeEach(() => { + vi.clearAllMocks(); + vi.spyOn(window, 'addEventListener').mockImplementation(vi.fn()); + vi.spyOn(window, 'removeEventListener').mockImplementation(vi.fn()); + Object.defineProperty(global, 'localStorage', { + value: { + clear: vi.fn(), + }, + writable: true, + }); + }); + + afterEach(() => { + vi.clearAllMocks(); + vi.useRealTimers(); + vi.restoreAllMocks(); + }); + + test('should handle visibility change to visible', async () => { + vi.useFakeTimers(); + + const { result } = renderHook(() => useSession(), { + wrapper: ({ children }: { children?: ReactNode }) => ( + + {children} + + ), + }); + + Object.defineProperty(document, 'visibilityState', { + value: 'visible', + writable: true, + }); + + result.current.startSession(); + + document.dispatchEvent(new Event('visibilitychange')); + + vi.advanceTimersByTime(15 * 60 * 1000); + + await vi.waitFor(() => { + expect(window.addEventListener).toHaveBeenCalledWith( + 'mousemove', + expect.any(Function), + ); + expect(window.addEventListener).toHaveBeenCalledWith( + 'keydown', + expect.any(Function), + ); + expect(toast.warning).toHaveBeenCalledWith('sessionWarning'); + }); + + vi.useRealTimers(); + }); + + test('should handle visibility change to hidden and ensure no warning appears in 15 minutes', async () => { + vi.useFakeTimers(); + + const { result } = renderHook(() => useSession(), { + wrapper: ({ children }: { children?: ReactNode }) => ( + + {children} + + ), + }); + + Object.defineProperty(document, 'visibilityState', { + value: 'hidden', + writable: true, + }); + + result.current.startSession(); + + document.dispatchEvent(new Event('visibilitychange')); + + vi.advanceTimersByTime(15 * 60 * 1000); + + await vi.waitFor(() => { + expect(window.removeEventListener).toHaveBeenCalledWith( + 'mousemove', + expect.any(Function), + ); + expect(window.removeEventListener).toHaveBeenCalledWith( + 'keydown', + expect.any(Function), + ); + expect(toast.warning).not.toHaveBeenCalled(); + }); + + vi.useRealTimers(); + }); + + test('should register event listeners on startSession', async () => { + const addEventListenerSpy = vi.fn(); + const windowAddEventListenerSpy = vi + .spyOn(window, 'addEventListener') + .mockImplementation(addEventListenerSpy); + const documentAddEventListenerSpy = vi + .spyOn(document, 'addEventListener') + .mockImplementation(addEventListenerSpy); + + const { result } = renderHook(() => useSession(), { + wrapper: ({ children }: { children?: ReactNode }) => ( + + {children} + + ), + }); + + result.current.startSession(); + + await vi.waitFor(() => { + const calls = addEventListenerSpy.mock.calls; + expect(calls.length).toBe(4); + + const eventTypes = calls.map((call) => call[0]); + expect(eventTypes).toContain('mousemove'); + expect(eventTypes).toContain('keydown'); + expect(eventTypes).toContain('visibilitychange'); + + calls.forEach((call) => { + expect(call[1]).toBeTypeOf('function'); + }); + }); + + windowAddEventListenerSpy.mockRestore(); + documentAddEventListenerSpy.mockRestore(); + }); + + test('should call handleLogout after session timeout', async () => { + vi.useFakeTimers(); + + const { result } = renderHook(() => useSession(), { + wrapper: ({ children }: { children?: ReactNode }) => ( + + {children} + + ), + }); + + result.current.startSession(); + + vi.advanceTimersByTime(31 * 60 * 1000); + + await vi.waitFor(() => { + expect(global.localStorage.clear).toHaveBeenCalled(); + expect(toast.warning).toHaveBeenCalledTimes(2); + expect(toast.warning).toHaveBeenNthCalledWith(1, 'sessionWarning'); + expect(toast.warning).toHaveBeenNthCalledWith(2, 'sessionLogout', { + autoClose: false, + }); + }); + }); + + test('should show a warning toast before session expiration', async () => { + vi.useFakeTimers(); + + const { result } = renderHook(() => useSession(), { + wrapper: ({ children }: { children?: ReactNode }) => ( + + {children} + + ), + }); + + result.current.startSession(); + + vi.advanceTimersByTime(15 * 60 * 1000); + + await vi.waitFor(() => + expect(toast.warning).toHaveBeenCalledWith('sessionWarning'), + ); + + vi.useRealTimers(); + }); + + test('should handle error when revoking token fails', async () => { + const consoleErrorMock = vi + .spyOn(console, 'error') + .mockImplementation(() => {}); + + const errorMocks = [ + { + request: { + query: GET_COMMUNITY_SESSION_TIMEOUT_DATA, + }, + result: { + data: { + getCommunityData: { + timeout: 30, + }, + }, + }, + delay: 1000, + }, + { + request: { + query: REVOKE_REFRESH_TOKEN, + }, + error: new Error('Failed to revoke refresh token'), + }, + ]; + + const { result } = renderHook(() => useSession(), { + wrapper: ({ children }: { children?: ReactNode }) => ( + + {children} + + ), + }); + + result.current.startSession(); + result.current.handleLogout(); + + await vi.waitFor(() => + expect(consoleErrorMock).toHaveBeenCalledWith( + 'Error revoking refresh token:', + expect.any(Error), + ), + ); + + consoleErrorMock.mockRestore(); + }); + + test('should set session timeout based on fetched data', async () => { + vi.spyOn(global, 'setTimeout'); + + const { result } = renderHook(() => useSession(), { + wrapper: ({ children }: { children?: ReactNode }) => ( + + {children} + + ), + }); + + result.current.startSession(); + + expect(global.setTimeout).toHaveBeenCalled(); + }); + + test('should call errorHandler on query error', async () => { + const errorMocks = [ + { + request: { + query: GET_COMMUNITY_SESSION_TIMEOUT_DATA, + }, + error: new Error('An error occurred'), + }, + ]; + + const { result } = renderHook(() => useSession(), { + wrapper: ({ children }: { children?: ReactNode }) => ( + + {children} + + ), + }); + + result.current.startSession(); + + await vi.waitFor(() => expect(errorHandler).toHaveBeenCalled()); + }); + + test('should remove event listeners on endSession', async () => { + const removeEventListenerSpy = vi.fn(); + const windowRemoveEventListenerSpy = vi + .spyOn(window, 'removeEventListener') + .mockImplementation(removeEventListenerSpy); + const documentRemoveEventListenerSpy = vi + .spyOn(document, 'removeEventListener') + .mockImplementation(removeEventListenerSpy); + + const { result } = renderHook(() => useSession(), { + wrapper: ({ children }: { children?: ReactNode }) => ( + + {children} + + ), + }); + + result.current.startSession(); + result.current.endSession(); + + await vi.waitFor(() => { + const calls = removeEventListenerSpy.mock.calls; + expect(calls.length).toBe(6); + + const eventTypes = calls.map((call) => call[0]); + expect(eventTypes).toContain('mousemove'); + expect(eventTypes).toContain('keydown'); + expect(eventTypes).toContain('visibilitychange'); + + calls.forEach((call) => { + expect(call[1]).toBeTypeOf('function'); + }); + }); + + windowRemoveEventListenerSpy.mockRestore(); + documentRemoveEventListenerSpy.mockRestore(); + }); + + test('should call initialize timers when session is still active when the user returns to the tab', async () => { + vi.useFakeTimers(); + vi.spyOn(global, 'setTimeout').mockImplementation(vi.fn()); + + const { result } = renderHook(() => useSession(), { + wrapper: ({ children }) => ( + + {children} + + ), + }); + + vi.advanceTimersByTime(1000); + + Object.defineProperty(document, 'visibilityState', { + value: 'visible', + writable: true, + }); + + result.current.startSession(); + vi.advanceTimersByTime(10 * 60 * 1000); + + Object.defineProperty(document, 'visibilityState', { + value: 'hidden', + writable: true, + }); + + document.dispatchEvent(new Event('visibilitychange')); + + vi.advanceTimersByTime(5 * 60 * 1000); + + Object.defineProperty(document, 'visibilityState', { + value: 'visible', + writable: true, + }); + + document.dispatchEvent(new Event('visibilitychange')); + + vi.advanceTimersByTime(1000); + + expect(global.setTimeout).toHaveBeenCalled(); + + vi.useRealTimers(); + }); + + test('should call handleLogout when session expires due to inactivity away from tab', async () => { + vi.useFakeTimers(); + + const { result } = renderHook(() => useSession(), { + wrapper: ({ children }) => ( + + {children} + + ), + }); + + vi.advanceTimersByTime(1000); + + Object.defineProperty(document, 'visibilityState', { + value: 'visible', + writable: true, + }); + + result.current.startSession(); + vi.advanceTimersByTime(10 * 60 * 1000); + + Object.defineProperty(document, 'visibilityState', { + value: 'hidden', + writable: true, + }); + + document.dispatchEvent(new Event('visibilitychange')); + + vi.advanceTimersByTime(32 * 60 * 1000); + + Object.defineProperty(document, 'visibilityState', { + value: 'visible', + writable: true, + }); + + document.dispatchEvent(new Event('visibilitychange')); + + vi.advanceTimersByTime(250); + + await vi.waitFor(() => { + expect(global.localStorage.clear).toHaveBeenCalled(); + expect(toast.warning).toHaveBeenCalledWith('sessionLogout', { + autoClose: false, + }); + }); + + vi.useRealTimers(); + }); + + test('should handle logout and revoke token', async () => { + vi.useFakeTimers(); + + const { result } = renderHook(() => useSession(), { + wrapper: ({ children }: { children?: ReactNode }) => ( + + {children} + + ), + }); + + result.current.startSession(); + result.current.handleLogout(); + + await vi.waitFor(() => { + expect(global.localStorage.clear).toHaveBeenCalled(); + expect(toast.warning).toHaveBeenCalledWith('sessionLogout', { + autoClose: false, + }); + }); + + vi.useRealTimers(); + }); +}); +test('should extend session when called directly', async () => { + vi.useFakeTimers(); + + const { result } = renderHook(() => useSession(), { + wrapper: ({ children }: { children?: ReactNode }) => ( + + {children} + + ), + }); + + result.current.startSession(); + + // Advance time to just before warning + vi.advanceTimersByTime(14 * 60 * 1000); + + // Extend session + result.current.extendSession(); + + // Advance time to where warning would have been + vi.advanceTimersByTime(1 * 60 * 1000); + + // Warning shouldn't have been called yet since we extended + expect(toast.warning).not.toHaveBeenCalled(); + + // Advance to new warning time + vi.advanceTimersByTime(14 * 60 * 1000); + + await vi.waitFor(() => + expect(toast.warning).toHaveBeenCalledWith('sessionWarning'), + ); + + vi.useRealTimers(); +}); + +test('should properly clean up on unmount', () => { + // Mock document.removeEventListener + const documentRemoveEventListener = vi.spyOn(document, 'removeEventListener'); + + const { result, unmount } = renderHook(() => useSession(), { + wrapper: ({ children }: { children?: ReactNode }) => ( + + {children} + + ), + }); + + result.current.startSession(); + unmount(); + + expect(window.removeEventListener).toHaveBeenCalledWith( + 'mousemove', + expect.any(Function), + ); + expect(window.removeEventListener).toHaveBeenCalledWith( + 'keydown', + expect.any(Function), + ); + expect(documentRemoveEventListener).toHaveBeenCalledWith( + 'visibilitychange', + expect.any(Function), + ); + + documentRemoveEventListener.mockRestore(); +}); +test('should handle missing community data', async () => { + vi.useFakeTimers(); + const setTimeoutSpy = vi.spyOn(global, 'setTimeout'); + + const nullDataMocks = [ + { + request: { + query: GET_COMMUNITY_SESSION_TIMEOUT_DATA, + }, + result: { + data: { + getCommunityData: null, + }, + }, + }, + ]; + + const { result } = renderHook(() => useSession(), { + wrapper: ({ children }: { children?: ReactNode }) => ( + + {children} + + ), + }); + + result.current.startSession(); + + // Wait for timers to be set + await vi.waitFor(() => { + expect(setTimeoutSpy).toHaveBeenCalled(); + }); + + // Get all setTimeout calls + const timeoutCalls = setTimeoutSpy.mock.calls; + + // Check for warning timeout (15 minutes = 900000ms) + const hasWarningTimeout = timeoutCalls.some( + (call: Parameters) => { + const [, ms] = call; + return typeof ms === 'number' && ms === (30 * 60 * 1000) / 2; + }, + ); + + // Check for session timeout (30 minutes = 1800000ms) + const hasSessionTimeout = timeoutCalls.some( + (call: Parameters) => { + const [, ms] = call; + return typeof ms === 'number' && ms === 30 * 60 * 1000; + }, + ); + + expect(hasWarningTimeout).toBe(true); + expect(hasSessionTimeout).toBe(true); + + setTimeoutSpy.mockRestore(); + vi.useRealTimers(); +}); + +test('should handle event listener errors gracefully', async () => { + const consoleErrorSpy = vi + .spyOn(console, 'error') + .mockImplementation(() => {}); + const mockError = new Error('Event listener error'); + + // Mock addEventListener to throw an error + const addEventListenerSpy = vi + .spyOn(window, 'addEventListener') + .mockImplementationOnce(() => { + throw mockError; + }); + + try { + const { result } = renderHook(() => useSession(), { + wrapper: ({ children }: { children?: ReactNode }) => ( + + {children} + + ), + }); + + result.current.startSession(); + } catch { + // Error should be caught and logged + expect(consoleErrorSpy).toHaveBeenCalled(); + } + + consoleErrorSpy.mockRestore(); + addEventListenerSpy.mockRestore(); +}); + +test('should handle session timeout data updates', async () => { + vi.useFakeTimers(); + const setTimeoutSpy = vi.spyOn(global, 'setTimeout'); + + const customMocks = [ + { + request: { + query: GET_COMMUNITY_SESSION_TIMEOUT_DATA, + }, + result: { + data: { + getCommunityData: { + timeout: 45, + }, + }, + }, + }, + ]; + + const { result } = renderHook(() => useSession(), { + wrapper: ({ children }: { children?: ReactNode }) => ( + + {children} + + ), + }); + + result.current.startSession(); + + // Wait for the query and timers + await vi.waitFor(() => { + expect(setTimeoutSpy).toHaveBeenCalled(); + }); + + const timeoutCalls = setTimeoutSpy.mock.calls; + const expectedWarningTime = (45 * 60 * 1000) / 2; + const expectedSessionTime = 45 * 60 * 1000; + + const hasWarningTimeout = timeoutCalls.some((call) => { + const duration = call[1] as number; + return ( + Math.abs(duration - expectedWarningTime) <= expectedWarningTime * 0.05 + ); // ±5% + }); + + const hasSessionTimeout = timeoutCalls.some((call) => { + const duration = call[1] as number; + return ( + Math.abs(duration - expectedSessionTime) <= expectedSessionTime * 0.05 + ); // ±5% + }); + + expect(hasWarningTimeout).toBe(false); + expect(hasSessionTimeout).toBe(false); + + setTimeoutSpy.mockRestore(); + vi.useRealTimers(); +}); diff --git a/src/utils/useSession.test.tsx b/src/utils/useSession.test.tsx deleted file mode 100644 index 32287ccbb0..0000000000 --- a/src/utils/useSession.test.tsx +++ /dev/null @@ -1,544 +0,0 @@ -import type { ReactNode } from 'react'; -import React from 'react'; -import { renderHook, act, waitFor } from '@testing-library/react'; -import { MockedProvider } from '@apollo/client/testing'; -import { toast } from 'react-toastify'; -import useSession from './useSession'; -import { GET_COMMUNITY_SESSION_TIMEOUT_DATA } from 'GraphQl/Queries/Queries'; -import { REVOKE_REFRESH_TOKEN } from 'GraphQl/Mutations/mutations'; -import { errorHandler } from 'utils/errorHandler'; -import { BrowserRouter } from 'react-router-dom'; - -jest.mock('react-toastify', () => ({ - toast: { - info: jest.fn(), - warning: jest.fn(), - error: jest.fn(), - }, -})); - -jest.mock('utils/errorHandler', () => ({ - errorHandler: jest.fn(), -})); - -jest.mock('react-i18next', () => ({ - useTranslation: () => ({ - t: (key: string) => key, - }), -})); - -const MOCKS = [ - { - request: { - query: GET_COMMUNITY_SESSION_TIMEOUT_DATA, - }, - result: { - data: { - getCommunityData: { - timeout: 30, - }, - }, - }, - delay: 100, - }, - { - request: { - query: REVOKE_REFRESH_TOKEN, - }, - result: { - data: { - revokeRefreshTokenForUser: true, - }, - }, - }, -]; - -const wait = (ms: number): Promise => - new Promise((resolve) => setTimeout(resolve, ms)); - -describe('useSession Hook', () => { - beforeEach(() => { - jest.clearAllMocks(); - jest.spyOn(window, 'addEventListener').mockImplementation(jest.fn()); - jest.spyOn(window, 'removeEventListener').mockImplementation(jest.fn()); - Object.defineProperty(global, 'localStorage', { - value: { - clear: jest.fn(), - }, - writable: true, - }); - }); - - afterEach(() => { - jest.clearAllMocks(); - jest.useRealTimers(); - jest.restoreAllMocks(); - }); - - test('should handle visibility change to visible', async () => { - jest.useFakeTimers(); - - const { result } = renderHook(() => useSession(), { - wrapper: ({ children }: { children?: ReactNode }) => ( - - {children} - - ), - }); - - Object.defineProperty(document, 'visibilityState', { - value: 'visible', - writable: true, - }); - - act(() => { - result.current.startSession(); - }); - - // Simulate visibility change - act(() => { - document.dispatchEvent(new Event('visibilitychange')); - }); - - act(() => { - jest.advanceTimersByTime(15 * 60 * 1000); - }); - - await waitFor(() => { - expect(window.addEventListener).toHaveBeenCalledWith( - 'mousemove', - expect.any(Function), - ); - expect(window.addEventListener).toHaveBeenCalledWith( - 'keydown', - expect.any(Function), - ); - expect(toast.warning).toHaveBeenCalledWith('sessionWarning'); - }); - - jest.useRealTimers(); - }); - - test('should handle visibility change to hidden and ensure no warning appears in 15 minutes', async () => { - jest.useFakeTimers(); - - const { result } = renderHook(() => useSession(), { - wrapper: ({ children }: { children?: ReactNode }) => ( - - {children} - - ), - }); - - Object.defineProperty(document, 'visibilityState', { - value: 'hidden', - writable: true, - }); - - act(() => { - result.current.startSession(); - }); - - act(() => { - document.dispatchEvent(new Event('visibilitychange')); - }); - - act(() => { - jest.advanceTimersByTime(15 * 60 * 1000); - }); - - await waitFor(() => { - expect(window.removeEventListener).toHaveBeenCalledWith( - 'mousemove', - expect.any(Function), - ); - expect(window.removeEventListener).toHaveBeenCalledWith( - 'keydown', - expect.any(Function), - ); - expect(toast.warning).not.toHaveBeenCalled(); - }); - - jest.useRealTimers(); - }); - - test('should register event listeners on startSession', async () => { - const addEventListenerMock = jest.fn(); - const originalWindowAddEventListener = window.addEventListener; - const originalDocumentAddEventListener = document.addEventListener; - - window.addEventListener = addEventListenerMock; - document.addEventListener = addEventListenerMock; - - const { result } = renderHook(() => useSession(), { - wrapper: ({ children }: { children?: ReactNode }) => ( - - {children} - - ), - }); - - act(() => { - result.current.startSession(); - }); - - expect(addEventListenerMock).toHaveBeenCalledWith( - 'mousemove', - expect.any(Function), - ); - expect(addEventListenerMock).toHaveBeenCalledWith( - 'keydown', - expect.any(Function), - ); - expect(addEventListenerMock).toHaveBeenCalledWith( - 'visibilitychange', - expect.any(Function), - ); - - window.addEventListener = originalWindowAddEventListener; - document.addEventListener = originalDocumentAddEventListener; - }); - - test('should call handleLogout after session timeout', async () => { - jest.useFakeTimers(); - - const { result } = renderHook(() => useSession(), { - wrapper: ({ children }: { children?: ReactNode }) => ( - - {children} - - ), - }); - - act(() => { - result.current.startSession(); - }); - - act(() => { - jest.advanceTimersByTime(31 * 60 * 1000); - }); - - await waitFor(() => { - expect(global.localStorage.clear).toHaveBeenCalled(); - expect(toast.warning).toHaveBeenCalledTimes(2); - expect(toast.warning).toHaveBeenNthCalledWith(1, 'sessionWarning'); - expect(toast.warning).toHaveBeenNthCalledWith(2, 'sessionLogout', { - autoClose: false, - }); - }); - }); - - test('should show a warning toast before session expiration', async () => { - jest.useFakeTimers(); - - const { result } = renderHook(() => useSession(), { - wrapper: ({ children }: { children?: ReactNode }) => ( - - {children} - - ), - }); - - act(() => { - result.current.startSession(); - }); - - act(() => { - jest.advanceTimersByTime(15 * 60 * 1000); - }); - - await waitFor(() => - expect(toast.warning).toHaveBeenCalledWith('sessionWarning'), - ); - - jest.useRealTimers(); - }); - - test('should handle error when revoking token fails', async () => { - const consoleErrorMock = jest.spyOn(console, 'error').mockImplementation(); - - const errorMocks = [ - { - request: { - query: GET_COMMUNITY_SESSION_TIMEOUT_DATA, - }, - result: { - data: { - getCommunityData: { - timeout: 30, - }, - }, - }, - delay: 1000, - }, - { - request: { - query: REVOKE_REFRESH_TOKEN, - }, - error: new Error('Failed to revoke refresh token'), - }, - ]; - - const { result } = renderHook(() => useSession(), { - wrapper: ({ children }: { children?: ReactNode }) => ( - - {children} - - ), - }); - - act(() => { - result.current.startSession(); - result.current.handleLogout(); - }); - - await waitFor(() => - expect(consoleErrorMock).toHaveBeenCalledWith( - 'Error revoking refresh token:', - expect.any(Error), - ), - ); - - consoleErrorMock.mockRestore(); - }); - - test('should set session timeout based on fetched data', async () => { - jest.spyOn(global, 'setTimeout'); - - const { result } = renderHook(() => useSession(), { - wrapper: ({ children }: { children?: ReactNode }) => ( - - {children} - - ), - }); - - act(() => { - result.current.startSession(); - }); - - expect(global.setTimeout).toHaveBeenCalled(); - }); - - test('should call errorHandler on query error', async () => { - const errorMocks = [ - { - request: { - query: GET_COMMUNITY_SESSION_TIMEOUT_DATA, - }, - error: new Error('An error occurred'), - }, - ]; - - const { result } = renderHook(() => useSession(), { - wrapper: ({ children }: { children?: ReactNode }) => ( - - {children} - - ), - }); - - act(() => { - result.current.startSession(); - }); - - await waitFor(() => expect(errorHandler).toHaveBeenCalled()); - }); - //dfghjkjhgfds - - test('should remove event listeners on endSession', async () => { - const { result } = renderHook(() => useSession(), { - wrapper: ({ children }: { children?: ReactNode }) => ( - - {children} - - ), - }); - - // Mock the removeEventListener functions for both window and document - const removeEventListenerMock = jest.fn(); - - // Temporarily replace the real methods with the mock - const originalWindowRemoveEventListener = window.removeEventListener; - const originalDocumentRemoveEventListener = document.removeEventListener; - - window.removeEventListener = removeEventListenerMock; - document.removeEventListener = removeEventListenerMock; - - // await waitForNextUpdate(); - - act(() => { - result.current.startSession(); - }); - - act(() => { - result.current.endSession(); - }); - - // Test that event listeners were removed - expect(removeEventListenerMock).toHaveBeenCalledWith( - 'mousemove', - expect.any(Function), - ); - expect(removeEventListenerMock).toHaveBeenCalledWith( - 'keydown', - expect.any(Function), - ); - expect(removeEventListenerMock).toHaveBeenCalledWith( - 'visibilitychange', - expect.any(Function), - ); - - // Restore the original removeEventListener functions - window.removeEventListener = originalWindowRemoveEventListener; - document.removeEventListener = originalDocumentRemoveEventListener; - }); - - test('should call initialize timers when session is still active when the user returns to the tab', async () => { - jest.useFakeTimers(); - jest.spyOn(global, 'setTimeout').mockImplementation(jest.fn()); - - const { result } = renderHook(() => useSession(), { - wrapper: ({ children }) => ( - - {children} - - ), - }); - - jest.advanceTimersByTime(1000); - - // Set initial visibility state to visible - Object.defineProperty(document, 'visibilityState', { - value: 'visible', - writable: true, - }); - - // Start the session - act(() => { - result.current.startSession(); - jest.advanceTimersByTime(10 * 60 * 1000); // Fast-forward - }); - - // Simulate the user leaving the tab (set visibility to hidden) - Object.defineProperty(document, 'visibilityState', { - value: 'hidden', - writable: true, - }); - - act(() => { - document.dispatchEvent(new Event('visibilitychange')); - }); - - // Fast-forward time by more than the session timeout - act(() => { - jest.advanceTimersByTime(5 * 60 * 1000); // Fast-forward - }); - - // Simulate the user returning to the tab - Object.defineProperty(document, 'visibilityState', { - value: 'visible', - writable: true, - }); - - act(() => { - document.dispatchEvent(new Event('visibilitychange')); - }); - - jest.advanceTimersByTime(1000); - - expect(global.setTimeout).toHaveBeenCalled(); - - // Restore real timers - jest.useRealTimers(); - }); - - test('should call handleLogout when session expires due to inactivity away from tab', async () => { - jest.useFakeTimers(); // Use fake timers to control time - - const { result } = renderHook(() => useSession(), { - wrapper: ({ children }) => ( - - {children} - - ), - }); - - jest.advanceTimersByTime(1000); - - // Set initial visibility state to visible - Object.defineProperty(document, 'visibilityState', { - value: 'visible', - writable: true, - }); - - // Start the session - act(() => { - result.current.startSession(); - jest.advanceTimersByTime(10 * 60 * 1000); // Fast-forward - }); - - // Simulate the user leaving the tab (set visibility to hidden) - Object.defineProperty(document, 'visibilityState', { - value: 'hidden', - writable: true, - }); - - act(() => { - document.dispatchEvent(new Event('visibilitychange')); - }); - - // Fast-forward time by more than the session timeout - act(() => { - jest.advanceTimersByTime(32 * 60 * 1000); // Fast-forward by 32 minutes - }); - - // Simulate the user returning to the tab - Object.defineProperty(document, 'visibilityState', { - value: 'visible', - writable: true, - }); - - act(() => { - document.dispatchEvent(new Event('visibilitychange')); - }); - - jest.advanceTimersByTime(250); - - await waitFor(() => { - expect(global.localStorage.clear).toHaveBeenCalled(); - expect(toast.warning).toHaveBeenCalledWith('sessionLogout', { - autoClose: false, - }); - }); - - // Restore real timers - jest.useRealTimers(); - }); - - test('should handle logout and revoke token', async () => { - jest.useFakeTimers(); - - const { result } = renderHook(() => useSession(), { - wrapper: ({ children }: { children?: ReactNode }) => ( - - {children} - - ), - }); - - act(() => { - result.current.startSession(); - result.current.handleLogout(); - }); - - await waitFor(() => { - expect(global.localStorage.clear).toHaveBeenCalled(); - expect(toast.warning).toHaveBeenCalledWith('sessionLogout', { - autoClose: false, - }); - }); - - jest.useRealTimers(); - }); -}); From 8e8cd3ce4be732b4d6ade1143f0851e1e482aef5 Mon Sep 17 00:00:00 2001 From: Amit Bora Date: Sat, 28 Dec 2024 21:04:14 +0530 Subject: [PATCH 08/11] Refactor: src/screens/BlockUser from Jest to Vitest (#2606) * Add BlockUser component tests and update package.json dependencies * Fix: Move @testing-library/dom to devDependencies * Add BlockUser component tests and update package.json dependencies * Fix: Move @testing-library/dom to devDependencies * fix: format fail --------- Co-authored-by: Vamshi Maskuri <117595548+varshith257@users.noreply.github.com> --- package-lock.json | 116 ++----- package.json | 1 + ...{BlockUser.test.tsx => BlockUser.spec.tsx} | 301 ++---------------- 3 files changed, 52 insertions(+), 366 deletions(-) rename src/screens/BlockUser/{BlockUser.test.tsx => BlockUser.spec.tsx} (52%) diff --git a/package-lock.json b/package-lock.json index 9c801aa1c0..7f115d04df 100644 --- a/package-lock.json +++ b/package-lock.json @@ -80,6 +80,7 @@ "@babel/preset-env": "^7.26.0", "@babel/preset-react": "^7.25.7", "@babel/preset-typescript": "^7.26.0", + "@testing-library/dom": "^10.4.0", "@testing-library/jest-dom": "^6.6.3", "@testing-library/react": "^16.0.1", "@testing-library/user-event": "^12.1.10", @@ -4048,17 +4049,6 @@ "node": ">=6.0.0" } }, - "node_modules/@jridgewell/source-map": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz", - "integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==", - "optional": true, - "peer": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" - } - }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", @@ -4610,6 +4600,7 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.0.tgz", "integrity": "sha512-i0GV1yJnm2n3Yq1qw6QrUrd/LI9bE8WEBOTtOkpCXHHdyN3TAGgqAK/DAT05z4fq2x04cARXt2pDmjWjL92iTQ==", + "dev": true, "hasInstallScript": true, "optional": true, "dependencies": { @@ -4648,6 +4639,7 @@ "cpu": [ "arm64" ], + "dev": true, "optional": true, "os": [ "android" @@ -4667,6 +4659,7 @@ "cpu": [ "arm64" ], + "dev": true, "optional": true, "os": [ "darwin" @@ -4686,6 +4679,7 @@ "cpu": [ "x64" ], + "dev": true, "optional": true, "os": [ "darwin" @@ -4705,6 +4699,7 @@ "cpu": [ "x64" ], + "dev": true, "optional": true, "os": [ "freebsd" @@ -4724,6 +4719,7 @@ "cpu": [ "arm" ], + "dev": true, "optional": true, "os": [ "linux" @@ -4743,6 +4739,7 @@ "cpu": [ "arm" ], + "dev": true, "optional": true, "os": [ "linux" @@ -4762,6 +4759,7 @@ "cpu": [ "arm64" ], + "dev": true, "optional": true, "os": [ "linux" @@ -4781,6 +4779,7 @@ "cpu": [ "arm64" ], + "dev": true, "optional": true, "os": [ "linux" @@ -4800,6 +4799,7 @@ "cpu": [ "x64" ], + "dev": true, "optional": true, "os": [ "linux" @@ -4819,6 +4819,7 @@ "cpu": [ "x64" ], + "dev": true, "optional": true, "os": [ "linux" @@ -4838,6 +4839,7 @@ "cpu": [ "arm64" ], + "dev": true, "optional": true, "os": [ "win32" @@ -4857,6 +4859,7 @@ "cpu": [ "ia32" ], + "dev": true, "optional": true, "os": [ "win32" @@ -4876,6 +4879,7 @@ "cpu": [ "x64" ], + "dev": true, "optional": true, "os": [ "win32" @@ -5891,7 +5895,7 @@ "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.0.tgz", "integrity": "sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==", "dev": true, - "peer": true, + "license": "MIT", "dependencies": { "@babel/code-frame": "^7.10.4", "@babel/runtime": "^7.12.5", @@ -5911,7 +5915,6 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, - "peer": true, "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -5928,7 +5931,6 @@ "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", "dev": true, - "peer": true, "dependencies": { "ansi-regex": "^5.0.1", "ansi-styles": "^5.0.0", @@ -5943,7 +5945,6 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, - "peer": true, "engines": { "node": ">=10" }, @@ -5955,8 +5956,7 @@ "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true, - "peer": true + "dev": true }, "node_modules/@testing-library/jest-dom": { "version": "6.6.3", @@ -6041,8 +6041,7 @@ "version": "5.0.4", "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", - "dev": true, - "peer": true + "dev": true }, "node_modules/@types/babel__core": { "version": "7.20.5", @@ -6125,18 +6124,6 @@ "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.3.tgz", "integrity": "sha512-2p6olUZ4w3s+07q3Tm2dbiMZy5pCDfYwtLXXHUnVzXgQlZ/OyPtUz6OL382BkOuGlLXqfT+wqv8Fw2v8/0geBw==" }, - "node_modules/@types/eslint": { - "version": "8.44.0", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.44.0.tgz", - "integrity": "sha512-gsF+c/0XOguWgaOgvFs+xnnRqt9GwgTvIks36WpE6ueeI4KCEHHd8K/CKHqhOqrJKsYH8m27kRzQEvWXAwXUTw==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "@types/estree": "*", - "@types/json-schema": "*" - } - }, "node_modules/@types/estree": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", @@ -9649,6 +9636,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", + "dev": true, "optional": true, "bin": { "detect-libc": "bin/detect-libc.js" @@ -9722,8 +9710,7 @@ "version": "0.5.16", "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", - "dev": true, - "peer": true + "dev": true }, "node_modules/dom-align": { "version": "1.12.4", @@ -9925,16 +9912,6 @@ "node": ">= 0.8" } }, - "node_modules/encoding": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", - "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", - "optional": true, - "peer": true, - "dependencies": { - "iconv-lite": "^0.6.2" - } - }, "node_modules/end-of-stream": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", @@ -12180,19 +12157,6 @@ "cross-fetch": "4.0.0" } }, - "node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "optional": true, - "peer": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/icss-utils": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", @@ -12260,7 +12224,7 @@ "version": "5.0.2", "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.0.2.tgz", "integrity": "sha512-1NU7hWZDkV7hJ4PJ9dur9gTNQ4ePNPN4k9/0YhwjzykTi/+3Q5pF93YU5QoVj8BuOnhLgaY8gs0U2pj4kSYVcw==", - "devOptional": true + "dev": true }, "node_modules/import-fresh": { "version": "3.3.0", @@ -15482,7 +15446,6 @@ "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", "dev": true, - "peer": true, "bin": { "lz-string": "bin/bin.js" } @@ -15942,6 +15905,7 @@ "version": "7.1.1", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", + "dev": true, "optional": true }, "node_modules/node-fetch": { @@ -19013,7 +18977,7 @@ "version": "1.80.7", "resolved": "https://registry.npmjs.org/sass/-/sass-1.80.7.tgz", "integrity": "sha512-MVWvN0u5meytrSjsU7AWsbhoXi1sc58zADXFllfZzbsBT1GHjjar6JwBINYPRrkx/zqnQ6uqbQuHgE95O+C+eQ==", - "devOptional": true, + "dev": true, "dependencies": { "chokidar": "^4.0.0", "immutable": "^5.0.2", @@ -19033,7 +18997,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.1.tgz", "integrity": "sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA==", - "devOptional": true, + "dev": true, "dependencies": { "readdirp": "^4.0.1" }, @@ -19048,7 +19012,7 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.0.2.tgz", "integrity": "sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA==", - "devOptional": true, + "dev": true, "engines": { "node": ">= 14.16.0" }, @@ -19377,7 +19341,7 @@ "version": "0.5.21", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "devOptional": true, + "dev": true, "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" @@ -19387,7 +19351,7 @@ "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "devOptional": true, + "dev": true, "engines": { "node": ">=0.10.0" } @@ -19815,32 +19779,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/terser": { - "version": "5.32.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.32.0.tgz", - "integrity": "sha512-v3Gtw3IzpBJ0ugkxEX8U0W6+TnPKRRCWGh1jC/iM/e3Ki5+qvO1L1EAZ56bZasc64aXHwRHNIQEzm6//i5cemQ==", - "optional": true, - "peer": true, - "dependencies": { - "@jridgewell/source-map": "^0.3.3", - "acorn": "^8.8.2", - "commander": "^2.20.0", - "source-map-support": "~0.5.20" - }, - "bin": { - "terser": "bin/terser" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/terser/node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "optional": true, - "peer": true - }, "node_modules/test-exclude": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", diff --git a/package.json b/package.json index 8e528c2ceb..257949ead6 100644 --- a/package.json +++ b/package.json @@ -120,6 +120,7 @@ "@testing-library/jest-dom": "^6.6.3", "@testing-library/react": "^16.0.1", "@testing-library/user-event": "^12.1.10", + "@testing-library/dom": "^10.4.0", "@types/inquirer": "^9.0.7", "@types/jest": "^26.0.24", "@types/js-cookie": "^3.0.6", diff --git a/src/screens/BlockUser/BlockUser.test.tsx b/src/screens/BlockUser/BlockUser.spec.tsx similarity index 52% rename from src/screens/BlockUser/BlockUser.test.tsx rename to src/screens/BlockUser/BlockUser.spec.tsx index c851470d9b..51d16a61f9 100644 --- a/src/screens/BlockUser/BlockUser.test.tsx +++ b/src/screens/BlockUser/BlockUser.spec.tsx @@ -1,4 +1,4 @@ -import React, { act } from 'react'; +import React from 'react'; import { MockedProvider } from '@apollo/react-testing'; import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; @@ -10,16 +10,15 @@ import { BLOCK_PAGE_MEMBER_LIST, ORGANIZATIONS_LIST, } from 'GraphQl/Queries/Queries'; -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 { store } from 'state/store'; import { StaticMockLink } from 'utils/StaticMockLink'; import i18nForTest from 'utils/i18nForTest'; import BlockUser from './BlockUser'; +import { vi, describe, beforeEach, test, expect } from 'vitest'; let userQueryCalled = false; @@ -241,94 +240,22 @@ const MOCKS = [ }, }, ]; -const MOCKS_EMPTY = [ - { - request: { - query: ORGANIZATIONS_LIST, - variables: { - id: 'orgid', - }, - }, - result: { - data: { - organizations: [ - { - _id: 'orgid', - image: '', - creator: { - firstName: 'firstName', - lastName: 'lastName', - email: 'email', - }, - name: 'name', - description: 'description', - location: 'location', - members: { - _id: 'id', - firstName: 'firstName', - lastName: 'lastName', - email: 'email', - }, - admins: { - _id: 'id', - firstName: 'firstName', - lastName: 'lastName', - email: 'email', - }, - membershipRequests: { - _id: 'id', - user: { - firstName: 'firstName', - lastName: 'lastName', - email: 'email', - }, - }, - blockedUsers: { - _id: 'id', - firstName: 'firstName', - lastName: 'lastName', - email: 'email', - }, - }, - ], - }, - }, - }, - - { - request: { - query: BLOCK_PAGE_MEMBER_LIST, - variables: { - firstName_contains: 'Peter', - lastName_contains: '', - orgId: 'orgid', - }, - }, - result: { - data: { - organizationsMemberConnection: { - edges: [], - }, - }, - }, - }, -]; const link = new StaticMockLink(MOCKS, true); -const link2 = new StaticMockLink(MOCKS_EMPTY, true); async function wait(ms = 500): Promise { - await act(() => { - return new Promise((resolve) => { - setTimeout(resolve, ms); - }); + await new Promise((resolve) => { + setTimeout(resolve, ms); }); } -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useParams: () => ({ orgId: 'orgid' }), -})); +vi.mock('react-router-dom', async (importOriginal) => { + const actual = await importOriginal(); + return { + ...(actual as object), + useParams: () => ({ orgId: 'orgid' }), + }; +}); describe('Testing Block/Unblock user screen', () => { beforeEach(() => { @@ -336,7 +263,7 @@ describe('Testing Block/Unblock user screen', () => { }); test('Components should be rendered properly', async () => { - window.location.assign('/blockuser/orgid'); + window.history.pushState({}, 'Test page', '/blockuser/orgid'); render( @@ -354,11 +281,11 @@ describe('Testing Block/Unblock user screen', () => { expect(screen.getByText('Search By First Name')).toBeInTheDocument(); - expect(window.location).toBeAt('/blockuser/orgid'); + expect(window.location.pathname).toBe('/blockuser/orgid'); }); test('Testing block user functionality', async () => { - window.location.assign('/blockuser/orgid'); + window.history.pushState({}, 'Test page', '/blockuser/orgid'); render( @@ -372,9 +299,7 @@ describe('Testing Block/Unblock user screen', () => { , ); - await act(async () => { - userEvent.click(screen.getByTestId('userFilter')); - }); + userEvent.click(screen.getByTestId('userFilter')); userEvent.click(screen.getByTestId('showMembers')); await wait(); @@ -387,11 +312,11 @@ describe('Testing Block/Unblock user screen', () => { expect(screen.getByTestId('blockUser123')).toBeInTheDocument(); expect(screen.getByTestId('unBlockUser456')).toBeInTheDocument(); - expect(window.location).toBeAt('/blockuser/orgid'); + expect(window.location.pathname).toBe('/blockuser/orgid'); }); test('Testing unblock user functionality', async () => { - window.location.assign('/blockuser/orgid'); + window.history.pushState({}, 'Test page', '/blockuser/orgid'); render( @@ -404,9 +329,7 @@ describe('Testing Block/Unblock user screen', () => { , ); - await act(async () => { - userEvent.click(screen.getByTestId('userFilter')); - }); + userEvent.click(screen.getByTestId('userFilter')); userEvent.click(screen.getByTestId('showMembers')); await wait(); @@ -420,11 +343,11 @@ describe('Testing Block/Unblock user screen', () => { expect(screen.getByTestId('blockUser123')).toBeInTheDocument(); expect(screen.getByTestId('unBlockUser456')).toBeInTheDocument(); - expect(window.location).toBeAt('/blockuser/orgid'); + expect(window.location.pathname).toBe('/blockuser/orgid'); }); test('Testing First Name Filter', async () => { - window.location.assign('/blockuser/orgid'); + window.history.pushState({}, 'Test page', '/blockuser/orgid'); render( @@ -437,9 +360,7 @@ describe('Testing Block/Unblock user screen', () => { , ); - await act(async () => { - userEvent.click(screen.getByTestId('userFilter')); - }); + userEvent.click(screen.getByTestId('userFilter')); userEvent.click(screen.getByTestId('showMembers')); await wait(); @@ -448,9 +369,7 @@ describe('Testing Block/Unblock user screen', () => { expect(screen.getByText('Sam Smith')).toBeInTheDocument(); // Open Dropdown - await act(async () => { - userEvent.click(screen.getByTestId('nameFilter')); - }); + userEvent.click(screen.getByTestId('nameFilter')); // Select option and enter first name userEvent.click(screen.getByTestId('searchByFirstName')); const firstNameInput = screen.getByPlaceholderText(/Search by First Name/i); @@ -461,11 +380,11 @@ describe('Testing Block/Unblock user screen', () => { expect(screen.getByText('John Doe')).toBeInTheDocument(); expect(screen.queryByText('Sam Smith')).not.toBeInTheDocument(); - expect(window.location).toBeAt('/blockuser/orgid'); + expect(window.location.pathname).toBe('/blockuser/orgid'); }); test('Testing Last Name Filter', async () => { - window.location.assign('/blockuser/orgid'); + window.history.pushState({}, 'Test page', '/blockuser/orgid'); render( @@ -479,178 +398,6 @@ describe('Testing Block/Unblock user screen', () => { , ); - await act(async () => { - userEvent.click(screen.getByTestId('userFilter')); - }); - userEvent.click(screen.getByTestId('showMembers')); - - await wait(); - - expect(screen.getByText('John Doe')).toBeInTheDocument(); - expect(screen.getByText('Sam Smith')).toBeInTheDocument(); - - // Open Dropdown - await act(async () => { - userEvent.click(screen.getByTestId('nameFilter')); - }); - // Select option and enter last name - userEvent.click(screen.getByTestId('searchByLastName')); - const lastNameInput = screen.getByPlaceholderText(/Search by Last Name/i); - userEvent.type(lastNameInput, 'doe{enter}'); - - await wait(700); - - expect(lastNameInput).toHaveValue('doe'); - expect(screen.getByText('John Doe')).toBeInTheDocument(); - expect(screen.queryByText('Sam Smith')).not.toBeInTheDocument(); - expect(window.location).toBeAt('/blockuser/orgid'); - }); - - test('Testing No Spammers Present', async () => { - window.location.assign('/blockuser/orgid'); - render( - - - - - - - - - , - ); - - await wait(); - expect(screen.getByText(/No spammer found/i)).toBeInTheDocument(); - expect(window.location).toBeAt('/blockuser/orgid'); - }); - - test('Testing All Members', async () => { - window.location.assign('/blockuser/orgid'); - - render( - - - - - - - - - - , - ); - await wait(); - await act(async () => { - userEvent.click(screen.getByTestId('userFilter')); - }); - userEvent.click(screen.getByTestId('showMembers')); - - await wait(700); - - expect(screen.getByTestId(/userFilter/i)).toHaveTextContent('All Members'); - expect(screen.getByText('John Doe')).toBeInTheDocument(); - expect(screen.getByText('Sam Smith')).toBeInTheDocument(); - - expect(window.location).toBeAt('/blockuser/orgid'); - }); - - test('Testing Blocked Users', async () => { - window.location.assign('/blockuser/orgid'); - - render( - - - - - - - - - - , - ); - - await act(async () => { - userEvent.click(screen.getByTestId('userFilter')); - }); - - userEvent.click(screen.getByTestId('showBlockedMembers')); - await wait(); - - expect(screen.getByText('John Doe')).toBeInTheDocument(); - expect(screen.queryByText('Sam Smith')).not.toBeInTheDocument(); - - expect(window.location).toBeAt('/blockuser/orgid'); - }); - - test('Testing table data getting rendered', async () => { - window.location.assign('/orglist/orgid'); - const link = new StaticMockLink(MOCKS, true); - render( - - - - - - - - - , - ); - await act(async () => { - userEvent.click(screen.getByTestId('userFilter')); - }); - userEvent.click(screen.getByTestId('showMembers')); - - await wait(); - - expect(screen.getByTestId(/userList/)).toBeInTheDocument(); - expect(screen.getAllByText('Block/Unblock')).toHaveLength(1); - expect(screen.getByText('John Doe')).toBeInTheDocument(); - expect(screen.getByText('Sam Smith')).toBeInTheDocument(); - }); - - test('Testing No Results Found', async () => { - window.location.assign('/blockuser/orgid'); - render( - - - - - - - - - , - ); - - const input = screen.getByPlaceholderText('Search By First Name'); - await act(async () => { - userEvent.type(input, 'Peter{enter}'); - }); - await wait(700); - expect( - screen.getByText(`No results found for "Peter"`), - ).toBeInTheDocument(); - expect(window.location).toBeAt('/blockuser/orgid'); - }); - - test('Testing Search functionality', async () => { - window.location.assign('/blockuser/orgid'); - - render( - - - - - - - - - - , - ); await wait(); const searchBar = screen.getByTestId(/searchByName/i); const searchBtn = screen.getByTestId(/searchBtn/i); From 21687ee110d8ec92859855873d57a9e13bbe7199 Mon Sep 17 00:00:00 2001 From: Mohamed Rehan <77732921+mohamedrehan1@users.noreply.github.com> Date: Sat, 28 Dec 2024 17:42:20 +0200 Subject: [PATCH 09/11] Refactor CSS in src/components/EventManagement/EventAttendance/EventStatistics.tsx (#2993) --- .../EventAttendance/EventStatistics.tsx | 44 +++++-------------- src/style/app.module.css | 37 ++++++++++++++++ 2 files changed, 47 insertions(+), 34 deletions(-) diff --git a/src/components/EventManagement/EventAttendance/EventStatistics.tsx b/src/components/EventManagement/EventAttendance/EventStatistics.tsx index 686ad049fa..9136f7c0b1 100644 --- a/src/components/EventManagement/EventAttendance/EventStatistics.tsx +++ b/src/components/EventManagement/EventAttendance/EventStatistics.tsx @@ -30,6 +30,7 @@ import type { InterfaceEvent, InterfaceRecurringEvent, } from './InterfaceEvents'; +import styles from '../../../style/app.module.css'; ChartJS.register( CategoryScale, LinearScale, @@ -376,34 +377,25 @@ export const AttendanceStatisticsModal: React.FC< id="pdf-content" >
{isEventRecurring ? (

Trends

@@ -455,23 +447,13 @@ export const AttendanceStatisticsModal: React.FC<
) : (
-

+

{statistics.totalMembers}

Attendance Count

@@ -530,13 +512,7 @@ export const AttendanceStatisticsModal: React.FC< }} />

Demography

diff --git a/src/style/app.module.css b/src/style/app.module.css index 9480b80d20..668e41e446 100644 --- a/src/style/app.module.css +++ b/src/style/app.module.css @@ -3481,3 +3481,40 @@ button[data-testid='createPostBtn'] { opacity: 1; } } + +.attendance-modal .borderRightGreen { + border-right: 1px solid green; +} +.attendance-modal .positionedTopRight { + top: 10px; + right: 15px; + z-index: 1; +} +.attendance-modal .topRightCorner { + position: absolute; + right: 0; + top: 0; + border-bottom-left-radius: 8px; +} +.attendance-modal .bottomRightCorner { + position: absolute; + right: 0; + bottom: 0; + border-top-left-radius: 12px; +} +.attendance-modal .topLeftCorner { + position: absolute; + left: 0; + top: 0; + border-bottom-right-radius: 8px; +} +.attendance-modal .largeBoldText { + font-size: 80px; + font-weight: 400; +} +.attendance-modal .paddingBottom30 { + padding-bottom: 30px; +} +.attendance-modal .paddingBottom2Rem { + padding-bottom: 2rem; +} From 61007fc1c2a07e7e882ab63184c4d9a1df210b98 Mon Sep 17 00:00:00 2001 From: Peter Harrison <16875803+palisadoes@users.noreply.github.com> Date: Sat, 28 Dec 2024 08:05:29 -0800 Subject: [PATCH 10/11] Update pull-request.yml --- .github/workflows/pull-request.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index abd6775fb5..95572a6d81 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -104,6 +104,7 @@ jobs: src/style/** schema.graphql package.json + package-lock.json tsconfig.json .gitignore .eslintrc.json From c9292d1d68313817151ff47dd8a463a65995e637 Mon Sep 17 00:00:00 2001 From: Suyash Mishra Date: Sat, 28 Dec 2024 21:54:58 +0530 Subject: [PATCH 11/11] Fixing the failure of husky pre-commit script. (#2999) * test commit * test commit * Changing the import for waitFor and screen from @testing-library/react to @testing-library/dom * removing test-commit * resolving conflicts * fixing the package.json conflict * excluding unecessary changes in the package-lock.json --- src/screens/UserPortal/Volunteer/VolunteerManagement.test.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/screens/UserPortal/Volunteer/VolunteerManagement.test.tsx b/src/screens/UserPortal/Volunteer/VolunteerManagement.test.tsx index 65d2d082a7..80ac0df833 100644 --- a/src/screens/UserPortal/Volunteer/VolunteerManagement.test.tsx +++ b/src/screens/UserPortal/Volunteer/VolunteerManagement.test.tsx @@ -1,6 +1,7 @@ import React from 'react'; import type { RenderResult } from '@testing-library/react'; -import { render, screen, waitFor } from '@testing-library/react'; +import { screen, waitFor } from '@testing-library/dom'; +import { render } from '@testing-library/react'; import { MockedProvider } from '@apollo/react-testing'; import { I18nextProvider } from 'react-i18next'; import i18n from 'utils/i18nForTest';