diff --git a/src/QueryProvider.tsx b/src/QueryProvider.tsx index 7ad9be1b63..e1fda8b698 100644 --- a/src/QueryProvider.tsx +++ b/src/QueryProvider.tsx @@ -2,15 +2,19 @@ import { type ReactNode } from 'react' import { QueryClientProvider } from '@tanstack/react-query' import { ReactQueryDevtools } from '@tanstack/react-query-devtools' -import { queryClient } from '~/plugins/queryClient' +import { queryClient, testQueryClient } from '~/plugins/queryClient' type QueryProviderProps = { children: ReactNode + testMode?: boolean } -const QueryProvider: React.FC = ({ children }) => { +const QueryProvider: React.FC = ({ + children, + testMode = false +}) => { return ( - + {children} diff --git a/src/components/active-students/ActiveStudentsBlock.tsx b/src/components/active-students/ActiveStudentsBlock.tsx index 1fcbe3cdfc..b90c36b9de 100644 --- a/src/components/active-students/ActiveStudentsBlock.tsx +++ b/src/components/active-students/ActiveStudentsBlock.tsx @@ -32,6 +32,17 @@ const ActiveStudentsBlock = () => { } }) + const activeStudents = data?.items.map((cooperation) => ( + + )) + if (isLoading) { return } @@ -70,16 +81,6 @@ const ActiveStudentsBlock = () => { ) - const activeStudents = data.items.map((cooperation) => ( - - )) return ( <> {t('activeStudents.title')} diff --git a/src/constants/translations/en/offer-details-page.json b/src/constants/translations/en/offer-details-page.json index 2ba14095a7..d20e89ce7b 100644 --- a/src/constants/translations/en/offer-details-page.json +++ b/src/constants/translations/en/offer-details-page.json @@ -4,12 +4,12 @@ "description": "Send a Request to Create a Cooperation", "inputs": { "level": "Choose the appropriate level of tutoring you require.", - "info": "Ask the questions you have, describe your learning needs or specify your preferred teaching approach." + "additionalInfo": "Ask the questions you have, describe your learning needs or specify your preferred teaching approach." }, "labels": { "level": "Your required level", "preferredPrice": "Set your preferred price for the lesson. Keep in mind that choosing a lower or higher price may affect tutor availability.", - "info": "Additional information" + "additionalInfo": "Additional information" }, "successMessage": "Request for cooperation sent successfully" }, @@ -18,7 +18,6 @@ "student": "Offer details", "tutor": "Offer details" }, - "description": { "student": "Here, you can access all the essential details about the offer you've selected. This page includes details about the chosen offer. Take a moment to review this information and make an informed decision about your tutoring needs.", "tutor": "Here, you can access all the essential details about the offer you've selected. This page includes details about the chosen offer. Take a moment to review this information and make an informed decision about your tutoring needs." diff --git a/src/constants/translations/uk/offer-details-page.json b/src/constants/translations/uk/offer-details-page.json index 75452431c9..17b07e1e35 100644 --- a/src/constants/translations/uk/offer-details-page.json +++ b/src/constants/translations/uk/offer-details-page.json @@ -4,12 +4,12 @@ "description": "Надіслати запит на створення співпраці", "inputs": { "level": "Виберіть відповідний рівень, який вам потрібен.", - "info": "Задайте свої запитання, опишіть свої потреби, або вкажіть бажаний підхід до викладання." + "additionalInfo": "Задайте свої запитання, опишіть свої потреби, або вкажіть бажаний підхід до викладання." }, "labels": { "level": "Ваш рівень", "preferredPrice": "Встановіть бажану ціну за урок. Майте на увазі, що вибір нижчої або вищої ціни може вплинути на доступність репетитора.", - "info": "Додаткова інформація" + "additionalInfo": "Додаткова інформація" }, "successMessage": "Запит на співпрацю надіслано успішно" }, @@ -18,7 +18,6 @@ "student": "Деталі пропозиції", "tutor": "Деталі пропозиції" }, - "description": { "student": "Тут ви можете отримати доступ до всіх важливих деталей про вибрану пропозицію. На цій сторінці міститься інформація про вибрану пропозицію. Знайдіть час, щоб переглянути цю інформацію та прийняти обґрунтоване рішення щодо ваших потреб у репетиторстві.", "tutor": "Тут ви можете отримати доступ до всіх важливих деталей про вибрану пропозицію. На цій сторінці міститься інформація про вибрану пропозицію. Знайдіть час, щоб переглянути цю інформацію та прийняти обґрунтоване рішення щодо ваших потреб у репетиторстві." diff --git a/src/containers/my-cooperations/accept-cooperation-modal/AcceptCooperationModal.tsx b/src/containers/my-cooperations/accept-cooperation-modal/AcceptCooperationModal.tsx index 904a8be2ef..c7a687a36f 100644 --- a/src/containers/my-cooperations/accept-cooperation-modal/AcceptCooperationModal.tsx +++ b/src/containers/my-cooperations/accept-cooperation-modal/AcceptCooperationModal.tsx @@ -28,6 +28,7 @@ import { import { snackbarVariants } from '~/constants' import { styles } from '~/containers/my-cooperations/accept-cooperation-modal/AcceptCooperation.styles' import useSnackbarAlert from '~/hooks/use-snackbar-alert' +import { useAppSelector } from '~/hooks/use-redux' interface AcceptCooperationModalProps { cooperation: Cooperation @@ -41,26 +42,25 @@ const AcceptCooperationModal: React.FC = ({ const { closeModal } = useModalContext() const { checkConfirmation } = useConfirm() const { handleAlert, handleErrorAlert } = useSnackbarAlert() - const [minPrice, maxPrice] = minMaxPrice(cooperation.offer.price, 0.25) + const [minPrice, maxPrice] = minMaxPrice(cooperation.price, 0.25) + const { userRole } = useAppSelector((state) => state.appMain) - const needAction = cooperation.user.role !== cooperation.needAction.role + const needAction = userRole === cooperation.needAction.role - const handleUpdateCooperation = useCallback( - (params: Omit) => { - return cooperationService.updateCooperation({ - _id: cooperation._id, - ...params - }) - }, - [cooperation._id] - ) + const handleUpdateCooperation = ( + params?: Omit + ) => + cooperationService.updateCooperation({ + _id: cooperation._id, + ...params + }) const handleUpdateOffer = useCallback( () => - OfferService.updateOfferWithBaseService(cooperation.offer._id, { + OfferService.updateOfferWithBaseService(cooperation.offer, { enrolledUsers: [] }), - [cooperation.offer._id] + [cooperation.offer] ) const onResponse = () => { @@ -193,7 +193,7 @@ const AcceptCooperationModal: React.FC = ({ title={t('cooperationsPage.acceptModal.level')} /> diff --git a/src/containers/my-cooperations/cooperation-card/CooperationCard.tsx b/src/containers/my-cooperations/cooperation-card/CooperationCard.tsx index a5529046b6..86d0f9caad 100644 --- a/src/containers/my-cooperations/cooperation-card/CooperationCard.tsx +++ b/src/containers/my-cooperations/cooperation-card/CooperationCard.tsx @@ -28,19 +28,18 @@ const CooperationCard: FC = ({ sx }) => { const { t } = useTranslation() - const { user, offer, updatedAt, proficiencyLevel, price } = cooperation + const { user, updatedAt, proficiencyLevel, price, status, needAction } = + cooperation const { userRole } = useAppSelector((state) => state.appMain) const roleBasedStatus = - cooperation.needAction.role === userRole + needAction.role === userRole ? StatusEnum.NeedAction : StatusEnum.RequestToClose const cooperationStatus = - cooperation.status === StatusEnum.RequestToClose - ? roleBasedStatus - : cooperation.status + status === StatusEnum.RequestToClose ? roleBasedStatus : cooperation.status return ( @@ -51,7 +50,7 @@ const CooperationCard: FC = ({ firstName={user.firstName} lastName={user.lastName} photo={user.photo} - role={user.role} + role={user.role[0]} sx={styles.userProfileInfo} /> @@ -64,12 +63,12 @@ const CooperationCard: FC = ({ - {cooperation.offer.title} + {cooperation.title} ) } diff --git a/src/containers/my-cooperations/cooperation-details/CooperationDetails.tsx b/src/containers/my-cooperations/cooperation-details/CooperationDetails.tsx index c11de4a4cc..b70e709604 100644 --- a/src/containers/my-cooperations/cooperation-details/CooperationDetails.tsx +++ b/src/containers/my-cooperations/cooperation-details/CooperationDetails.tsx @@ -82,10 +82,7 @@ const CooperationDetails = () => { isError } = useQuery({ queryFn: getCooperation, - queryKey: ['cooperation', id], - options: { - staleTime: Infinity - } + queryKey: ['cooperation', id] }) useEffect(() => { diff --git a/src/containers/my-cooperations/cooperations-container/CooperationContainer.constants.tsx b/src/containers/my-cooperations/cooperations-container/CooperationContainer.constants.tsx index 714ba99ea2..8ea2bc093c 100644 --- a/src/containers/my-cooperations/cooperations-container/CooperationContainer.constants.tsx +++ b/src/containers/my-cooperations/cooperations-container/CooperationContainer.constants.tsx @@ -25,7 +25,7 @@ export const columns: TableColumn[] = [ firstName={item.user.firstName} lastName={item.user.lastName} photo={item.user.photo} - role={item.user.role} + role={item.user.role[0]} sx={styles.profileInfo} /> ) @@ -34,7 +34,7 @@ export const columns: TableColumn[] = [ { label: 'cooperationsPage.tableHeaders.title', calculatedCellValue: (item: Cooperation) => ( - {item.offer.title} + {item.title} ) }, { @@ -42,7 +42,7 @@ export const columns: TableColumn[] = [ calculatedCellValue: (item: Cooperation) => ( ) @@ -63,7 +63,7 @@ export const columns: TableColumn[] = [ label: 'cooperationsPage.tableHeaders.status', calculatedCellValue: ({ user, needAction, status }: Cooperation) => { const cooperationStatus = - user.role !== needAction?.role && status === StatusEnum.Pending + user.role[0] !== needAction.role && status === StatusEnum.Pending ? StatusEnum.NeedAction : status return diff --git a/src/containers/my-cooperations/my-cooperations-details/MyCooperationsDetails.tsx b/src/containers/my-cooperations/my-cooperations-details/MyCooperationsDetails.tsx index 86ea7dbd27..f0a1954a1b 100644 --- a/src/containers/my-cooperations/my-cooperations-details/MyCooperationsDetails.tsx +++ b/src/containers/my-cooperations/my-cooperations-details/MyCooperationsDetails.tsx @@ -76,43 +76,56 @@ const MyCooperationsDetails = () => { } const displayedUser = - cooperationDetails.initiator._id === userId + cooperationDetails.user._id === userId ? cooperationDetails.receiver : cooperationDetails.initiator + const isTutor = displayedUser.role[0] === UserRoleEnum.Tutor - const [displayedUserRole] = displayedUser.role - - const { offer, price } = cooperationDetails - - const CategoryIcon = getCategoryIcon(offer.category.appearance.icon) - const categoryColor = getValidatedHexColor(offer.category.appearance.color) + const CategoryIcon = getCategoryIcon( + cooperationDetails.category.appearance.icon + ) + const categoryColor = getValidatedHexColor( + cooperationDetails.category.appearance.color + ) const onClickOpenChat = () => setChatInfo({ author: displayedUser, - authorRole: displayedUserRole as + authorRole: displayedUser.role[0] as | UserRoleEnum.Student | UserRoleEnum.Tutor, - chatId: offer.chatId, + chatId: cooperationDetails.chatId, updateInfo: () => {} }) - const languages = offer.languages?.map((item: string) => ( + const languages = cooperationDetails.languages?.map((item: string) => ( {item} )) + const userImageSrc = import.meta.env + .VITE_APP_IMG_USER_URL as `${string}/:fileName` + const avatarSrc = displayedUser.photo && + userImageSrc && getFullUrl({ - pathname: import.meta.env.VITE_APP_IMG_USER_URL as `${string}/:fileName`, + pathname: userImageSrc, parameters: { fileName: displayedUser.photo } }) + const cooperationCompletion = userRole === UserRoleEnum.Tutor && ( + + ) + return ( @@ -122,96 +135,110 @@ const MyCooperationsDetails = () => { {t('cooperationDetailsPage.title')} - {offer.title} + {cooperationDetails.title} {t( - displayedUserRole === UserRoleEnum.Tutor + isTutor ? 'cooperationDetailsPage.tutor' : 'cooperationDetailsPage.student' )} - - + {t('cooperationDetailsPage.details')} + + + + {t('cooperationDetailsPage.title')} + + {cooperationDetails.title} + + {t( + displayedUser.role[0] === UserRoleEnum.Tutor + ? 'cooperationDetailsPage.tutor' + : 'cooperationDetailsPage.student' + )} + + + + + + {displayedUser.firstName} {displayedUser.lastName} + + + {displayedUser.professionalSummary} + + + + + + + + + {t('cooperationDetailsPage.tutoringSubject')} + + + + + {cooperationDetails.category.name} + + + + + {t('cooperationDetailsPage.aboutCooperation')} + + - - {displayedUser.firstName} {displayedUser.lastName} + + {t('cooperationDetailsPage.tutoringLanguages')} - - {displayedUser.professionalSummary} + {languages} + + {t('cooperationDetailsPage.pricing')} + {`${cooperationDetails.price} UAH/hour`} - - - - - - - {t('cooperationDetailsPage.tutoringSubject')} - - - - - {offer.category.name} - - + {cooperationCompletion} - - {t('cooperationDetailsPage.aboutCooperation')} - - - - {t('cooperationDetailsPage.tutoringLanguages')} - - {languages} - - {t('cooperationDetailsPage.pricing')} - - {`${price} UAH/hour`} - ) } diff --git a/src/containers/offer-details/enroll-offer/EnrollOffer.tsx b/src/containers/offer-details/enroll-offer/EnrollOffer.tsx index 4c801ba939..593dcdd102 100644 --- a/src/containers/offer-details/enroll-offer/EnrollOffer.tsx +++ b/src/containers/offer-details/enroll-offer/EnrollOffer.tsx @@ -46,7 +46,7 @@ const EnrollOffer: React.FC = ({ offer, enrollOffer }) => { const [minPrice, maxPrice] = minMaxPrice(offer.price, 0.25) - const handleResponseError = (error: ResponseError) => { + const handleResponseError = (error?: ResponseError) => { dispatch( openAlert({ severity: snackbarVariants.error, @@ -108,7 +108,11 @@ const EnrollOffer: React.FC = ({ offer, enrollOffer }) => { ...data, receiver: offer.author._id, receiverRole: offer.authorRole, - offer: offer._id + offer: offer._id, + subject: offer.subject._id, + category: offer.category._id, + description: offer.description, + languages: offer.languages }) } } @@ -163,12 +167,12 @@ const EnrollOffer: React.FC = ({ offer, enrollOffer }) => { {errors.additionalInfo && ( diff --git a/src/pages/bookmarked-offers/BookmarkedOffers.tsx b/src/pages/bookmarked-offers/BookmarkedOffers.tsx index 0bd9161d6d..a386aadc8c 100644 --- a/src/pages/bookmarked-offers/BookmarkedOffers.tsx +++ b/src/pages/bookmarked-offers/BookmarkedOffers.tsx @@ -65,10 +65,7 @@ const BookmarkedOffers = () => { isError } = useQuery({ queryKey: ['bookmarks', filters, searchParams.toString()], - queryFn: getBookmarkedOffers, - options: { - staleTime: Infinity - } + queryFn: getBookmarkedOffers }) useEffect(() => { diff --git a/src/plugins/queryClient.ts b/src/plugins/queryClient.ts index 9f6926016a..9ed1ec24af 100644 --- a/src/plugins/queryClient.ts +++ b/src/plugins/queryClient.ts @@ -1,3 +1,13 @@ import { QueryClient } from '@tanstack/react-query' export const queryClient = new QueryClient() +export const testQueryClient = new QueryClient({ + defaultOptions: { + queries: { + retry: false, + refetchOnWindowFocus: false, + refetchOnReconnect: false, + staleTime: 0 + } + } +}) diff --git a/src/types/common/enums/common.enums.ts b/src/types/common/enums/common.enums.ts index 23775860f2..e3035dd4de 100644 --- a/src/types/common/enums/common.enums.ts +++ b/src/types/common/enums/common.enums.ts @@ -145,3 +145,9 @@ export enum SortByEnum { highestRating = 'highestRating', lowestRating = 'lowestRating' } + +export enum NeedActionTypeEnum { + WaitingForAnswer = 'waiting for answer', + WaitingForApproval = 'waiting for approval', + Price = 'price' +} diff --git a/src/types/cooperation/interfaces/cooperation.interface.ts b/src/types/cooperation/interfaces/cooperation.interface.ts index f086045962..2160626f66 100644 --- a/src/types/cooperation/interfaces/cooperation.interface.ts +++ b/src/types/cooperation/interfaces/cooperation.interface.ts @@ -1,57 +1,83 @@ import { - type CommonEntityFields, - type ProficiencyLevelEnum, - type StatusEnum, - type EnrollOfferForm, - type Offer, - type UserResponse, + CommonEntityFields, + ProficiencyLevelEnum, + StatusEnum, + EnrollOfferForm, + Offer, + UserResponse, UserRoleEnum, - type CourseSection + SubjectInterface, + CategoryInterface, + CourseSection, + LanguagesEnum, + NeedActionTypeEnum } from '~/types' -export enum NeedActionTypeEnum { - WaitingForAnswer = 'waiting for answer', - WaitingForApproval = 'waiting for approval', - Price = 'price' -} - export interface Cooperation extends CommonEntityFields { - offer: Pick< - Offer, - | 'subject' - | 'title' - | 'category' - | 'price' - | '_id' - | 'chatId' - | 'languages' - | 'author' - | 'proficiencyLevel' - | 'description' - > - user: Pick & { - role: UserRoleEnum.Tutor | UserRoleEnum.Student + offer: string + subject: Pick + category: CategoryInterface + description: string + languages: LanguagesEnum[] + user: Pick< + UserResponse, + 'firstName' | 'lastName' | 'photo' | '_id' | 'professionalSummary' + > & { + role: UserRoleEnum[] } + receiver: UserResponse + receiverRole: UserRoleEnum initiator: UserResponse - initiatorRole: UserRoleEnum.Tutor | UserRoleEnum.Student + initiatorRole: UserRoleEnum title: Offer['title'] price: Offer['price'] - proficiencyLevel: ProficiencyLevelEnum - chatId: string + proficiencyLevel: ProficiencyLevelEnum[] status: StatusEnum + completedResourcesPercentage: number + chatId: string needAction: { role: UserRoleEnum.Tutor | UserRoleEnum.Student type: NeedActionTypeEnum messages: string[] } - receiver: UserResponse - receiverRole: UserRoleEnum.Tutor | UserRoleEnum.Student sections: CourseSection[] - completedResourcesPercentage: number + createdAt: string + updatedAt: string +} + +export interface MyCooperationDetails { + offer: Pick + price: number + title: string + description: string + receiver: UserResponse + receiverRole: UserRoleEnum + languages: LanguagesEnum[] + chatId: string + author: UserResponse + subject: Pick + category: CategoryInterface + proficiencyLevel: ProficiencyLevelEnum[] + initiator: UserResponse + initiatorRole: UserRoleEnum + status: StatusEnum + needAction: { + role: UserRoleEnum.Tutor | UserRoleEnum.Student + type: NeedActionTypeEnum + messages: string[] + } + createdAt: string + updatedAt: string } export interface CreateCooperationsParams extends EnrollOfferForm { + title: string offer: string receiver: string - receiverRole: UserRoleEnum.Tutor | UserRoleEnum.Student + receiverRole: UserRoleEnum + subject: string + category: string + proficiencyLevel: ProficiencyLevelEnum + description: string + languages: LanguagesEnum[] } diff --git a/src/types/offer-details/interfaces/offerDetails.interfaces.ts b/src/types/offer-details/interfaces/offerDetails.interfaces.ts index 0cd1c8d834..d178678627 100644 --- a/src/types/offer-details/interfaces/offerDetails.interfaces.ts +++ b/src/types/offer-details/interfaces/offerDetails.interfaces.ts @@ -2,6 +2,6 @@ import { Offer, ProficiencyLevelEnum } from '~/types' export interface EnrollOfferForm extends Pick { proficiencyLevel: ProficiencyLevelEnum - additionalInfo?: string title: string + additionalInfo?: string } diff --git a/tests/test-constants.js b/tests/test-constants.js new file mode 100644 index 0000000000..e9651f4a17 --- /dev/null +++ b/tests/test-constants.js @@ -0,0 +1,132 @@ +export const getCooperationByIdMockResponse = { + _id: '672fd85a48371231a70da39f', + price: 500, + proficiencyLevel: ['Beginner'], + status: 'waiting for approval', + needAction: { + role: 'tutor', + type: 'price', + messages: [] + }, + title: 'Cooperation title', + initiator: { + _id: '66fd88ddc84a281ab2f2de93', + firstName: 'John', + lastName: 'Doe', + photo: '1726302583778-pexels-vanessa-garcia-6326377.jpg', + professionalSummary: 'I have 5 years of experience', + role: ['tutor'] + }, + receiver: { + _id: '66b0aecdadd1fe775238c7d5', + firstName: 'Jane', + lastName: 'Smith', + photo: 'receiver-photo.jpg', + professionalSummary: 'Experienced student in web development', + role: ['student'] + }, + offer: '66ec53d40d9d9983a9525421', + description: 'Cooperation description', + languages: ['English'], + subject: { name: 'Web Development' }, + category: { + appearance: { + icon: 'StarRoundedIcon', + color: '#607D8B' + } + }, + sections: [ + { + _id: '66ec53d40d9d9983a952543', + title: 'Section 1', + description: 'Content of section 1', + resourses: [] + }, + { + _id: '66ec53d40d9d9983a952544', + title: 'Section 2', + description: 'Content of section 2', + resourses: [] + } + ], + user: { + _id: '66fd88ddc84a281ab2f2de93', + firstName: 'John', + lastName: 'Doe', + photo: '1726302583778-pexels-vanessa-garcia-6326377.jpg', + professionalSummary: 'I have 5 years of experience', + role: ['tutor'] + }, + createdAt: '2024-09-12T11:28:34.397Z', + updatedAt: '2024-09-12T11:28:34.397Z' +} + +export const mockedCooperations = { + items: [ + { + _id: '66ec53d40d9d9983a952541', + title: 'Cooperation title', + offer: '66ec53d40d9d9983a952542', + receiver: { + _id: '6750ca3f466f194485b1e178', + firstName: 'Alice', + lastName: 'Johnson', + photo: 'alice-photo.jpg', + professionalSummary: 'Passionate about learning', + role: ['tutor'] + }, + receiverRole: 'tutor', + initiator: { + _id: '6736f6cec333d2e67f3710dc', + firstName: 'Bob', + lastName: 'Williams', + photo: 'bob-photo.jpg', + professionalSummary: 'Experienced mentor', + role: ['student'] + }, + initiatorRole: 'student', + subject: { name: 'Web Development' }, + category: { + appearance: { + icon: 'StarRoundedIcon', + color: '#607D8B' + } + }, + description: 'Cooperation description', + languages: ['English'], + user: { + _id: '6565f781b2b2c701e9183cb8', + firstName: 'Jane', + lastName: 'Doe', + photo: 'https://images.unsplash.com/photo-1570295999919-56ceb5ecca61', + professionalSummary: 'Experienced in online collaboration', + role: ['student'] + }, + price: 1800, + proficiencyLevel: ['Beginner'], + status: 'pending', + needAction: { + role: 'student', + type: 'price', + messages: [] + }, + sections: [ + { + _id: '66ec53d40d9d9983a952543', + title: 'Section 1', + description: 'Content of section 1', + resourses: [] + }, + { + _id: '66ec53d40d9d9983a952544', + title: 'Section 2', + description: 'Content of section 2', + resourses: [] + } + ], + createdAt: '2024-09-12T11:28:34.397Z', + updatedAt: '2024-09-12T11:28:34.397Z' + } + ], + count: 1 +} diff --git a/tests/test-utils.jsx b/tests/test-utils.jsx index 9f62507ec0..7e5353eec9 100644 --- a/tests/test-utils.jsx +++ b/tests/test-utils.jsx @@ -40,7 +40,7 @@ export const renderWithProviders = ( - + {children} diff --git a/tests/unit/components/active-students/ActiveStudentsBlock.spec.jsx b/tests/unit/components/active-students/ActiveStudentsBlock.spec.jsx index 269059f7dd..d8797028a6 100644 --- a/tests/unit/components/active-students/ActiveStudentsBlock.spec.jsx +++ b/tests/unit/components/active-students/ActiveStudentsBlock.spec.jsx @@ -2,9 +2,10 @@ import { screen, fireEvent } from '@testing-library/react' import { authRoutes } from '~/router/constants/authRoutes' import { renderWithProviders } from '~tests/test-utils' +import { mockedCooperations as testCooperations } from '~tests/test-constants' import ActiveStudentsBlock from '~/components/active-students/ActiveStudentsBlock' import useQuery from '~/hooks/use-query' -import { vi } from 'vitest' +import { describe, vi } from 'vitest' vi.mock('~/hooks/use-query') @@ -17,45 +18,36 @@ vi.mock('react-router-dom', async () => ({ const mockedCooperations = [ { - _id: 'cooperation1', - offer: { - subject: { - name: 'Violin' - } - }, + ...testCooperations.items[0], + _id: '66ec53d40d9d9983a952541', + subject: { name: 'Web Development' }, user: { - _id: 'student1', - firstName: 'FirstNameStudent1', - lastName: 'LastNameStudent1', - photo: 'Student1Photo' + _id: '6565f781b2b2c701e9183cb8', + firstName: 'John', + lastName: 'Doe', + photo: 'https://images.unsplash.com/photo-1570295999919-56ceb5ecca61' } }, { - _id: 'cooperation2', - offer: { - subject: { - name: 'Piano' - } - }, + ...testCooperations.items[0], + _id: '66ec53d40d9d9983a952542', + subject: { name: 'UI/UX Design' }, user: { - _id: 'student2', - firstName: 'FirstNameStudent2', - lastName: 'LastNameStudent2', - photo: 'Student2Photo' + _id: '6565f781b2b2c701e9183cb8', + firstName: 'Jane', + lastName: 'Doe', + photo: 'https://images.unsplash.com/photo-1570295999919-56ceb5ecca61' } }, { - _id: 'cooperation3', - offer: { - subject: { - name: 'Web Development' - } - }, + ...testCooperations.items[0], + _id: '66ec53d40d9d9983a952543', + subject: { name: 'Testing' }, user: { - _id: 'student3', - firstName: 'FirstNameStudent3', - lastName: 'LastNameStudent3', - photo: 'Student3Photo' + _id: '6565f781b2b2c701e9183cb8', + firstName: 'Jack', + lastName: 'Black', + photo: 'https://images.unsplash.com/photo-1570295999919-56ceb5ecca61' } } ] @@ -64,14 +56,14 @@ const mockedData = { isLoading: false, data: { items: mockedCooperations, - count: 1 + count: 3 }, refetch: vi.fn() } const mockedLoading = { isLoading: true, - response: null, + data: null, refetch: vi.fn() } @@ -99,17 +91,53 @@ const errorCooperationsMock = { refetch: vi.fn() } -describe('ActiveStudentsBlock', () => { - useQuery.mockImplementation(() => mockedData) +describe('ActiveStudentsBlock Loader', () => { + it('should render Loader when loading', () => { + useQuery.mockImplementation(() => mockedLoading) + renderWithProviders() - it('should render active students', () => { + expect(screen.getByTestId('loader')).toBeInTheDocument() + }) +}) + +describe('ActiveStudentsBlock with No Cooperations', () => { + beforeEach(() => { + useQuery.mockImplementation(() => noCooperationsMock) + renderWithProviders() + }) + afterEach(() => { + vi.clearAllMocks() + }) + + it('should render add student button when no active cooperations available', () => { + const addStudent = screen.getByTestId('addStudent') + expect(addStudent).toBeInTheDocument() + }) + + it('should navigate to /categories/subjects/find-offers on add student button click', () => { + const showMoreButton = screen.getByTestId('addStudent') + fireEvent.click(showMoreButton) + + expect(navigateMock).toHaveBeenCalledWith(authRoutes.findOffers.path) + }) +}) + +describe('ActiveStudentsBlock with Mocked Cooperations', () => { + beforeEach(() => { + useQuery.mockImplementation(() => mockedData) renderWithProviders() + }) + + afterEach(() => { + vi.clearAllMocks() + }) + it('should render active students', () => { for (const cooperation of mockedCooperations) { const fullName = screen.getByText( `${cooperation.user.firstName} ${cooperation.user.lastName}` ) - const subjectName = screen.getByText(cooperation.offer.subject.name) + const subjectName = screen.getByText(cooperation.subject.name) expect(fullName).toBeInTheDocument() expect(subjectName).toBeInTheDocument() @@ -117,8 +145,6 @@ describe('ActiveStudentsBlock', () => { }) it('should navigate to /my-cooperations on Show More button click', () => { - renderWithProviders() - const showMoreButton = screen.getByTestId('showMore') fireEvent.click(showMoreButton) @@ -126,35 +152,19 @@ describe('ActiveStudentsBlock', () => { authRoutes.cooperationDetails.path ) }) +}) - it('should render Loader when loading', () => { - useQuery.mockImplementation(() => mockedLoading) - renderWithProviders() - - expect(screen.getByTestId('loader')).toBeInTheDocument() - }) - - it('should render add student button when no active cooperations available', () => { - useQuery.mockImplementation(() => noCooperationsMock) +describe('ActiveStudentsBlock with No Cooperations Error', () => { + beforeEach(() => { + useQuery.mockImplementation(() => errorCooperationsMock) renderWithProviders() - const addStudent = screen.getByTestId('addStudent') - expect(addStudent).toBeInTheDocument() }) - it('should navigate to /categories/subjects/find-offers on add student button click', () => { - useQuery.mockImplementation(() => noCooperationsMock) - renderWithProviders() - - const showMoreButton = screen.getByTestId('addStudent') - fireEvent.click(showMoreButton) - - expect(navigateMock).toHaveBeenCalledWith(authRoutes.findOffers.path) + afterEach(() => { + vi.clearAllMocks() }) it('should not render on error', () => { - useQuery.mockImplementation(() => errorCooperationsMock) - renderWithProviders() - expect(screen.queryByText('activeStudents.title')).not.toBeInTheDocument() }) }) diff --git a/tests/unit/containers/my-cooperations/accept-cooperation-modal/AcceptCooperationModal.spec.jsx b/tests/unit/containers/my-cooperations/accept-cooperation-modal/AcceptCooperationModal.spec.jsx index b1cf109a44..a92579ac83 100644 --- a/tests/unit/containers/my-cooperations/accept-cooperation-modal/AcceptCooperationModal.spec.jsx +++ b/tests/unit/containers/my-cooperations/accept-cooperation-modal/AcceptCooperationModal.spec.jsx @@ -1,3 +1,4 @@ +import { vi } from 'vitest' import { fireEvent, screen } from '@testing-library/react' import AcceptCooperationModal from '~/containers/my-cooperations/accept-cooperation-modal/AcceptCooperationModal' import { @@ -7,8 +8,7 @@ import { } from '~tests/test-utils' import { URLs } from '~/constants/request' import useBreakpoints from '~/hooks/use-breakpoints' -import { mockedCoop } from '~tests/unit/containers/my-cooperations/MyCooperations.spec.constants' -import { vi } from 'vitest' +import { mockedCooperations } from '~tests/test-constants' vi.mock('~/hooks/use-debounce', () => ({ useDebounce: (callback) => callback @@ -18,9 +18,11 @@ vi.mock('~/hooks/use-breakpoints') useBreakpoints.mockImplementation(() => ({ isDesktop: true })) const preloadedState = { - appMain: { userRole: 'tutor' } + appMain: { userRole: 'student' } } +const mockedCoop = mockedCooperations.items[0] + describe('AcceptCooperationModal component ', () => { beforeEach(() => { mockAxiosClient diff --git a/tests/unit/containers/my-cooperations/cooperation-card/CooperationCard.spec.jsx b/tests/unit/containers/my-cooperations/cooperation-card/CooperationCard.spec.jsx index bd90146ef5..48d4fbc289 100644 --- a/tests/unit/containers/my-cooperations/cooperation-card/CooperationCard.spec.jsx +++ b/tests/unit/containers/my-cooperations/cooperation-card/CooperationCard.spec.jsx @@ -1,7 +1,9 @@ import { screen } from '@testing-library/react' import CooperationCard from '~/containers/my-cooperations/cooperation-card/CooperationCard' import { renderWithProviders } from '~tests/test-utils' -import { mockedCoop } from '~tests/unit/containers/my-cooperations/MyCooperations.spec.constants' +import { mockedCooperations } from '~tests/test-constants' + +const mockedCoop = mockedCooperations.items[0] const preloadedState = { appMain: { userRole: 'tutor' }, diff --git a/tests/unit/containers/my-cooperations/cooperation-container/CooperationContainer.spec.jsx b/tests/unit/containers/my-cooperations/cooperation-container/CooperationContainer.spec.jsx index 4552728ac0..fe234aa846 100644 --- a/tests/unit/containers/my-cooperations/cooperation-container/CooperationContainer.spec.jsx +++ b/tests/unit/containers/my-cooperations/cooperation-container/CooperationContainer.spec.jsx @@ -1,10 +1,12 @@ +import { vi } from 'vitest' import { screen } from '@testing-library/react' import { renderWithProviders } from '~tests/test-utils' import CooperationContainer from '~/containers/my-cooperations/cooperations-container/CooperationContainer' -import { mockedCoop } from '~tests/unit/containers/my-cooperations/MyCooperations.spec.constants' -import { afterEach, vi } from 'vitest' -import userEvent from '@testing-library/user-event' import { StatusEnum } from '~/types' +import userEvent from '@testing-library/user-event' +import { mockedCooperations } from '~tests/test-constants' + +const mockedCoop = mockedCooperations.items[0] const filterOptionsMock = { filters: { @@ -70,7 +72,7 @@ describe('CooperationContainer component ', () => { { preloadedState } ) - const card = screen.getByText(activeCoop.offer.subject.name) + const card = screen.getByText(activeCoop.subject.name) await userEvent.click(card) expect(navigateMock).toHaveBeenCalledWith(`./${activeCoop._id}`) @@ -86,7 +88,7 @@ describe('CooperationContainer component ', () => { { preloadedState } ) - const card = screen.getByText(activeCoop.offer.subject.name) + const card = screen.getByText(activeCoop.subject.name) await userEvent.click(card) expect(navigateMock).toHaveBeenCalledWith(`./${activeCoop._id}`) @@ -103,7 +105,7 @@ describe('CooperationContainer component ', () => { { preloadedState } ) - const card = screen.getByText(pendingCoop.offer.subject.name) + const card = screen.getByText(pendingCoop.subject.name) await userEvent.click(card) expect(mockOpenModal).toHaveBeenCalled() diff --git a/tests/unit/containers/my-cooperations/cooperation-details/CooperationDetails.spec.jsx b/tests/unit/containers/my-cooperations/cooperation-details/CooperationDetails.spec.jsx index 711f3a4ccc..cd490e56a2 100644 --- a/tests/unit/containers/my-cooperations/cooperation-details/CooperationDetails.spec.jsx +++ b/tests/unit/containers/my-cooperations/cooperation-details/CooperationDetails.spec.jsx @@ -1,156 +1,65 @@ import { screen, fireEvent } from '@testing-library/react' import { renderWithProviders, mockAxiosClient } from '~tests/test-utils' +import { getCooperationByIdMockResponse as cooperationMock } from '~tests/test-constants' import { URLs } from '~/constants/request' -import { queryClient } from '~/plugins/queryClient' import CooperationDetails from '~/containers/my-cooperations/cooperation-details/CooperationDetails' -import { vi } from 'vitest' +import { afterEach, describe, vi } from 'vitest' -const cooperationID = '123456789' -const userId = '33t5ffe34' +const cooperationId = cooperationMock._id vi.mock('react-router-dom', async () => { const actual = await vi.importActual('react-router-dom') return { ...actual, useParams: () => ({ - id: cooperationID + id: cooperationId }) } }) -const mockStateTutor = { - appMain: { userId: userId, userRole: 'tutor' } -} - -const mockStateStudent = { - appMain: { userId: userId, userRole: 'student' } -} - -const cooperationData = { - _id: '123456789', - price: 100, - proficiencyLevel: 'Beginner', +const coopClosureMock = { + ...cooperationMock, status: 'request to close', - title: 'Cooperation title', - offer: { - title: 'Title', - description: 'Description', - languages: ['Ukrainian', 'English'], - author: { - firstName: 'Michael', - lastName: 'Scarn', - photo: '1701182621626.jpg', - professionalSummary: 'Agent' - }, - subject: { - name: 'Algebra' - }, - category: { - name: 'Mathematics', - appearance: { - color: '#1234' - } - }, - proficiencyLevel: ['INTERMEDIATE'] - }, - user: { - _id: '123456', - firstName: 'Name', - lastName: 'Surname', - role: 'tutor' - }, - sections: [ - { - title: 'module 1', - description: 'description for module 1', - resources: [ - { - resource: { - _id: '67d089447c1856f0d205dfe2', - author: '67d020fbcda203e190670036', - fileName: 'Apoptosis review.pdf', - link: '1741719874044-Apoptosis review.pdf', - size: 3959441, - category: null, - resourceType: 'attachment' - }, - resourceType: 'attachment', - availability: { - status: 'closed', - date: null - }, - completionStatus: 'completed' - }, - { - resource: { - _id: '67d089a57c1856f0d205e00b', - author: '67d020fbcda203e190670036', - fileName: 'Apoptosis review.pdf', - link: '1741719874044-Apoptosis review.pdf', - size: 3959441, - category: null, - resourceType: 'attachment', - isDuplicate: true - }, - resourceType: 'attachment', - availability: { - status: 'open', - date: null - }, - completionStatus: 'completed' - } - ], - _id: '67d0250ccda203e190670173' - } - ], - createdAt: '2024-01-12T11:28:34.397Z', - updatedAt: '2024-01-12T11:28:34.397Z', - completedResourcesPercentage: 50 -} - -const OPPOSITE_USER_DECIDED_TO_CLOSE_COOPERATION = { - ...cooperationData, needAction: { role: 'tutor', type: 'waiting for approval', - messages: [] - }, - initiator: { _id: userId, role: ['tutor'] }, - receiver: { _id: '123123', role: ['student'] } + messages: [ + 'Please confirm the price of 500 USD for the cooperation.', + 'The price is acceptable for me.' + ] + } } -const OPPOSITE_USER_DECLINED_TO_CLOSE_COOPERATION = { - ...cooperationData, +const acceptCoopClosureMockWfAns = { + ...cooperationMock, + status: 'request to close', needAction: { - role: 'student', + role: 'tutor', type: 'waiting for answer', - messages: ['reason1'] - }, - initiator: { _id: userId, role: ['student'] }, - receiver: { _id: '123123', role: ['tutor'] } + messages: [] + } } -const USER_SUBMITTED_AN_ANSWER = { - ...cooperationData, +const acceptCoopClosureMockWfAppr = { + ...cooperationMock, + status: 'request to close', needAction: { - role: 'student', + role: 'tutor', type: 'waiting for approval', - messages: ['message1'] - }, - initiator: { _id: userId, role: ['tutor'] }, - receiver: { _id: '123123', role: ['student'] } + messages: [ + 'Please confirm the price of 500 USD for the cooperation.', + 'The price is acceptable for me.' + ] + } } -const USER_SUBMITTED_A_REASON_FOR_DECLINING = { - ...cooperationData, - needAction: { - role: 'tutor', - type: 'waiting for answer', - messages: ['reason1'] - }, - initiator: { _id: userId, role: ['student'] }, - receiver: { _id: '123123', role: ['tutor'] } +const mockStateTutor = { + appMain: { userId: cooperationMock.initiator._id, userRole: 'tutor' } +} + +const mockStateStudent = { + appMain: { userId: cooperationMock.receiver._id, userRole: 'student' } } vi.mock( @@ -163,20 +72,19 @@ vi.mock( ) describe('CooperationDetails', () => { - beforeAll(() => { + beforeEach(() => { mockAxiosClient - .onGet(URLs.cooperations.getById.replace(':id', cooperationID)) - .reply(200, OPPOSITE_USER_DECIDED_TO_CLOSE_COOPERATION) - }) + .onGet(URLs.cooperations.getById.replace(':id', cooperationId)) + .reply(200, cooperationMock) - beforeEach(() => { renderWithProviders(, { preloadedState: mockStateTutor }) }) - afterAll(() => { + afterEach(() => { mockAxiosClient.reset() + vi.clearAllMocks() }) it('should render details page', async () => { @@ -188,10 +96,8 @@ describe('CooperationDetails', () => { }) it('should show cooperation status and title', () => { - const title = screen.getByText( - OPPOSITE_USER_DECIDED_TO_CLOSE_COOPERATION.title - ) - const statusChip = screen.getByText('need action') + const title = screen.getByText(cooperationMock.title) + const statusChip = screen.getByText(cooperationMock.status) expect(title).toBeInTheDocument() expect(statusChip).toBeInTheDocument() @@ -226,85 +132,82 @@ describe('CooperationDetails', () => { expect(cooperationNotes).not.toBeInTheDocument() }) - - it('should render AcceptCooperationClosing modal when needAction type is "waiting for approval" and role equals users role', () => { - const cooperationClosingModal = screen.getByText( - 'titles.acceptCooperationClosing' - ) - expect(cooperationClosingModal).toBeInTheDocument() - }) - - it('should render progress bar with predefined value', () => { - const progressBar = screen.getByText( - '50% cooperationDetailsPage.progressBar.completed' - ) - expect(progressBar).toBeInTheDocument() - }) }) -describe('CooperationClosureDeclinedBanner without answer being submitted', () => { - beforeAll(() => { - mockAxiosClient.reset() +describe('CooperationDetails with AcceptCooperationClosing modal', () => { + beforeEach(() => { mockAxiosClient - .onGet(URLs.cooperations.getById.replace(':id', cooperationID)) - .reply(200, OPPOSITE_USER_DECLINED_TO_CLOSE_COOPERATION) - }) + .onGet(URLs.cooperations.getById.replace(':id', cooperationId)) + .reply(200, acceptCoopClosureMockWfAppr) - beforeEach(() => { - queryClient.clear() renderWithProviders(, { - preloadedState: mockStateStudent + preloadedState: mockStateTutor }) }) - it('should render CooperationClosureDeclinedBanner when needAction type is "waiting for answer" and role equals users role', async () => { + afterEach(() => { + mockAxiosClient.reset() + vi.clearAllMocks() + }) + + it('should render AcceptCooperationClosing modal when needAction type is "waiting for approval" and role equals users role', async () => { const cooperationClosingModal = await screen.findByText( - 'titles.cooperationClosureDeclined' + 'titles.acceptCooperationClosing' ) expect(cooperationClosingModal).toBeInTheDocument() }) }) -describe('CooperationClosureDeclinedBanner with submitted answer', () => { - beforeAll(() => { - mockAxiosClient.reset() +describe('AcceptCooperationClosing modal with submitted answer', () => { + beforeEach(() => { mockAxiosClient - .onGet(URLs.cooperations.getById.replace(':id', cooperationID)) - .reply(200, USER_SUBMITTED_AN_ANSWER) - }) + .onGet(URLs.cooperations.getById.replace(':id', cooperationId)) + .reply(200, acceptCoopClosureMockWfAns) - beforeEach(() => { - queryClient.clear() renderWithProviders(, { preloadedState: mockStateTutor }) }) - it('should render CooperationClosureDeclinedBanner when needAction type is "waiting for approval" and role is not the same as users role', async () => { - const cooperationClosingModal = await screen.findByText( - 'titles.cooperationClosureDeclined' + afterEach(() => { + mockAxiosClient.reset() + vi.clearAllMocks() + }) + + it('should render AcceptCooperationClosing modal when needAction type is "waiting for answer" and role is not the same as users role', async () => { + const cooperationClosingModal = screen.getByText( + 'titles.acceptCooperationClosing' ) expect(cooperationClosingModal).toBeInTheDocument() }) }) -describe('AcceptCooperationClosing modal with submitted answer', () => { - beforeAll(() => { - mockAxiosClient.reset() +describe('CooperationClosureDeclinedBanner without answer being submitted', () => { + beforeEach(() => { mockAxiosClient - .onGet(URLs.cooperations.getById.replace(':id', cooperationID)) - .reply(200, USER_SUBMITTED_A_REASON_FOR_DECLINING) - }) + .onGet(URLs.cooperations.getById.replace(':id', coopClosureMock._id)) + .reply(200, coopClosureMock) - beforeEach(() => { renderWithProviders(, { preloadedState: mockStateStudent }) }) - it('should render AcceptCooperationClosing modal when needAction type is "waiting for answer" and role is not the same as users role', async () => { - const cooperationClosingModal = screen.getByText( - 'titles.acceptCooperationClosing' + afterEach(() => { + mockAxiosClient.reset() + vi.clearAllMocks() + }) + + it('should render CooperationClosureDeclinedBanner when needAction type is "waiting for answer" and role equals users role', async () => { + const cooperationClosingModal = await screen.findByText( + 'titles.cooperationClosureDeclined' + ) + + expect(cooperationClosingModal).toBeInTheDocument() + }) + it('should render CooperationClosureDeclinedBanner when needAction type is "waiting for approval" and role is not the same as users role', async () => { + const cooperationClosingModal = await screen.findByText( + 'titles.cooperationClosureDeclined' ) expect(cooperationClosingModal).toBeInTheDocument() }) diff --git a/tests/unit/containers/my-cooperations/my-cooperations-details/MyCooperationsDetails.spec.jsx b/tests/unit/containers/my-cooperations/my-cooperations-details/MyCooperationsDetails.spec.jsx index 50ef36c364..8647b1431c 100644 --- a/tests/unit/containers/my-cooperations/my-cooperations-details/MyCooperationsDetails.spec.jsx +++ b/tests/unit/containers/my-cooperations/my-cooperations-details/MyCooperationsDetails.spec.jsx @@ -1,36 +1,13 @@ import { renderWithProviders, mockAxiosClient } from '~tests/test-utils' +import { getCooperationByIdMockResponse } from '~tests/test-constants' import { URLs } from '~/constants/request' import MyCooperationsDetails from '~/containers/my-cooperations/my-cooperations-details/MyCooperationsDetails.tsx' import { screen, fireEvent } from '@testing-library/react' -import { vi } from 'vitest' - -const mockedOffer = { - initiator: { _id: 'initiatorId', role: ['tutor'] }, - receiver: { _id: 'receiverId', role: ['student'] }, - offer: { - title: 'Title', - description: 'Description', - languages: ['Ukrainian', 'English'], - author: { - firstName: 'Michael', - lastName: 'Scarn', - photo: '1701182621626.jpg', - professionalSummary: 'Agent' - }, - subject: { - name: 'Algebra' - }, - category: { - name: 'Mathematics', - appearance: { - color: '#1234' - } - }, - proficiencyLevel: ['INTERMEDIATE'] - }, - price: 100 -} +import { expect, vi } from 'vitest' + +const mockedCooperation = { ...getCooperationByIdMockResponse } +mockedCooperation.languages = ['Ukrainian', 'English'] const mockChatContext = { setChatInfo: vi.fn() @@ -44,22 +21,28 @@ describe('MyCooperationsDetails component', () => { beforeEach(() => { mockAxiosClient .onGet(URLs.cooperations.getById.replace(':id', '')) - .reply(200, mockedOffer) + .reply(200, mockedCooperation) renderWithProviders() }) + afterEach(() => { + vi.clearAllMocks() + }) + it('should render title', async () => { - const title = await screen.findByText('cooperationDetailsPage.details') + const title = await screen.findAllByText('cooperationDetailsPage.details') - expect(title).toBeInTheDocument() + expect(title).toHaveLength(2) + expect(...title).toBeInTheDocument() }) it('should render languages', async () => { const language1 = await screen.findByText('Ukrainian') - const language2 = await screen.findByText('English') + expect(language1).toBeInTheDocument() - expect(language1, language2).toBeInTheDocument() + const language2 = await screen.findByText('English') + expect(language2).toBeInTheDocument() }) it('should open chat after clicking on chat-button', async () => { @@ -81,7 +64,7 @@ describe('MyCooperationsDetails component', () => { expect(profileButton).toBeInTheDocument() expect(profileButton.parentElement.href).toContain( - `/user/${mockedOffer.initiator._id}?role=${mockedOffer.initiator.role[0]}` + `/user/${mockedCooperation.initiator._id}?role=${mockedCooperation.initiator.role[0]}` ) }) }) diff --git a/tests/unit/containers/offer-details/enroll-offer/EnrollOffer.spec.jsx b/tests/unit/containers/offer-details/enroll-offer/EnrollOffer.spec.jsx index 2e46c204a5..718c1735e3 100644 --- a/tests/unit/containers/offer-details/enroll-offer/EnrollOffer.spec.jsx +++ b/tests/unit/containers/offer-details/enroll-offer/EnrollOffer.spec.jsx @@ -24,19 +24,19 @@ describe('EnrollOffer', () => { it('should change proficiencyLevel', () => { const newLevel = 'Intermediate' - const levelSelect = screen.getAllByTestId('app-select')[0] + const levelSelect = screen.getByTestId('app-select') fireEvent.change(levelSelect, { target: { value: newLevel } }) - expect(levelSelect.value).toBe(newLevel) + expect(levelSelect.value.split(',')).toContain(newLevel) }) it('should display error message', () => { const newAdditionalInfo = 'Some text' const additionalInfoInput = screen.getByLabelText( - 'offerDetailsPage.enrollOffer.labels.info' + 'offerDetailsPage.enrollOffer.labels.additionalInfo' ) fireEvent.change(additionalInfoInput, { target: { value: newAdditionalInfo } diff --git a/tests/unit/pages/my-cooperations/MyCooperations.spec.jsx b/tests/unit/pages/my-cooperations/MyCooperations.spec.jsx index ed1c146fd1..71f1b894f4 100644 --- a/tests/unit/pages/my-cooperations/MyCooperations.spec.jsx +++ b/tests/unit/pages/my-cooperations/MyCooperations.spec.jsx @@ -1,42 +1,15 @@ import { fireEvent, screen } from '@testing-library/react' import { renderWithProviders, mockAxiosClient } from '~tests/test-utils' +import { mockedCooperations } from '~tests/test-constants' import { URLs } from '~/constants/request' import MyCooperations from '~/pages/my-cooperations/MyCooperations' -const MOCK_RESPONSE = { - items: [ - { - _id: 'id', - offer: { - description: - 'Hello. There are many variations of passages of There are many variations of passages of... Hello. There are many variations of passages of There are many variations of passages of... Hello. There are many variations of passages of There are many variations of passages of... Hello. There are many variations of passages of There are many variations of passages of... Hello. There are many variations of passages of There are many variations of passages of... Hello. There are many variations of passages of There are many variations of passages of... Hello. There are many variations of passages of There are many variations of passages of... ', - subject: { _id: 'id', name: 'Quantum Mechanics' } - }, - user: { - firstName: 'Kathryn', - lastName: 'Murphy', - photo: - 'https://images.unsplash.com/photo-1570295999919-56ceb5ecca61?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=880&q=80' - }, - price: 1800, - proficiencyLevel: 'Beginner', - status: 'pending', - needAction: { - role: 'student', - type: 'price', - messages: [] - } - } - ], - count: 0 -} - describe('MyCooperations', () => { beforeAll(() => { mockAxiosClient .onGet(new RegExp(URLs.cooperations.get)) - .reply(200, MOCK_RESPONSE) + .reply(200, mockedCooperations) }) beforeEach(() => { @@ -50,7 +23,7 @@ describe('MyCooperations', () => { }) it('should render opposite user name on cooperation card', async () => { - const activeTab = screen.queryByText('Kathryn Murphy') + const activeTab = screen.getByText('Jane Doe') expect(activeTab).toBeInTheDocument() }) diff --git a/tests/unit/pages/offer-details/OfferDetails.spec.constants.js b/tests/unit/pages/offer-details/OfferDetails.spec.constants.js index c83a6a9b91..cf5a194949 100644 --- a/tests/unit/pages/offer-details/OfferDetails.spec.constants.js +++ b/tests/unit/pages/offer-details/OfferDetails.spec.constants.js @@ -1,13 +1,7 @@ export const mockOffer = { _id: '6480c14f5ca047c53c2ab784', price: 55, - proficiencyLevel: [ - 'Beginner', - 'Intermediate', - 'Advanced', - 'Test Preparation', - 'Professional' - ], + proficiencyLevel: ['Beginner', 'Intermediate'], title: 'test', description: 'testtesttesttesttesttesttesttest', languages: ['Ukrainian'], diff --git a/tests/unit/pages/offer-details/OfferDetails.spec.jsx b/tests/unit/pages/offer-details/OfferDetails.spec.jsx index ea78fb740d..07e61b4786 100644 --- a/tests/unit/pages/offer-details/OfferDetails.spec.jsx +++ b/tests/unit/pages/offer-details/OfferDetails.spec.jsx @@ -78,14 +78,24 @@ describe('OfferDetails on desktop', () => { const { description, proficiencyLevel, - author: { firstName, lastName } + title, + author: { firstName, lastName, averageRating } } = mockOffer const descriptionElement = await screen.findByText(description) const nameElement = screen.getByText(`${firstName} ${lastName[0]}.`) - const proficiency = screen.getByText(proficiencyLevel[2]) + const authorAvgRatingElement = screen.getByText( + averageRating.tutor.toString() + ) + const titleElement = screen.getByText(title) + + proficiencyLevel.forEach((level) => { + const proficiency = screen.getByText(level) + expect(proficiency).toBeInTheDocument() + }) + expect(authorAvgRatingElement).toBeInTheDocument() + expect(titleElement).toBeInTheDocument() expect(descriptionElement).toBeInTheDocument() - expect(proficiency).toBeInTheDocument() expect(nameElement).toBeInTheDocument() }) @@ -232,34 +242,6 @@ describe('Offer details with student role', () => { }) }) -describe('OfferDetails on mobile', () => { - const mobileData = { - isLaptopAndAbove: false, - isMobile: true, - isTablet: false - } - beforeEach(() => { - useBreakpoints.mockImplementation(() => mobileData) - renderWithProviders(, { - preloadedState: mockState - }) - }) - - it('should display the offer details correctly', async () => { - const authorAvgRating = await screen.findByText( - mockOffer.author.averageRating.tutor - ) - const title = screen.getByText(mockOffer.title) - const name = screen.getByText( - `${mockOffer.author.firstName} ${mockOffer.author.lastName}` - ) - - expect(authorAvgRating).toBeInTheDocument() - expect(title).toBeInTheDocument() - expect(name).toBeInTheDocument() - }) -}) - describe('Offer details with student role', () => { beforeEach(() => { renderWithProviders(, {