diff --git a/src/constants/translations/en/cooperations-page.json b/src/constants/translations/en/cooperations-page.json index 10f3a307c2..764243b5e3 100644 --- a/src/constants/translations/en/cooperations-page.json +++ b/src/constants/translations/en/cooperations-page.json @@ -74,10 +74,10 @@ }, "notes": { "noteText": "Note text...", - "privateSetting": "Make it private", - "noteMsg": "Note was successfully created" + "privateSetting": "Make it private" }, "modalMessages": { + "successCreation": "Note was successfully created", "successDeletion": "Note was deleted successfully", "successDuplication": "Note was successfully duplicated", "successUpdating": "Note was successfully updated", diff --git a/src/constants/translations/uk/cooperations-page.json b/src/constants/translations/uk/cooperations-page.json index 91c257df88..7363272b3c 100644 --- a/src/constants/translations/uk/cooperations-page.json +++ b/src/constants/translations/uk/cooperations-page.json @@ -75,10 +75,10 @@ }, "notes": { "noteText": "Текст нотатки...", - "privateSetting": "Зробити приватною", - "noteMsg": "Нотатку було успішно створено" + "privateSetting": "Зробити приватною" }, "modalMessages": { + "successCreation": "Нотатку було успішно створено", "successDeletion": "Нотатку успішно видалено", "successDuplication": "Нотатку було успішно продубльовано", "successUpdating": "Нотатку було успішно оновлено", diff --git a/src/containers/my-cooperations/cooperation-notes/CooperationNotes.tsx b/src/containers/my-cooperations/cooperation-notes/CooperationNotes.tsx index 1fe46c11b5..2b026d862a 100644 --- a/src/containers/my-cooperations/cooperation-notes/CooperationNotes.tsx +++ b/src/containers/my-cooperations/cooperation-notes/CooperationNotes.tsx @@ -1,4 +1,4 @@ -import { useState, useCallback } from 'react' +import { useState, useCallback, useEffect } from 'react' import { useParams } from 'react-router-dom' import { useTranslation } from 'react-i18next' import Box from '@mui/material/Box' @@ -6,219 +6,170 @@ import Divider from '@mui/material/Divider' import Typography from '@mui/material/Typography' import AddIcon from '@mui/icons-material/Add' -import useAxios from '~/hooks/use-axios' import useConfirm from '~/hooks/use-confirm' import { CooperationNotesService } from '~/services/cooperation-service' import CreateOrEditNote from '~/containers/my-cooperations/cooperation-notes/create-or-edit-note/CreateOrEditNote' import NoteView from '~/containers/my-cooperations/cooperation-notes/note-view/NoteView' import Loader from '~/components/loader/Loader' -import { noteNotFoundError } from '~/containers/my-cooperations/cooperation-notes/CooperationNotes.constants' -import { snackbarVariants, defaultResponses } from '~/constants' +import { snackbarVariants } from '~/constants' import { styles } from '~/containers/my-cooperations/cooperation-notes/CooperationNotes.styles' import { - CreateOrUpdateNoteParams, + type CreateOrUpdateNoteParams, PositionEnum, - ErrorResponse, - NoteResponse + type NoteResponse } from '~/types' -import { useAppDispatch } from '~/hooks/use-redux' -import { openAlert } from '~/redux/features/snackbarSlice' -import { getErrorMessage } from '~/utils/error-with-message' -import { getErrorKey } from '~/utils/get-error-key' +import useSnackbarAlert from '~/hooks/use-snackbar-alert' +import useQuery from '~/hooks/use-query' +import useMutation from '~/hooks/use-mutation' +import { noteActionMap, NoteAction } from './constant' -const CooperationNotes = () => { +const CooperationNotes: React.FC = () => { const { t } = useTranslation() - const { id = '' } = useParams() - const dispatch = useAppDispatch() + const { id: cooperationId = '' } = useParams() const { openDialog } = useConfirm() const [open, setOpen] = useState(false) const [editableItemId, setEditableItemId] = useState('') + const { handleAlert, handleErrorAlert } = useSnackbarAlert() - const onResponseError = useCallback( - (error?: ErrorResponse) => { - const errorKey = getErrorKey(error) - - dispatch( - openAlert({ - severity: snackbarVariants.error, - message: error - ? { - text: errorKey, - options: { - message: getErrorMessage(error.message) - } - } - : errorKey - }) - ) - }, - [dispatch] - ) - - const onResponse = useCallback(() => { - dispatch( - openAlert({ - severity: snackbarVariants.success, - message: 'cooperationsPage.notes.noteMsg' - }) - ) - }, [dispatch]) + const onSuccessResponse = useCallback( + (noteAction: NoteAction) => { + const responseMessage = noteActionMap[noteAction] - const onDeleteResponse = useCallback(() => { - dispatch( - openAlert({ - severity: snackbarVariants.success, - message: 'cooperationsPage.modalMessages.successDeletion' - }) - ) - }, [dispatch]) + if (noteAction === 'create') { + setOpen(false) + } - const onUpdateResponse = useCallback(() => { - dispatch( - openAlert({ + handleAlert({ severity: snackbarVariants.success, - message: 'cooperationsPage.modalMessages.successUpdating' + message: responseMessage }) - ) - }, [dispatch]) - - const getNotes = useCallback(() => CooperationNotesService.getNotes(id), [id]) - - const createNoteService = useCallback( - (data: CreateOrUpdateNoteParams) => - CooperationNotesService.createNote(id, data), - [id] - ) - - const deleteNote = useCallback( - (noteId?: string) => - CooperationNotesService.deleteNote(id ?? '', noteId ?? ''), - [id] + }, + [handleAlert] ) - const updateNoteService = useCallback( - (params: { noteId: string; data: CreateOrUpdateNoteParams }) => - CooperationNotesService.updateNote(id, params.noteId, params.data), - [id] - ) + const getNotes = useCallback(() => { + return CooperationNotesService.getNotes(cooperationId) + }, [cooperationId]) const { - response: notes, - loading, - fetchData - } = useAxios({ - service: getNotes, - defaultResponse: defaultResponses.array, - onResponseError + data: notes, + isLoading: isNotesLoading, + error: getNotesError + } = useQuery({ + queryKey: ['notes', cooperationId], + queryFn: getNotes, + options: { + staleTime: Infinity + } }) - const onNoteCreate = useCallback(() => { - onResponse() - setOpen(false) - void fetchData() - }, [onResponse, fetchData]) - - const { loading: createLoading, fetchData: addNewNote } = useAxios({ - service: createNoteService, - defaultResponse: null, - fetchOnMount: false, - onResponseError, - onResponse: onNoteCreate - }) + useEffect(() => { + if (getNotesError) { + handleErrorAlert(getNotesError) + } + }, [handleErrorAlert, getNotesError]) - const { error, fetchData: deleteItem } = useAxios({ - service: deleteNote, - fetchOnMount: false, - defaultResponse: null, - onResponseError, - onResponse: onDeleteResponse - }) + const createNote = useCallback( + (data: CreateOrUpdateNoteParams) => { + return CooperationNotesService.createNote(cooperationId, data) + }, + [cooperationId] + ) - const { - error: updateError, - loading: updateLoading, - fetchData: updateNote - } = useAxios({ - service: updateNoteService, - fetchOnMount: false, - defaultResponse: null, - onResponseError, - onResponse: onUpdateResponse + const { mutate: addNewNote, isPending: createLoading } = useMutation({ + mutationFn: createNote, + queryKey: ['notes', cooperationId], + onError: handleErrorAlert, + onSuccess: () => onSuccessResponse('create') }) - const handleDelete = async (id: string, isConfirmed: boolean) => { - if (isConfirmed) { - await deleteItem(id) - if (!error) await fetchData() - } - } + const deleteSelectedNote = useCallback( + (noteId: string) => { + return CooperationNotesService.deleteNote(cooperationId, noteId) + }, + [cooperationId] + ) + + const { mutate: deleteNote } = useMutation({ + mutationFn: deleteSelectedNote, + queryKey: ['notes', cooperationId], + onError: handleErrorAlert, + onSuccess: () => onSuccessResponse('delete') + }) const onDeleteNote = (id: string) => { openDialog({ message: 'cooperationsPage.modalMessages.confirmDeletionMessage', - sendConfirm: (isConfirmed: boolean) => void handleDelete(id, isConfirmed), - title: `cooperationsPage.modalMessages.confirmDeletionTitle` + title: `cooperationsPage.modalMessages.confirmDeletionTitle`, + sendConfirm: (isConfirmed: boolean) => { + if (isConfirmed) { + deleteNote(id) + } + } }) } + const updateSelectedNote = useCallback( + (params: { noteId: string; data: CreateOrUpdateNoteParams }) => { + return CooperationNotesService.updateNote( + cooperationId, + params.noteId, + params.data + ) + }, + [cooperationId] + ) + + const { mutate: updateNote, isPending: updateNoteLoading } = useMutation({ + mutationFn: updateSelectedNote, + queryKey: ['notes', cooperationId], + onError: handleErrorAlert, + onSuccess: () => onSuccessResponse('update') + }) + const duplicateNote = useCallback( - (id: string) => { - const note = notes.find((item) => item._id === id) + (noteId: string) => { + const note = notes?.data.find((item) => item._id === noteId) + if (!note) { - return Promise.reject(noteNotFoundError) + throw new Error('Note with specified ID was not found') } - return createNoteService(note) + return CooperationNotesService.createNote(cooperationId, note) }, - [notes, createNoteService] + [cooperationId, notes] ) - const onDuplicateResponse = () => { - dispatch( - openAlert({ - severity: snackbarVariants.success, - message: `cooperationsPage.modalMessages.successDuplication` - }) - ) - } - - const { error: duplicationError, fetchData: duplicateItem } = useAxios({ - service: duplicateNote, - fetchOnMount: false, - defaultResponse: null, - onResponseError, - onResponse: onDuplicateResponse + const { mutate: duplicateItem } = useMutation({ + mutationFn: duplicateNote, + queryKey: ['notes', cooperationId], + onSuccess: () => onSuccessResponse('duplicate'), + onError: handleErrorAlert }) - const handleDuplicate = async (itemId: string) => { - await duplicateItem(itemId) - if (!duplicationError) await fetchData() - } - - const handleUpdate = async (data: CreateOrUpdateNoteParams) => { - await updateNote({ noteId: editableItemId, data }) + const handleUpdate = (data: CreateOrUpdateNoteParams) => { + updateNote({ noteId: editableItemId, data }) onCloseEdit() - if (!updateError) await fetchData() } const onCloseEdit = () => setEditableItemId('') const onCloseNote = () => setOpen(false) const onAddNoteOpen = () => setOpen(true) - const NotesList = notes.map((item: NoteResponse) => + const notesList = notes?.data.map((item: NoteResponse) => editableItemId === item._id ? ( ) : ( void handleDuplicate(itemId)} + duplicateItem={duplicateItem} key={item._id} note={item} updateItem={setEditableItemId} @@ -241,7 +192,7 @@ const CooperationNotes = () => { onSubmitLoading={createLoading} /> )} - {loading ? : NotesList} + {isNotesLoading || !notes ? : notesList} ) diff --git a/src/containers/my-cooperations/cooperation-notes/constant.ts b/src/containers/my-cooperations/cooperation-notes/constant.ts new file mode 100644 index 0000000000..1dd4190e06 --- /dev/null +++ b/src/containers/my-cooperations/cooperation-notes/constant.ts @@ -0,0 +1,8 @@ +export type NoteAction = 'create' | 'delete' | 'update' | 'duplicate' + +export const noteActionMap: Record = { + create: 'cooperationsPage.modalMessages.successCreation', + delete: 'cooperationsPage.modalMessages.successDeletion', + duplicate: 'cooperationsPage.modalMessages.successDuplication', + update: 'cooperationsPage.modalMessages.successUpdating' +} diff --git a/src/containers/my-cooperations/cooperation-notes/create-or-edit-note/CreateOrEditNote.tsx b/src/containers/my-cooperations/cooperation-notes/create-or-edit-note/CreateOrEditNote.tsx index 04b9ed4d67..1ebae32982 100644 --- a/src/containers/my-cooperations/cooperation-notes/create-or-edit-note/CreateOrEditNote.tsx +++ b/src/containers/my-cooperations/cooperation-notes/create-or-edit-note/CreateOrEditNote.tsx @@ -29,7 +29,7 @@ import { interface CreateOrEditNoteProps { note?: NoteResponse onSubmitLoading: boolean - onSubmit: (data: CreateOrUpdateNoteParams) => Promise + onSubmit: (data: CreateOrUpdateNoteParams) => void onCloseNote: () => void } @@ -65,8 +65,8 @@ const CreateOrEditNote = ({ text: note?.text ?? '', isPrivate: note?.isPrivate ?? false }, - onSubmit: async () => { - await onSubmit(data) + onSubmit: () => { + onSubmit(data) } }) diff --git a/tests/unit/containers/my-cooperations/cooperation-notes/CooperationNotes.constants.js b/tests/unit/containers/my-cooperations/cooperation-notes/CooperationNotes.constants.js new file mode 100644 index 0000000000..334de874a0 --- /dev/null +++ b/tests/unit/containers/my-cooperations/cooperation-notes/CooperationNotes.constants.js @@ -0,0 +1,192 @@ +export const mockNotesData = [ + { + _id: '65b03361bf20871d3adaeb9c', + text: 'Test note1 content', + author: { + _id: '6565fd508a848ff2202df79c', + firstName: 'User', + lastName: 'Test', + photo: '', + role: 'tutor' + }, + isPrivate: false, + cooperation: '65afbd053d67b51996a67c4c', + createdAt: '2024-01-23T21:45:05.200Z', + updatedAt: '2024-01-23T21:45:05.200Z' + }, + { + _id: '65b03361bf20871d3a3aeb9c', + text: 'Test note2 content', + author: { + _id: '6565fd508a848ff2202df79c', + firstName: 'User', + lastName: 'Test', + photo: '', + role: 'tutor' + }, + isPrivate: false, + cooperation: '65afbd053d67b51996a67c4c', + createdAt: '2024-01-23T21:45:05.200Z', + updatedAt: '2024-01-23T21:45:05.200Z' + } +] + +export const completeNewNote = { + _id: '65b03362js20871d3a3aeb9c', + text: 'Newly created note', + author: { + _id: '6565fd508a848ff2202df79c', + firstName: 'User', + lastName: 'Test', + photo: '', + role: 'tutor' + }, + isPrivate: false, + cooperation: '65afbd053d67b51996a67c4c', + createdAt: '2024-01-23T21:45:05.200Z', + updatedAt: '2024-01-23T21:45:05.200Z' +} + +export const mockUpdatedNotesData = [ + { + _id: '65b03361bf20871d3adaeb9c', + text: 'updated note', + author: { + _id: '6565fd508a848ff2202df79c', + firstName: 'User', + lastName: 'Test', + photo: '', + role: 'tutor' + }, + isPrivate: false, + cooperation: '65afbd053d67b51996a67c4c', + createdAt: '2024-01-23T21:45:05.200Z', + updatedAt: '2024-01-23T21:45:05.200Z' + }, + { + _id: '65b03361bf20871d3a3aeb9c', + text: 'Test note2 content', + author: { + _id: '6565fd508a848ff2202df79c', + firstName: 'User', + lastName: 'Test', + photo: '', + role: 'tutor' + }, + isPrivate: false, + cooperation: '65afbd053d67b51996a67c4c', + createdAt: '2024-01-23T21:45:05.200Z', + updatedAt: '2024-01-23T21:45:05.200Z' + }, + { + _id: '65b88762js20871d3a3aeb9c', + text: 'Newly created note', + author: { + _id: '6565fd508a848ff2202df79c', + firstName: 'User', + lastName: 'Test', + photo: '', + role: 'tutor' + }, + isPrivate: false, + cooperation: '65afbd053d67b51996a67c4c', + createdAt: '2024-01-23T21:45:05.200Z', + updatedAt: '2024-01-23T21:45:05.200Z' + } +] + +export const mockUpdatedWithDuplicatedNoteData = [ + { + _id: '65b03361bf20871d3adaeb9c', + text: 'updated note', + author: { + _id: '6565fd508a848ff2202df79c', + firstName: 'User', + lastName: 'Test', + photo: '', + role: 'tutor' + }, + isPrivate: false, + cooperation: '65afbd053d67b51996a67c4c', + createdAt: '2024-01-23T21:45:05.200Z', + updatedAt: '2024-01-23T21:45:05.200Z' + }, + { + _id: '65b03361bf20871d3adead9c', + text: 'Test note2 content', + author: { + _id: '6565fd508a848ff2202df79c', + firstName: 'User', + lastName: 'Test', + photo: '', + role: 'tutor' + }, + isPrivate: false, + cooperation: '65afbd053d67b51996a67c4c', + createdAt: '2024-01-23T21:45:05.200Z', + updatedAt: '2024-01-23T21:45:05.200Z' + }, + { + _id: '65b03361bf20871d3a3aeb9c', + text: 'Test note2 content', + author: { + _id: '6565fd508a848ff2202df79c', + firstName: 'User', + lastName: 'Test', + photo: '', + role: 'tutor' + }, + isPrivate: false, + cooperation: '65afbd053d67b51996a67c4c', + createdAt: '2024-01-23T21:45:05.200Z', + updatedAt: '2024-01-23T21:45:05.200Z' + }, + { + _id: '65b88762js20871d3a3aeb9c', + text: 'Newly created note', + author: { + _id: '6565fd508a848ff2202df79c', + firstName: 'User', + lastName: 'Test', + photo: '', + role: 'tutor' + }, + isPrivate: false, + cooperation: '65afbd053d67b51996a67c4c', + createdAt: '2024-01-23T21:45:05.200Z', + updatedAt: '2024-01-23T21:45:05.200Z' + } +] + +export const finishedMockedNotesData = [ + { + _id: '65b03361bf20871d3a3aeb9c', + text: 'Test note2 content', + author: { + _id: '6565fd508a848ff2202df79c', + firstName: 'User', + lastName: 'Test', + photo: '', + role: 'tutor' + }, + isPrivate: false, + cooperation: '65afbd053d67b51996a67c4c', + createdAt: '2024-01-23T21:45:05.200Z', + updatedAt: '2024-01-23T21:45:05.200Z' + }, + { + _id: '65b88762js20871d3a3aeb9c', + text: 'Newly created note', + author: { + _id: '6565fd508a848ff2202df79c', + firstName: 'User', + lastName: 'Test', + photo: '', + role: 'tutor' + }, + isPrivate: false, + cooperation: '65afbd053d67b51996a67c4c', + createdAt: '2024-01-23T21:45:05.200Z', + updatedAt: '2024-01-23T21:45:05.200Z' + } +] diff --git a/tests/unit/containers/my-cooperations/cooperation-notes/CooperationNotes.spec.jsx b/tests/unit/containers/my-cooperations/cooperation-notes/CooperationNotes.spec.jsx index 0aa4e89e2d..ba2096b19d 100644 --- a/tests/unit/containers/my-cooperations/cooperation-notes/CooperationNotes.spec.jsx +++ b/tests/unit/containers/my-cooperations/cooperation-notes/CooperationNotes.spec.jsx @@ -1,91 +1,96 @@ import { screen, fireEvent, waitFor } from '@testing-library/react' +import { afterEach, vi } from 'vitest' import CooperationNotes from '~/containers/my-cooperations/cooperation-notes/CooperationNotes' import { renderWithProviders, - mockAxiosClient, - TestSnackbar + TestSnackbar, + mockAxiosClient } from '~tests/test-utils' -import { vi } from 'vitest' import { ConfirmationDialogProvider } from '~/context/confirm-context' import { URLs } from '~/constants/request' +import { + mockNotesData, + mockUpdatedNotesData, + mockUpdatedWithDuplicatedNoteData, + completeNewNote, + finishedMockedNotesData +} from './CooperationNotes.constants' +import * as useQuery from '~/hooks/use-query' import { getFullUrl } from '~/utils/get-full-url' -const mockNotesData = [ - { - _id: '65b03361bf20871d3adaeb9c', - text: 'Test note1 content', - author: { - _id: '6565fd508a848ff2202df79c', - firstName: 'User', - lastName: 'Test', - role: 'tutor' - }, - isPrivate: false, - cooperation: '65afbd053d67b51996a67c4c', - createdAt: '2024-01-23T21:45:05.200Z', - updatedAt: '2024-01-23T21:45:05.200Z' - }, - { - _id: '65b03361bf20871d3a3aeb9c', - text: 'Test note2 content', - author: { - _id: '6565fd508a848ff2202df79c', - firstName: 'User', - lastName: 'Test', - role: 'tutor' - }, - isPrivate: false, - cooperation: '65afbd053d67b51996a67c4c', - createdAt: '2024-01-23T21:45:05.200Z', - updatedAt: '2024-01-23T21:45:05.200Z' - } -] +const cooperationId = '675b37915a23a358ab40bf66' -const mockResponseData = { - data: '' +const newNotePayload = { + text: 'Newly created note', + isPrivate: false } -const userMock = { - _id: '648850c4fdc2d1a130c24aea', - role: 'tutor', - firstName: 'Test', - lastName: 'User', - photo: 'https://www.google.com' + +const updatedNotePayload = { + text: 'updated note', + isPrivate: false } -const mockGetNote = vi.fn() -const mockUpdateNote = vi.fn().mockReturnValue(mockResponseData) -const mockCreateNote = vi.fn().mockReturnValue(mockResponseData) -const mockDeleteNote = vi.fn().mockReturnValue(mockResponseData) +const duplicatedNote = { + ...mockUpdatedNotesData[1], + _id: '65b03361bf20871d3adead9c', + text: mockUpdatedNotesData[1].text +} -vi.mock('~/services/cooperation-service', async () => { - const actual = await vi.importActual('~/services/cooperation-service') +vi.mock('react-router-dom', async () => { + const actual = await vi.importActual('react-router-dom') return { ...actual, - CooperationNotesService: { - getNotes: () => mockGetNote(), - updateNote: () => mockUpdateNote(), - createNote: () => mockCreateNote(), - deleteNote: () => mockDeleteNote() - } + useParams: () => ({ + id: cooperationId + }) } }) +const userMock = { + _id: '648850c4fdc2d1a130c24aea', + role: 'tutor', + firstName: 'Test', + lastName: 'User', + photo: '' +} + const appMain = { appMain: { userRole: 'tutor', userId: mockNotesData[0].author._id } } +const getNotesUrl = URLs.notes.get.replace(':id', cooperationId) +const createNoteUrl = URLs.notes.create.replace(':id', cooperationId) +const updateNoteUrl = URLs.notes.update + .replace(':id', cooperationId) + .replace(':noteId', mockNotesData[0]._id) +const deleteNoteUrl = URLs.notes.delete + .replace(':id', cooperationId) + .replace(':noteId', mockUpdatedNotesData[0]._id) +const duplicateNoteUrl = URLs.notes.create.replace(':id', cooperationId) + +const url = getFullUrl({ + parameters: { id: mockNotesData[0].author._id }, + pathname: URLs.users.getUserById, + searchParameters: { userRole: mockNotesData[0].author.role } +}) + describe('CooperationNotes', () => { beforeEach(() => { - const url = getFullUrl({ - parameters: { id: mockNotesData[0].author._id }, - pathname: URLs.users.getUserById, - searchParameters: { userRole: mockNotesData[0].author.role } - }) mockAxiosClient.onGet(url).reply(200, userMock) + mockAxiosClient.onGet(getNotesUrl).replyOnce(200, mockNotesData) + mockAxiosClient.onPost(createNoteUrl).reply(200, newNotePayload) + mockAxiosClient + .onGet(getNotesUrl) + .replyOnce(200, [...mockNotesData, completeNewNote]) + mockAxiosClient.onPatch(updateNoteUrl).reply(200, updatedNotePayload) + mockAxiosClient.onGet(getNotesUrl).replyOnce(200, mockUpdatedNotesData) + mockAxiosClient.onPost(duplicateNoteUrl).reply(200, duplicatedNote) + mockAxiosClient + .onGet(getNotesUrl) + .replyOnce(200, mockUpdatedWithDuplicatedNoteData) + mockAxiosClient.onDelete(deleteNoteUrl).reply(200, null) + mockAxiosClient.onGet(getNotesUrl).replyOnce(200, finishedMockedNotesData) - mockGetNote.mockReturnValue({ - data: mockNotesData - }) renderWithProviders( @@ -110,12 +115,14 @@ describe('CooperationNotes', () => { const newNoteText = 'Newly created note' const addNoteBtn = screen.getByTestId('AddIcon') fireEvent.click(addNoteBtn) + await waitFor(() => { const noteFormSettings = screen.getByText( 'cooperationsPage.notes.privateSetting' ) expect(noteFormSettings).toBeInTheDocument() }) + const noteTextInput = screen.getByLabelText( 'cooperationsPage.notes.noteText' ) @@ -127,10 +134,14 @@ describe('CooperationNotes', () => { target: { value: newNoteText } }) fireEvent.click(saveButton) - await waitFor(() => { - const newNote = screen.getByText(newNoteText) - expect(newNote).toBeInTheDocument() - }) + + const snackbar = await screen.findByText( + 'cooperationsPage.modalMessages.successCreation' + ) + expect(snackbar).toBeInTheDocument() + + const newNote = screen.getByText(newNoteText) + expect(newNote).toBeInTheDocument() }) it('should close create note form', () => { @@ -148,7 +159,6 @@ describe('CooperationNotes', () => { }) it('should enable the edit mode and handle updates', async () => { - const newNoteText = 'New note text' const [menuButton] = screen.getAllByTestId('MoreVertIcon') fireEvent.click(menuButton) @@ -158,32 +168,42 @@ describe('CooperationNotes', () => { const [noteTextInput] = screen.getAllByDisplayValue(mockNotesData[0].text) const saveButton = screen.getByRole('button', { name: 'common.save' }) - fireEvent.change(noteTextInput, { target: { value: newNoteText } }) + fireEvent.change(noteTextInput, { target: { value: 'updated note' } }) fireEvent.click(saveButton) - const newNote = screen.getByText(newNoteText) + const snackbar = await screen.findByText( + 'cooperationsPage.modalMessages.successUpdating' + ) + expect(snackbar).toBeInTheDocument() - await waitFor(() => { - expect(mockUpdateNote).toHaveBeenCalled() - expect(newNote).toBeInTheDocument() - }) + const newNote = await screen.findByText('updated note') + expect(newNote).toBeInTheDocument() }) it('should handle duplicate notes', async () => { - const [menuButton] = screen.getAllByTestId('MoreVertIcon') - fireEvent.click(menuButton) + const noteText = mockUpdatedNotesData[1].text + const initialNoteElements = screen.getAllByText(noteText) + + const menuButtons = screen.getAllByTestId('MoreVertIcon') + fireEvent.click(menuButtons[1]) const duplicateButton = screen.getByTestId('ContentCopyIcon') fireEvent.click(duplicateButton) + const snackbar = await screen.findByText( + 'cooperationsPage.modalMessages.successDuplication' + ) + expect(snackbar).toBeInTheDocument() + await waitFor(() => { - expect(mockCreateNote).toHaveBeenCalled() + const updatedNoteElements = screen.getAllByText(noteText) + expect(updatedNoteElements.length).toBe(initialNoteElements.length + 1) }) }) it('should handle delete notes', async () => { - const [menuButton] = screen.getAllByTestId('MoreVertIcon') - fireEvent.click(menuButton) + const menuButtons = screen.getAllByTestId('MoreVertIcon') + fireEvent.click(menuButtons[0]) const deleteButton = screen.getByTestId('DeleteOutlineIcon') fireEvent.click(deleteButton) @@ -191,20 +211,26 @@ describe('CooperationNotes', () => { const confirmButton = screen.getByRole('button', { name: 'common.yes' }) fireEvent.click(confirmButton) + const snackbar = await screen.findByText( + 'cooperationsPage.modalMessages.successDeletion' + ) + expect(snackbar).toBeInTheDocument() + + const noteText = mockUpdatedNotesData[0].text await waitFor(() => { - expect(mockDeleteNote).toHaveBeenCalled() + expect(screen.queryByText(noteText)).not.toBeInTheDocument() }) }) }) describe('CooperationNotes with error', () => { - const fakeError = { - message: 'UNKNOWN_ERROR' - } + const fakeError = { code: 'errorCode', message: 'UNKNOWN_ERROR' } beforeEach(() => { - mockGetNote.mockRejectedValue({ - response: { data: fakeError } + vi.spyOn(useQuery, 'default').mockReturnValue({ + isLoading: false, + error: fakeError, + data: null }) renderWithProviders( @@ -215,8 +241,7 @@ describe('CooperationNotes with error', () => { }) it('should show the error message', async () => { - const errorAlert = await screen.findByText(`errors.${fakeError.message}`) - + const errorAlert = await screen.findByText(`errors.${fakeError.code}`) expect(errorAlert).toBeInTheDocument() }) })