From 84f749bccc1363f049292c37880cbff75dec666b Mon Sep 17 00:00:00 2001 From: ehconitin Date: Sat, 14 Dec 2024 16:16:00 +0530 Subject: [PATCH] updated tests and rename useReorderFavorite to useHandleFavoriteDragAndDrop --- .../components/FavoritesDragProvider.tsx | 6 +- .../favorites/hooks/__mocks__/useFavorites.ts | 636 ++++++++++-------- .../useHandleFavoriteDragAndDrop.test.tsx | 163 +++++ .../__tests__/useReorderFavorite.test.tsx | 67 -- ...ite.ts => useHandleFavoriteDragAndDrop.ts} | 6 +- 5 files changed, 512 insertions(+), 366 deletions(-) create mode 100644 packages/twenty-front/src/modules/favorites/hooks/__tests__/useHandleFavoriteDragAndDrop.test.tsx delete mode 100644 packages/twenty-front/src/modules/favorites/hooks/__tests__/useReorderFavorite.test.tsx rename packages/twenty-front/src/modules/favorites/hooks/{useReorderFavorite.ts => useHandleFavoriteDragAndDrop.ts} (95%) diff --git a/packages/twenty-front/src/modules/favorites/components/FavoritesDragProvider.tsx b/packages/twenty-front/src/modules/favorites/components/FavoritesDragProvider.tsx index 006472e4b471..db3f1700f66b 100644 --- a/packages/twenty-front/src/modules/favorites/components/FavoritesDragProvider.tsx +++ b/packages/twenty-front/src/modules/favorites/components/FavoritesDragProvider.tsx @@ -1,5 +1,5 @@ import { FavoritesDragContext } from '@/favorites/contexts/FavoritesDragContext'; -import { useReorderFavorite } from '@/favorites/hooks/useReorderFavorite'; +import { useHandleFavoriteDragAndDrop } from '@/favorites/hooks/useHandleFavoriteDragAndDrop'; import { DragDropContext, DragStart, @@ -16,7 +16,7 @@ export const FavoritesDragProvider = ({ children, }: FavoritesDragProviderProps) => { const [isDragging, setIsDragging] = useState(false); - const { handleReorderFavorite } = useReorderFavorite(); + const { handleFavoriteDragAndDrop } = useHandleFavoriteDragAndDrop(); const handleDragStart = (_: DragStart) => { setIsDragging(true); @@ -24,7 +24,7 @@ export const FavoritesDragProvider = ({ const handleDragEnd = (result: DropResult, provided: ResponderProvided) => { setIsDragging(false); - handleReorderFavorite(result, provided); + handleFavoriteDragAndDrop(result, provided); }; return ( diff --git a/packages/twenty-front/src/modules/favorites/hooks/__mocks__/useFavorites.ts b/packages/twenty-front/src/modules/favorites/hooks/__mocks__/useFavorites.ts index e5d3e601a380..154bad46cf6d 100644 --- a/packages/twenty-front/src/modules/favorites/hooks/__mocks__/useFavorites.ts +++ b/packages/twenty-front/src/modules/favorites/hooks/__mocks__/useFavorites.ts @@ -25,7 +25,7 @@ export const initialFavorites = [ person: { id: '1', name: 'John Doe' }, company: { id: '2', name: 'ABC Corp' }, workspaceMemberId: '1', - favoriteFolderId: undefined, + favoriteFolderId: '1', }, { __typename: 'Favorite', @@ -40,7 +40,7 @@ export const initialFavorites = [ person: { id: '3', name: 'Jane Doe' }, company: { id: '4', name: 'Company Test' }, workspaceMemberId: '1', - favoriteFolderId: undefined, + favoriteFolderId: '1', }, { @@ -54,7 +54,7 @@ export const initialFavorites = [ link: 'example.com', recordId: '1', workspaceMemberId: '1', - favoriteFolderId: undefined, + favoriteFolderId: '1', }, ]; @@ -69,7 +69,7 @@ export const sortedFavorites = [ link: '/object/person/1', objectNameSingular: 'person', workspaceMemberId: '1', - favoriteFolderId: undefined, + favoriteFolderId: '1', __typename: 'Favorite', }, { @@ -82,7 +82,7 @@ export const sortedFavorites = [ link: '/object/person/3', objectNameSingular: 'person', workspaceMemberId: '1', - favoriteFolderId: undefined, + favoriteFolderId: '1', __typename: 'Favorite', }, { @@ -94,12 +94,298 @@ export const sortedFavorites = [ link: 'example.com', recordId: '1', avatarType: 'squared', - favoriteFolderId: undefined, + favoriteFolderId: '1', workspaceMemberId: '1', __typename: 'Favorite', }, ]; +const UPDATE_ONE_FAVORITE_MUTATION = gql` +mutation UpdateOneFavorite( + $idToUpdate: ID! + $input: FavoriteUpdateInput! +) { + updateFavorite(id: $idToUpdate, data: $input) { + __typename + company { + __typename + accountOwnerId + address { + addressStreet1 + addressStreet2 + addressCity + addressState + addressCountry + addressPostcode + addressLat + addressLng + } + annualRecurringRevenue { + amountMicros + currencyCode + } + createdAt + createdBy { + source + workspaceMemberId + name + } + deletedAt + domainName { + primaryLinkUrl + primaryLinkLabel + secondaryLinks + } + employees + id + idealCustomerProfile + introVideo { + primaryLinkUrl + primaryLinkLabel + secondaryLinks + } + linkedinLink { + primaryLinkUrl + primaryLinkLabel + secondaryLinks + } + name + position + tagline + updatedAt + visaSponsorship + workPolicy + xLink { + primaryLinkUrl + primaryLinkLabel + secondaryLinks + } + } + companyId + createdAt + deletedAt + favoriteFolder { + __typename + createdAt + deletedAt + id + name + position + updatedAt + } + favoriteFolderId + id + note { + __typename + body + createdAt + createdBy { + source + workspaceMemberId + name + } + deletedAt + id + position + title + updatedAt + } + noteId + opportunity { + __typename + amount { + amountMicros + currencyCode + } + closeDate + companyId + createdAt + createdBy { + source + workspaceMemberId + name + } + deletedAt + id + name + pointOfContactId + position + stage + updatedAt + } + opportunityId + person { + __typename + avatarUrl + city + companyId + createdAt + createdBy { + source + workspaceMemberId + name + } + deletedAt + emails { + primaryEmail + additionalEmails + } + id + intro + jobTitle + linkedinLink { + primaryLinkUrl + primaryLinkLabel + secondaryLinks + } + name { + firstName + lastName + } + performanceRating + phones { + primaryPhoneNumber + primaryPhoneCountryCode + additionalPhones + } + position + updatedAt + whatsapp { + primaryPhoneNumber + primaryPhoneCountryCode + additionalPhones + } + workPreference + xLink { + primaryLinkUrl + primaryLinkLabel + secondaryLinks + } + } + personId + position + rocket { + __typename + createdAt + createdBy { + source + workspaceMemberId + name + } + deletedAt + id + name + position + updatedAt + } + rocketId + task { + __typename + assigneeId + body + createdAt + createdBy { + source + workspaceMemberId + name + } + deletedAt + dueAt + id + position + status + title + updatedAt + } + taskId + updatedAt + view { + __typename + createdAt + deletedAt + icon + id + isCompact + kanbanFieldMetadataId + key + name + objectMetadataId + position + type + updatedAt + } + viewId + workflow { + __typename + createdAt + deletedAt + id + lastPublishedVersionId + name + position + statuses + updatedAt + } + workflowId + workflowRun { + __typename + createdAt + createdBy { + source + workspaceMemberId + name + } + deletedAt + endedAt + id + name + output + position + startedAt + status + updatedAt + workflowId + workflowVersionId + } + workflowRunId + workflowVersion { + __typename + createdAt + deletedAt + id + name + position + status + steps + trigger + updatedAt + workflowId + } + workflowVersionId + workspaceMember { + __typename + avatarUrl + colorScheme + createdAt + dateFormat + deletedAt + id + locale + name { + firstName + lastName + } + timeFormat + timeZone + updatedAt + userEmail + userId + } + workspaceMemberId + } +} +`; + export const mocks = [ { request: { @@ -388,7 +674,7 @@ export const mocks = [ variables: { input: { personId: favoriteTargetObjectId, - position: 3, + position: 1, workspaceMemberId: '1', favoriteFolderId: undefined, id: mockId, @@ -430,291 +716,7 @@ export const mocks = [ }, { request: { - query: gql` - mutation UpdateOneFavorite( - $idToUpdate: ID! - $input: FavoriteUpdateInput! - ) { - updateFavorite(id: $idToUpdate, data: $input) { - __typename - company { - __typename - accountOwnerId - address { - addressStreet1 - addressStreet2 - addressCity - addressState - addressCountry - addressPostcode - addressLat - addressLng - } - annualRecurringRevenue { - amountMicros - currencyCode - } - createdAt - createdBy { - source - workspaceMemberId - name - } - deletedAt - domainName { - primaryLinkUrl - primaryLinkLabel - secondaryLinks - } - employees - id - idealCustomerProfile - introVideo { - primaryLinkUrl - primaryLinkLabel - secondaryLinks - } - linkedinLink { - primaryLinkUrl - primaryLinkLabel - secondaryLinks - } - name - position - tagline - updatedAt - visaSponsorship - workPolicy - xLink { - primaryLinkUrl - primaryLinkLabel - secondaryLinks - } - } - companyId - createdAt - deletedAt - favoriteFolder { - __typename - createdAt - deletedAt - id - name - position - updatedAt - } - favoriteFolderId - id - note { - __typename - body - createdAt - createdBy { - source - workspaceMemberId - name - } - deletedAt - id - position - title - updatedAt - } - noteId - opportunity { - __typename - amount { - amountMicros - currencyCode - } - closeDate - companyId - createdAt - createdBy { - source - workspaceMemberId - name - } - deletedAt - id - name - pointOfContactId - position - stage - updatedAt - } - opportunityId - person { - __typename - avatarUrl - city - companyId - createdAt - createdBy { - source - workspaceMemberId - name - } - deletedAt - emails { - primaryEmail - additionalEmails - } - id - intro - jobTitle - linkedinLink { - primaryLinkUrl - primaryLinkLabel - secondaryLinks - } - name { - firstName - lastName - } - performanceRating - phones { - primaryPhoneNumber - primaryPhoneCountryCode - additionalPhones - } - position - updatedAt - whatsapp { - primaryPhoneNumber - primaryPhoneCountryCode - additionalPhones - } - workPreference - xLink { - primaryLinkUrl - primaryLinkLabel - secondaryLinks - } - } - personId - position - rocket { - __typename - createdAt - createdBy { - source - workspaceMemberId - name - } - deletedAt - id - name - position - updatedAt - } - rocketId - task { - __typename - assigneeId - body - createdAt - createdBy { - source - workspaceMemberId - name - } - deletedAt - dueAt - id - position - status - title - updatedAt - } - taskId - updatedAt - view { - __typename - createdAt - deletedAt - icon - id - isCompact - kanbanFieldMetadataId - key - name - objectMetadataId - position - type - updatedAt - } - viewId - workflow { - __typename - createdAt - deletedAt - id - lastPublishedVersionId - name - position - statuses - updatedAt - } - workflowId - workflowRun { - __typename - createdAt - createdBy { - source - workspaceMemberId - name - } - deletedAt - endedAt - id - name - output - position - startedAt - status - updatedAt - workflowId - workflowVersionId - } - workflowRunId - workflowVersion { - __typename - createdAt - deletedAt - id - name - position - status - steps - trigger - updatedAt - workflowId - } - workflowVersionId - workspaceMember { - __typename - avatarUrl - colorScheme - createdAt - dateFormat - deletedAt - id - locale - name { - firstName - lastName - } - timeFormat - timeZone - updatedAt - userEmail - userId - } - workspaceMemberId - } - } - `, + query: UPDATE_ONE_FAVORITE_MUTATION, variables: { idToUpdate: '1', input: { @@ -726,12 +728,60 @@ export const mocks = [ data: { updateFavorite: { __typename: 'Favorite', - id: favoriteId, + id: favoriteId, position: 2, }, }, })), }, + + // Mock for folder move + { + request: { + query: UPDATE_ONE_FAVORITE_MUTATION, + variables: { + idToUpdate: '1', + input: { + position: 0, + favoriteFolderId: '2', + }, + }, + }, + result: jest.fn(() => ({ + data: { + updateFavorite: { + __typename: 'Favorite', + id: favoriteId, + position: 0, + favoriteFolderId: '2', + }, + }, + })), + }, + + // Mock for orphan favorites + { + request: { + query: UPDATE_ONE_FAVORITE_MUTATION, + variables: { + idToUpdate: '1', + input: { + position: 0, + favoriteFolderId: null, + }, + }, + }, + result: jest.fn(() => ({ + data: { + updateFavorite: { + __typename: 'Favorite', + id: favoriteId, + position: 0, + favoriteFolderId: null, + }, + }, + })), + }, ]; export const mockWorkspaceMember = { diff --git a/packages/twenty-front/src/modules/favorites/hooks/__tests__/useHandleFavoriteDragAndDrop.test.tsx b/packages/twenty-front/src/modules/favorites/hooks/__tests__/useHandleFavoriteDragAndDrop.test.tsx new file mode 100644 index 000000000000..955291e926b0 --- /dev/null +++ b/packages/twenty-front/src/modules/favorites/hooks/__tests__/useHandleFavoriteDragAndDrop.test.tsx @@ -0,0 +1,163 @@ +import { DropResult, ResponderProvided } from '@hello-pangea/dnd'; +import { renderHook, waitFor } from '@testing-library/react'; +import { act } from 'react'; +import { useSetRecoilState } from 'recoil'; + +import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState'; +import { useHandleFavoriteDragAndDrop } from '@/favorites/hooks/useHandleFavoriteDragAndDrop'; +import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; +import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper'; +import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems'; + +import { + initialFavorites, + mockWorkspaceMember, + mocks, +} from '../__mocks__/useFavorites'; + +jest.mock('@/object-record/hooks/useFindManyRecords', () => ({ + useFindManyRecords: () => ({ records: initialFavorites }), +})); + +const Wrapper = getJestMetadataAndApolloMocksWrapper({ + apolloMocks: mocks, +}); + +describe('useHandleFavoriteDragAndDrop', () => { + const mockResponderProvided: ResponderProvided = { + announce: jest.fn(), + }; + + const setupHook = () => { + return renderHook( + () => { + const setCurrentWorkspaceMember = useSetRecoilState( + currentWorkspaceMemberState, + ); + const setMetadataItems = useSetRecoilState(objectMetadataItemsState); + + setCurrentWorkspaceMember(mockWorkspaceMember); + setMetadataItems(generatedMockObjectMetadataItems); + + return { + hook: useHandleFavoriteDragAndDrop(), + }; + }, + { wrapper: Wrapper }, + ); + }; + + it('should not update when destination is null', () => { + const { result } = setupHook(); + + act(() => { + result.current.hook.handleFavoriteDragAndDrop( + { + source: { index: 0, droppableId: 'folder-1' }, + destination: null, + draggableId: '1', + } as DropResult, + mockResponderProvided, + ); + }); + + expect(mocks[2].result).not.toHaveBeenCalled(); + expect(mocks[3].result).not.toHaveBeenCalled(); + expect(mocks[4].result).not.toHaveBeenCalled(); + }); + + it('should not update when destination is same as source', () => { + const { result } = setupHook(); + + act(() => { + result.current.hook.handleFavoriteDragAndDrop( + { + source: { index: 0, droppableId: 'folder-1' }, + destination: { index: 0, droppableId: 'folder-1' }, + draggableId: '1', + } as DropResult, + mockResponderProvided, + ); + }); + + expect(mocks[2].result).not.toHaveBeenCalled(); + expect(mocks[3].result).not.toHaveBeenCalled(); + expect(mocks[4].result).not.toHaveBeenCalled(); + }); + //fails + it('should reorder within same folder', async () => { + const { result } = setupHook(); + + act(() => { + result.current.hook.handleFavoriteDragAndDrop( + { + source: { index: 0, droppableId: 'folder-1' }, + destination: { index: 2, droppableId: 'folder-1' }, + draggableId: '1', + } as DropResult, + mockResponderProvided, + ); + }); + + await waitFor(() => { + expect(mocks[2].result).toHaveBeenCalled(); + }); + }); + + it('should move to another folder', async () => { + const { result } = setupHook(); + + act(() => { + result.current.hook.handleFavoriteDragAndDrop( + { + source: { index: 0, droppableId: 'folder-1' }, + destination: { index: 0, droppableId: 'folder-2' }, + draggableId: '1', + } as DropResult, + mockResponderProvided, + ); + }); + + await waitFor(() => { + expect(mocks[3].result).toHaveBeenCalled(); + }); + }); + + it('should move to orphan favorites', async () => { + const { result } = setupHook(); + + act(() => { + result.current.hook.handleFavoriteDragAndDrop( + { + source: { index: 0, droppableId: 'folder-1' }, + destination: { index: 0, droppableId: 'orphan-favorites' }, + draggableId: '1', + } as DropResult, + mockResponderProvided, + ); + }); + + await waitFor(() => { + expect(mocks[4].result).toHaveBeenCalled(); + }); + }); + //fails + it('should handle dropping into folder header', async () => { + const { result } = setupHook(); + + act(() => { + result.current.hook.handleFavoriteDragAndDrop( + { + source: { index: 0, droppableId: 'folder-1' }, + destination: { index: 0, droppableId: 'folder-header-2' }, + draggableId: '1', + } as DropResult, + mockResponderProvided, + ); + }); + + await waitFor(() => { + expect(mocks[3].result).toHaveBeenCalled(); + }); + }); +}); diff --git a/packages/twenty-front/src/modules/favorites/hooks/__tests__/useReorderFavorite.test.tsx b/packages/twenty-front/src/modules/favorites/hooks/__tests__/useReorderFavorite.test.tsx deleted file mode 100644 index c43c8e1abd71..000000000000 --- a/packages/twenty-front/src/modules/favorites/hooks/__tests__/useReorderFavorite.test.tsx +++ /dev/null @@ -1,67 +0,0 @@ -import { DropResult, ResponderProvided } from '@hello-pangea/dnd'; -import { renderHook, waitFor } from '@testing-library/react'; -import { act } from 'react'; -import { useSetRecoilState } from 'recoil'; - -import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState'; -import { useReorderFavorite } from '@/favorites/hooks/useReorderFavorite'; -import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; -import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper'; -import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems'; -import { - initialFavorites, - mockWorkspaceMember, - mocks, -} from '../__mocks__/useFavorites'; - -jest.mock('@/object-record/hooks/useFindManyRecords', () => ({ - useFindManyRecords: () => ({ records: initialFavorites }), -})); - -const Wrapper = getJestMetadataAndApolloMocksWrapper({ - apolloMocks: mocks, -}); - -describe('useReorderFavorite', () => { - it('should handle reordering favorites successfully', async () => { - const { result } = renderHook( - () => { - const setCurrentWorkspaceMember = useSetRecoilState( - currentWorkspaceMemberState, - ); - setCurrentWorkspaceMember(mockWorkspaceMember); - - const setMetadataItems = useSetRecoilState(objectMetadataItemsState); - setMetadataItems(generatedMockObjectMetadataItems); - - return useReorderFavorite(); - }, - { wrapper: Wrapper }, - ); - - act(() => { - const dragAndDropResult: DropResult = { - source: { index: 0, droppableId: 'droppableId' }, - destination: { index: 2, droppableId: 'droppableId' }, - combine: null, - mode: 'FLUID', - draggableId: '1', - type: 'type', - reason: 'DROP', - }; - - const responderProvided: ResponderProvided = { - announce: () => {}, - }; - - result.current.handleReorderFavorite( - dragAndDropResult, - responderProvided, - ); - }); - - await waitFor(() => { - expect(mocks[2].result).toHaveBeenCalled(); - }); - }); -}); diff --git a/packages/twenty-front/src/modules/favorites/hooks/useReorderFavorite.ts b/packages/twenty-front/src/modules/favorites/hooks/useHandleFavoriteDragAndDrop.ts similarity index 95% rename from packages/twenty-front/src/modules/favorites/hooks/useReorderFavorite.ts rename to packages/twenty-front/src/modules/favorites/hooks/useHandleFavoriteDragAndDrop.ts index 91130e5ef1f0..285e1a943e93 100644 --- a/packages/twenty-front/src/modules/favorites/hooks/useReorderFavorite.ts +++ b/packages/twenty-front/src/modules/favorites/hooks/useHandleFavoriteDragAndDrop.ts @@ -7,7 +7,7 @@ import { OnDragEndResponder } from '@hello-pangea/dnd'; import { useSetRecoilState } from 'recoil'; import { usePrefetchedFavoritesData } from './usePrefetchedFavoritesData'; -export const useReorderFavorite = () => { +export const useHandleFavoriteDragAndDrop = () => { const { favorites } = usePrefetchedFavoritesData(); const { favoritesSorted } = useSortedFavorites(); const { updateOneRecord: updateOneFavorite } = useUpdateOneRecord({ @@ -17,7 +17,7 @@ export const useReorderFavorite = () => { activeFavoriteFolderIdState, ); - const handleReorderFavorite: OnDragEndResponder = (result) => { + const handleFavoriteDragAndDrop: OnDragEndResponder = (result) => { const { destination, source, draggableId } = result; if (!destination) return; @@ -117,5 +117,5 @@ export const useReorderFavorite = () => { }); }; - return { handleReorderFavorite }; + return { handleFavoriteDragAndDrop }; };