From a0e5ca44bae98b09ae2a01ba5196c63745546c01 Mon Sep 17 00:00:00 2001 From: Thomas Trompette Date: Thu, 8 Aug 2024 15:53:17 +0200 Subject: [PATCH] Fix last batch of jest tests (#6582) As title --- .../hooks/__tests__/useActivities.test.tsx | 205 ++---------- ...test.ts => useTimelineActivities.test.tsx} | 11 +- ...filterOutInvalidTimelineActivities.test.ts | 25 +- .../filterOutInvalidTimelineActivities.ts | 3 +- .../__tests__/useMultiObjectSearch.test.tsx | 299 +++++++----------- 5 files changed, 188 insertions(+), 355 deletions(-) rename packages/twenty-front/src/modules/activities/timelineActivities/hooks/__tests__/{useTimelineActivities.test.ts => useTimelineActivities.test.tsx} (86%) diff --git a/packages/twenty-front/src/modules/activities/hooks/__tests__/useActivities.test.tsx b/packages/twenty-front/src/modules/activities/hooks/__tests__/useActivities.test.tsx index 2985f122a..23229f581 100644 --- a/packages/twenty-front/src/modules/activities/hooks/__tests__/useActivities.test.tsx +++ b/packages/twenty-front/src/modules/activities/hooks/__tests__/useActivities.test.tsx @@ -1,14 +1,17 @@ -import { gql } from '@apollo/client'; -import { MockedProvider, MockedResponse } from '@apollo/client/testing'; -import { act, renderHook, waitFor } from '@testing-library/react'; +import { renderHook } from '@testing-library/react'; import { ReactNode } from 'react'; -import { RecoilRoot, useSetRecoilState } from 'recoil'; +import { RecoilRoot } from 'recoil'; import { useActivities } from '@/activities/hooks/useActivities'; -import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; -import { SnackBarProviderScope } from '@/ui/feedback/snack-bar-manager/scopes/SnackBarProviderScope'; -import { mockWorkspaceMembers } from '~/testing/mock-data/workspace-members'; + +jest.mock('@/activities/hooks/useActivityTargetsForTargetableObjects', () => ({ + useActivityTargetsForTargetableObjects: jest.fn(), +})); + +jest.mock('@/object-record/hooks/useFindManyRecords', () => ({ + useFindManyRecords: jest.fn(), +})); const mockActivityTarget = { __typename: 'ActivityTarget', @@ -22,6 +25,7 @@ const mockActivityTarget = { const mockActivity = { __typename: 'Task', + companyId: '123', updatedAt: '2021-08-03T19:20:06.000Z', createdAt: '2021-08-03T19:20:06.000Z', status: 'DONE', @@ -33,168 +37,35 @@ const mockActivity = { id: '234', }; -const defaultResponseData = { - pageInfo: { - hasNextPage: false, - startCursor: '', - endCursor: '', - }, - totalCount: 1, -}; - -const mocks: MockedResponse[] = [ - { - request: { - query: gql` - query FindManyActivityTargets( - $filter: ActivityTargetFilterInput - $orderBy: [ActivityTargetOrderByInput] - $lastCursor: String - $limit: Int - ) { - activityTargets( - filter: $filter - orderBy: $orderBy - first: $limit - after: $lastCursor - ) { - edges { - node { - __typename - updatedAt - createdAt - activityId - id - } - cursor - } - pageInfo { - hasNextPage - hasPreviousPage - startCursor - endCursor - } - totalCount - } - } - `, - variables: { - filter: { companyId: { eq: '123' } }, - limit: undefined, - orderBy: undefined, - }, - }, - result: jest.fn(() => ({ - data: { - activityTargets: { - ...defaultResponseData, - edges: [ - { - node: mockActivityTarget, - cursor: '1', - }, - ], - }, - }, - })), - }, - { - request: { - query: gql` - query FindManyTasks( - $filter: TaskFilterInput - $orderBy: [TaskOrderByInput] - $lastCursor: String - $limit: Int - ) { - tasks( - filter: $filter - orderBy: $orderBy - first: $limit - after: $lastCursor - ) { - edges { - node { - __typename - title - id - updatedAt - createdAt - body - status - dueAt - } - cursor - } - pageInfo { - hasNextPage - hasPreviousPage - startCursor - endCursor - } - totalCount - } - } - `, - variables: { - filter: { id: { in: ['234'] } }, - limit: undefined, - orderBy: [{}], - }, - }, - result: jest.fn(() => ({ - data: { - activities: { - ...defaultResponseData, - edges: [ - { - node: mockActivity, - cursor: '1', - }, - ], - }, - }, - })), - }, -]; - const Wrapper = ({ children }: { children: ReactNode }) => ( - - - - {children} - - - + {children} ); describe('useActivities', () => { - it('returns default response', () => { - const { result } = renderHook( - () => - useActivities({ - objectNameSingular: CoreObjectNameSingular.Task, - targetableObjects: [], - activitiesFilters: {}, - activitiesOrderByVariables: [{}], - skip: false, - }), - { wrapper: Wrapper }, - ); - - expect(result.current).toEqual({ - activities: [], - loading: false, - }); + afterEach(() => { + jest.clearAllMocks(); }); it('fetches activities', async () => { + const useActivityTargetsForTargetableObjectsMock = jest.requireMock( + '@/activities/hooks/useActivityTargetsForTargetableObjects', + ); + useActivityTargetsForTargetableObjectsMock.useActivityTargetsForTargetableObjects.mockReturnValue( + { + activityTargets: [mockActivityTarget], + loadingActivityTargets: false, + }, + ); + + const useFindManyRecordsMock = jest.requireMock( + '@/object-record/hooks/useFindManyRecords', + ); + useFindManyRecordsMock.useFindManyRecords.mockReturnValue({ + records: [mockActivity], + }); + const { result } = renderHook( () => { - const setCurrentWorkspaceMember = useSetRecoilState( - currentWorkspaceMemberState, - ); - const activities = useActivities({ objectNameSingular: CoreObjectNameSingular.Task, targetableObjects: [ @@ -204,21 +75,11 @@ describe('useActivities', () => { activitiesOrderByVariables: [{}], skip: false, }); - return { activities, setCurrentWorkspaceMember }; + return activities; }, { wrapper: Wrapper }, ); - act(() => { - result.current.setCurrentWorkspaceMember(mockWorkspaceMembers[0]); - }); - - await waitFor(() => { - expect(result.current.activities.loading).toBe(false); - }); - - const { activities } = result.current; - - expect(activities.activities).toEqual([mockActivity]); + expect(result.current.activities).toEqual([mockActivity]); }); }); diff --git a/packages/twenty-front/src/modules/activities/timelineActivities/hooks/__tests__/useTimelineActivities.test.ts b/packages/twenty-front/src/modules/activities/timelineActivities/hooks/__tests__/useTimelineActivities.test.tsx similarity index 86% rename from packages/twenty-front/src/modules/activities/timelineActivities/hooks/__tests__/useTimelineActivities.test.ts rename to packages/twenty-front/src/modules/activities/timelineActivities/hooks/__tests__/useTimelineActivities.test.tsx index 1115a4c70..e7d0da054 100644 --- a/packages/twenty-front/src/modules/activities/timelineActivities/hooks/__tests__/useTimelineActivities.test.ts +++ b/packages/twenty-front/src/modules/activities/timelineActivities/hooks/__tests__/useTimelineActivities.test.tsx @@ -1,11 +1,17 @@ import { renderHook } from '@testing-library/react'; import { useTimelineActivities } from '@/activities/timelineActivities/hooks/useTimelineActivities'; +import { ReactNode } from 'react'; +import { RecoilRoot } from 'recoil'; jest.mock('@/object-record/hooks/useFindManyRecords', () => ({ useFindManyRecords: jest.fn(), })); +const Wrapper = ({ children }: { children: ReactNode }) => ( + {children} +); + describe('useTimelineActivities', () => { afterEach(() => { jest.clearAllMocks(); @@ -52,8 +58,9 @@ describe('useTimelineActivities', () => { records: mockedTimelineActivities, }); - const { result } = renderHook(() => - useTimelineActivities(mockTargetableObject), + const { result } = renderHook( + () => useTimelineActivities(mockTargetableObject), + { wrapper: Wrapper }, ); expect(result.current.timelineActivities).toEqual(mockedTimelineActivities); diff --git a/packages/twenty-front/src/modules/activities/timelineActivities/utils/__tests__/filterOutInvalidTimelineActivities.test.ts b/packages/twenty-front/src/modules/activities/timelineActivities/utils/__tests__/filterOutInvalidTimelineActivities.test.ts index 02ddb9282..1dc114410 100644 --- a/packages/twenty-front/src/modules/activities/timelineActivities/utils/__tests__/filterOutInvalidTimelineActivities.test.ts +++ b/packages/twenty-front/src/modules/activities/timelineActivities/utils/__tests__/filterOutInvalidTimelineActivities.test.ts @@ -1,12 +1,20 @@ import { TimelineActivity } from '@/activities/timelineActivities/types/TimelineActivity'; import { filterOutInvalidTimelineActivities } from '@/activities/timelineActivities/utils/filterOutInvalidTimelineActivities'; +import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; +const noteObjectMetadataItem = { + nameSingular: CoreObjectNameSingular.Note, + namePlural: 'notes', + fields: [{ name: 'field1' }, { name: 'field2' }, { name: 'field3' }], +} as ObjectMetadataItem; + describe('filterOutInvalidTimelineActivities', () => { it('should filter out TimelineActivities with deleted fields from the properties diff', () => { const events = [ { id: '1', + name: 'event1', properties: { diff: { field1: { before: 'value1', after: 'value2' }, @@ -17,6 +25,7 @@ describe('filterOutInvalidTimelineActivities', () => { }, { id: '2', + name: 'event2', properties: { diff: { field1: { before: 'value7', after: 'value8' }, @@ -36,12 +45,13 @@ describe('filterOutInvalidTimelineActivities', () => { const filteredEvents = filterOutInvalidTimelineActivities( events, 'objectNameSingular', - [mainObjectMetadataItem], + [mainObjectMetadataItem, noteObjectMetadataItem], ); expect(filteredEvents).toEqual([ { id: '1', + name: 'event1', properties: { diff: { field1: { before: 'value1', after: 'value2' }, @@ -52,6 +62,7 @@ describe('filterOutInvalidTimelineActivities', () => { }, { id: '2', + name: 'event2', properties: { diff: { field1: { before: 'value7', after: 'value8' }, @@ -66,6 +77,7 @@ describe('filterOutInvalidTimelineActivities', () => { const events = [ { id: '1', + name: 'event1', properties: { diff: { field3: { before: 'value5', after: 'value6' }, @@ -74,6 +86,7 @@ describe('filterOutInvalidTimelineActivities', () => { }, { id: '2', + name: 'event2', properties: { diff: { field4: { before: 'value11', after: 'value12' }, @@ -83,13 +96,15 @@ describe('filterOutInvalidTimelineActivities', () => { ] as TimelineActivity[]; const mainObjectMetadataItem = { + nameSingular: 'objectNameSingular', + namePlural: 'objectNamePlural', fields: [{ name: 'field1' }, { name: 'field2' }], } as ObjectMetadataItem; const filteredEvents = filterOutInvalidTimelineActivities( events, 'objectNameSingular', - [mainObjectMetadataItem], + [mainObjectMetadataItem, noteObjectMetadataItem], ); expect(filteredEvents).toEqual([]); @@ -99,22 +114,26 @@ describe('filterOutInvalidTimelineActivities', () => { const events = [ { id: '1', + name: 'event1', properties: {}, }, { id: '2', + name: 'event2', properties: {}, }, ] as TimelineActivity[]; const mainObjectMetadataItem = { + nameSingular: 'objectNameSingular', + namePlural: 'objectNamePlural', fields: [{ name: 'field1' }, { name: 'field2' }], } as ObjectMetadataItem; const filteredEvents = filterOutInvalidTimelineActivities( events, 'objectNameSingular', - [mainObjectMetadataItem], + [mainObjectMetadataItem, noteObjectMetadataItem], ); expect(filteredEvents).toEqual(events); diff --git a/packages/twenty-front/src/modules/activities/timelineActivities/utils/filterOutInvalidTimelineActivities.ts b/packages/twenty-front/src/modules/activities/timelineActivities/utils/filterOutInvalidTimelineActivities.ts index 1bdfcbf79..5613db9d4 100644 --- a/packages/twenty-front/src/modules/activities/timelineActivities/utils/filterOutInvalidTimelineActivities.ts +++ b/packages/twenty-front/src/modules/activities/timelineActivities/utils/filterOutInvalidTimelineActivities.ts @@ -43,7 +43,8 @@ export const filterOutInvalidTimelineActivities = ( const validDiffEntries = Object.entries(diff).filter(([diffKey]) => isNoteOrTask - ? noteFieldMetadataItemMap.has(diffKey) + ? // Note and Task objects have the same field metadata + noteFieldMetadataItemMap.has(diffKey) : fieldMetadataItemMap.has(diffKey), ); diff --git a/packages/twenty-front/src/modules/object-record/relation-picker/hooks/__tests__/useMultiObjectSearch.test.tsx b/packages/twenty-front/src/modules/object-record/relation-picker/hooks/__tests__/useMultiObjectSearch.test.tsx index 63868f068..54fb2aeaa 100644 --- a/packages/twenty-front/src/modules/object-record/relation-picker/hooks/__tests__/useMultiObjectSearch.test.tsx +++ b/packages/twenty-front/src/modules/object-record/relation-picker/hooks/__tests__/useMultiObjectSearch.test.tsx @@ -1,194 +1,139 @@ -import { gql } from '@apollo/client'; -import { MockedProvider } from '@apollo/client/testing'; -import { act, renderHook, waitFor } from '@testing-library/react'; -import { RecoilRoot, useSetRecoilState } from 'recoil'; - -import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; +import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; -import { useMultiObjectSearch } from '@/object-record/relation-picker/hooks/useMultiObjectSearch'; +import { + MultiObjectSearch, + ObjectRecordForSelect, + SelectedObjectRecordId, + useMultiObjectSearch, +} from '@/object-record/relation-picker/hooks/useMultiObjectSearch'; +import { useMultiObjectSearchMatchesSearchFilterAndSelectedItemsQuery } from '@/object-record/relation-picker/hooks/useMultiObjectSearchMatchesSearchFilterAndSelectedItemsQuery'; +import { useMultiObjectSearchMatchesSearchFilterAndToSelectQuery } from '@/object-record/relation-picker/hooks/useMultiObjectSearchMatchesSearchFilterAndToSelectQuery'; +import { useMultiObjectSearchSelectedItemsQuery } from '@/object-record/relation-picker/hooks/useMultiObjectSearchSelectedItemsQuery'; +import { renderHook } from '@testing-library/react'; import { FieldMetadataType } from '~/generated/graphql'; -const query = gql` - query CombinedFindManyRecords( - $filterNameSingular: NameSingularFilterInput - $orderByNameSingular: [NameSingularOrderByInput] - $lastCursorNameSingular: String - $limitNameSingular: Int - ) { - namePlural( - filter: $filterNameSingular - orderBy: $orderByNameSingular - first: $limitNameSingular - after: $lastCursorNameSingular - ) { - edges { - node { - __typename - id - } - cursor - } - pageInfo { - hasNextPage - startCursor - endCursor - } - totalCount - } - } -`; -const response = { - namePlural: { - edges: [{ node: { __typename: 'Custom', id: 'nodeId' }, cursor: 'cursor' }], - pageInfo: { startCursor: '', hasNextPage: '', endCursor: '' }, - }, -}; +jest.mock( + '@/object-record/relation-picker/hooks/useMultiObjectSearchSelectedItemsQuery', +); +jest.mock( + '@/object-record/relation-picker/hooks/useMultiObjectSearchMatchesSearchFilterAndSelectedItemsQuery', +); +jest.mock( + '@/object-record/relation-picker/hooks/useMultiObjectSearchMatchesSearchFilterAndToSelectQuery', +); -const mocks = [ +const objectData: ObjectMetadataItem[] = [ { - request: { - query, - variables: { - filterNameSingular: { id: { in: ['1'] } }, - orderByNameSingular: [{ createdAt: 'DescNullsLast' }], - limitNameSingular: 60, + createdAt: 'createdAt', + id: 'id', + isActive: true, + isCustom: true, + isSystem: false, + isRemote: false, + labelPlural: 'labelPlural', + labelSingular: 'labelSingular', + namePlural: 'namePlural', + nameSingular: 'nameSingular', + updatedAt: 'updatedAt', + fields: [ + { + id: 'f6a0a73a-5ee6-442e-b764-39b682471240', + name: 'id', + label: 'id', + type: FieldMetadataType.Uuid, + createdAt: '2024-01-01T00:00:00.000Z', + updatedAt: '2024-01-01T00:00:00.000Z', + isActive: true, }, - }, - result: jest.fn(() => ({ - data: response, - })), - }, - { - request: { - query, - variables: { - filterNameSingular: { and: [{}, { id: { in: ['1'] } }] }, - orderByNameSingular: [{ createdAt: 'DescNullsLast' }], - limitNameSingular: 60, - }, - }, - result: jest.fn(() => ({ - data: response, - })), - }, - { - request: { - query, - variables: { - limitNameSingular: 60, - filterNameSingular: { not: { id: { in: ['1'] } } }, - orderByNameSingular: [{ createdAt: 'DescNullsLast' }], - }, - }, - result: jest.fn(() => ({ - data: response, - })), + ], }, ]; -const Wrapper = ({ children }: { children: React.ReactNode }) => ( - - {children} - -); - describe('useMultiObjectSearch', () => { - it('should return object formatted from objectMetadataItemsState', async () => { - const { result } = renderHook( - () => ({ - multiObjects: useMultiObjectSearch({ - searchFilterValue: '', - selectedObjectRecordIds: [ - { - objectNameSingular: 'nameSingular', - id: '1', - }, - ], - }), - setObjectMetadata: useSetRecoilState(objectMetadataItemsState), - }), - { - wrapper: Wrapper, - }, - ); - const objectData: ObjectMetadataItem[] = [ - { + const selectedObjectRecordIds: SelectedObjectRecordId[] = [ + { objectNameSingular: 'object1', id: '1' }, + { objectNameSingular: 'object2', id: '2' }, + ]; + const searchFilterValue = 'searchValue'; + const limit = 5; + const excludedObjectRecordIds: SelectedObjectRecordId[] = [ + { objectNameSingular: 'object3', id: '3' }, + { objectNameSingular: 'object4', id: '4' }, + ]; + const excludedObjects: CoreObjectNameSingular[] = []; + + const selectedObjectRecords: ObjectRecordForSelect[] = [ + { + objectMetadataItem: objectData[0], + record: { + __typename: 'ObjectRecord', + id: '1', createdAt: 'createdAt', - id: 'id', - isActive: true, - isCustom: true, - isSystem: false, - isRemote: false, - labelPlural: 'labelPlural', - labelSingular: 'labelSingular', - namePlural: 'namePlural', - nameSingular: 'nameSingular', updatedAt: 'updatedAt', - fields: [ - { - id: 'f6a0a73a-5ee6-442e-b764-39b682471240', - name: 'id', - label: 'id', - type: FieldMetadataType.Uuid, - createdAt: '2024-01-01T00:00:00.000Z', - updatedAt: '2024-01-01T00:00:00.000Z', - isActive: true, - }, - ], }, - ]; - act(() => { - result.current.setObjectMetadata(objectData); - }); - await waitFor(() => { - expect(mocks[0].result).toHaveBeenCalled(); - // expect(mocks[1].result).toHaveBeenCalled(); - expect(mocks[2].result).toHaveBeenCalled(); - }); - const expectedData = [ - { - objectMetadataItem: { - createdAt: 'createdAt', - id: 'id', - isActive: true, - isCustom: true, - isSystem: false, - isRemote: false, - labelPlural: 'labelPlural', - labelSingular: 'labelSingular', - namePlural: 'namePlural', - nameSingular: 'nameSingular', - updatedAt: 'updatedAt', - fields: [ - { - id: 'f6a0a73a-5ee6-442e-b764-39b682471240', - name: 'id', - label: 'id', - isActive: true, - type: FieldMetadataType.Uuid, - createdAt: '2024-01-01T00:00:00.000Z', - updatedAt: '2024-01-01T00:00:00.000Z', - }, - ], - }, - record: { id: 'nodeId', __typename: 'Custom' }, - recordIdentifier: { - id: 'nodeId', - name: '', - avatarUrl: '', - avatarType: 'rounded', - linkToShowPage: '/object/nameSingular/nodeId', - }, + recordIdentifier: { + id: '1', + name: 'name', }, - ]; - expect(result.current.multiObjects.selectedObjectRecords).toStrictEqual( - expectedData, - ); - expect( - result.current.multiObjects.filteredSelectedObjectRecords, - ).toStrictEqual(expectedData); - expect(result.current.multiObjects.objectRecordsToSelect).toStrictEqual( - expectedData, + }, + ]; + const selectedObjectRecordsLoading = false; + + const selectedAndMatchesSearchFilterObjectRecords: ObjectRecordForSelect[] = + []; + const selectedAndMatchesSearchFilterObjectRecordsLoading = false; + + const toSelectAndMatchesSearchFilterObjectRecords: ObjectRecordForSelect[] = + []; + const toSelectAndMatchesSearchFilterObjectRecordsLoading = false; + + beforeEach(() => { + (useMultiObjectSearchSelectedItemsQuery as jest.Mock).mockReturnValue({ + selectedObjectRecords, + selectedObjectRecordsLoading, + }); + + ( + useMultiObjectSearchMatchesSearchFilterAndSelectedItemsQuery as jest.Mock + ).mockReturnValue({ + selectedAndMatchesSearchFilterObjectRecords, + selectedAndMatchesSearchFilterObjectRecordsLoading, + }); + + ( + useMultiObjectSearchMatchesSearchFilterAndToSelectQuery as jest.Mock + ).mockReturnValue({ + toSelectAndMatchesSearchFilterObjectRecords, + toSelectAndMatchesSearchFilterObjectRecordsLoading, + }); + }); + + afterEach(() => { + jest.resetAllMocks(); + }); + + it('should return the correct object records and loading state', () => { + const { result } = renderHook(() => + useMultiObjectSearch({ + searchFilterValue, + selectedObjectRecordIds, + limit, + excludedObjectRecordIds, + excludedObjects, + }), ); + + const expected: MultiObjectSearch = { + selectedObjectRecords, + filteredSelectedObjectRecords: + selectedAndMatchesSearchFilterObjectRecords, + objectRecordsToSelect: toSelectAndMatchesSearchFilterObjectRecords, + loading: + selectedAndMatchesSearchFilterObjectRecordsLoading || + toSelectAndMatchesSearchFilterObjectRecordsLoading || + selectedObjectRecordsLoading, + }; + + expect(result.current).toEqual(expected); }); });