From 7b83c84fa5fdd0bd22fe6c17bcc6a246b73b4533 Mon Sep 17 00:00:00 2001 From: "gitstart-app[bot]" <57568882+gitstart-app[bot]@users.noreply.github.com> Date: Fri, 15 Mar 2024 16:30:42 +0100 Subject: [PATCH] TWNTY-4447 - Add tests for `/modules/activities/hooks` (#4475) Add tests for `/modules/activities/hooks` Co-authored-by: gitstart-twenty Co-authored-by: v1b3m --- .../hooks/__tests__/useActivities.test.tsx | 242 ++++++++++++++++++ .../hooks/__tests__/useActivityById.test.tsx | 80 ++++++ .../useActivityConnectionUtils.test.tsx | 8 - .../useActivityTargetObjectRecords.test.tsx | 223 ++++++++++++++++ ...ctivityTargetsForTargetableObject.test.tsx | 129 ++++++++++ ...useAttachRelationInBothDirections.test.tsx | 76 ++++++ .../useCreateActivityInCache.test.tsx | 99 +++++++ .../__tests__/useCreateActivityInDB.test.tsx | 90 +++++++ .../useDeleteActivityFromCache.test.tsx | 53 ++++ .../useInjectIntoActivitiesQueries.test.tsx | 60 +++++ ...eInjectIntoActivityTargetsQueries.test.tsx | 64 +++++ ...ifyActivityOnActivityTargetsCache.test.tsx | 44 ++++ ...ifyActivityTargetsOnActivityCache.test.tsx | 43 ++++ .../useOpenActivityRightDrawer.test.tsx | 42 +++ .../useOpenCreateActivityDrawer.test.tsx | 63 +++++ ...teActivityDrawerForSelectedRowIds.test.tsx | 110 ++++++++ .../useRemoveFromActivitiesQueries.test.tsx | 63 +++++ ...eRemoveFromActivityTargetsQueries.test.tsx | 72 ++++++ .../__tests__/useUpsertActivity.test.tsx | 187 ++++++++++++++ 19 files changed, 1740 insertions(+), 8 deletions(-) create mode 100644 packages/twenty-front/src/modules/activities/hooks/__tests__/useActivities.test.tsx create mode 100644 packages/twenty-front/src/modules/activities/hooks/__tests__/useActivityById.test.tsx create mode 100644 packages/twenty-front/src/modules/activities/hooks/__tests__/useActivityTargetObjectRecords.test.tsx create mode 100644 packages/twenty-front/src/modules/activities/hooks/__tests__/useActivityTargetsForTargetableObject.test.tsx create mode 100644 packages/twenty-front/src/modules/activities/hooks/__tests__/useAttachRelationInBothDirections.test.tsx create mode 100644 packages/twenty-front/src/modules/activities/hooks/__tests__/useCreateActivityInCache.test.tsx create mode 100644 packages/twenty-front/src/modules/activities/hooks/__tests__/useCreateActivityInDB.test.tsx create mode 100644 packages/twenty-front/src/modules/activities/hooks/__tests__/useDeleteActivityFromCache.test.tsx create mode 100644 packages/twenty-front/src/modules/activities/hooks/__tests__/useInjectIntoActivitiesQueries.test.tsx create mode 100644 packages/twenty-front/src/modules/activities/hooks/__tests__/useInjectIntoActivityTargetsQueries.test.tsx create mode 100644 packages/twenty-front/src/modules/activities/hooks/__tests__/useModifyActivityOnActivityTargetsCache.test.tsx create mode 100644 packages/twenty-front/src/modules/activities/hooks/__tests__/useModifyActivityTargetsOnActivityCache.test.tsx create mode 100644 packages/twenty-front/src/modules/activities/hooks/__tests__/useOpenActivityRightDrawer.test.tsx create mode 100644 packages/twenty-front/src/modules/activities/hooks/__tests__/useOpenCreateActivityDrawer.test.tsx create mode 100644 packages/twenty-front/src/modules/activities/hooks/__tests__/useOpenCreateActivityDrawerForSelectedRowIds.test.tsx create mode 100644 packages/twenty-front/src/modules/activities/hooks/__tests__/useRemoveFromActivitiesQueries.test.tsx create mode 100644 packages/twenty-front/src/modules/activities/hooks/__tests__/useRemoveFromActivityTargetsQueries.test.tsx create mode 100644 packages/twenty-front/src/modules/activities/hooks/__tests__/useUpsertActivity.test.tsx 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 new file mode 100644 index 0000000000..56730f9c8f --- /dev/null +++ b/packages/twenty-front/src/modules/activities/hooks/__tests__/useActivities.test.tsx @@ -0,0 +1,242 @@ +import { ReactNode } from 'react'; +import { gql } from '@apollo/client'; +import { MockedProvider, MockedResponse } from '@apollo/client/testing'; +import { act, renderHook, waitFor } from '@testing-library/react'; +import { RecoilRoot, useSetRecoilState } from 'recoil'; + +import { useActivities } from '@/activities/hooks/useActivities'; +import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState'; +import { SnackBarProviderScope } from '@/ui/feedback/snack-bar-manager/scopes/SnackBarProviderScope'; +import { mockWorkspaceMembers } from '~/testing/mock-data/workspace-members'; + +const mockActivityTarget = { + __typename: 'ActivityTarget', + updatedAt: '2021-08-03T19:20:06.000Z', + createdAt: '2021-08-03T19:20:06.000Z', + personId: '1', + activityId: '234', + companyId: '1', + id: '123', +}; + +const mockActivity = { + __typename: 'Activity', + activityTargets: [], + updatedAt: '2021-08-03T19:20:06.000Z', + createdAt: '2021-08-03T19:20:06.000Z', + completedAt: '2021-08-03T19:20:06.000Z', + reminderAt: '2021-08-03T19:20:06.000Z', + title: 'title', + authorId: '1', + body: 'body', + comments: [], + dueAt: '2021-08-03T19:20:06.000Z', + type: 'type', + assigneeId: '1', + 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: Float + ) { + activityTargets( + filter: $filter + orderBy: $orderBy + first: $limit + after: $lastCursor + ) { + edges { + node { + __typename + updatedAt + createdAt + personId + activityId + companyId + id + } + cursor + } + pageInfo { + hasNextPage + startCursor + endCursor + } + totalCount + } + } + `, + variables: { + filter: { activityTargetId: { eq: '123' } }, + limit: undefined, + orderBy: undefined, + }, + }, + result: jest.fn(() => ({ + data: { + activityTargets: { + ...defaultResponseData, + edges: [ + { + node: mockActivityTarget, + cursor: '1', + }, + ], + }, + }, + })), + }, + { + request: { + query: gql` + query FindManyActivities( + $filter: ActivityFilterInput + $orderBy: ActivityOrderByInput + $lastCursor: String + $limit: Float + ) { + activities( + filter: $filter + orderBy: $orderBy + first: $limit + after: $lastCursor + ) { + edges { + node { + __typename + createdAt + reminderAt + authorId + title + completedAt + updatedAt + body + dueAt + type + id + assigneeId + } + cursor + } + pageInfo { + hasNextPage + 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} + + + +); + +describe('useActivities', () => { + it('returns default response', () => { + const { result } = renderHook( + () => + useActivities({ + targetableObjects: [], + activitiesFilters: {}, + activitiesOrderByVariables: {}, + skip: false, + skipActivityTargets: false, + }), + { wrapper: Wrapper }, + ); + + expect(result.current).toEqual({ + activities: [], + loading: false, + initialized: true, + noActivities: true, + }); + }); + + it('fetches activities', async () => { + const { result } = renderHook( + () => { + const setCurrentWorkspaceMember = useSetRecoilState( + currentWorkspaceMemberState(), + ); + + const activities = useActivities({ + targetableObjects: [ + { targetObjectNameSingular: 'activityTarget', id: '123' }, + ], + activitiesFilters: {}, + activitiesOrderByVariables: {}, + skip: false, + skipActivityTargets: false, + }); + return { activities, setCurrentWorkspaceMember }; + }, + { wrapper: Wrapper }, + ); + + act(() => { + result.current.setCurrentWorkspaceMember(mockWorkspaceMembers[0]); + }); + + expect(result.current.activities.loading).toBe(true); + + // Wait for activityTargets to complete fetching + await waitFor(() => !result.current.activities.loading); + + expect(result.current.activities.loading).toBe(false); + + // Wait for request to fetch activities to be made + await waitFor(() => result.current.activities.loading); + + // Wait for activities to complete fetching + await waitFor(() => !result.current.activities.loading); + + const { activities } = result.current; + + expect(activities.activities).toEqual([mockActivity]); + }); +}); diff --git a/packages/twenty-front/src/modules/activities/hooks/__tests__/useActivityById.test.tsx b/packages/twenty-front/src/modules/activities/hooks/__tests__/useActivityById.test.tsx new file mode 100644 index 0000000000..4db2793e09 --- /dev/null +++ b/packages/twenty-front/src/modules/activities/hooks/__tests__/useActivityById.test.tsx @@ -0,0 +1,80 @@ +import { ReactNode } from 'react'; +import { MockedProvider, MockedResponse } from '@apollo/client/testing'; +import { renderHook, waitFor } from '@testing-library/react'; +import gql from 'graphql-tag'; +import { RecoilRoot } from 'recoil'; + +import { useActivityById } from '@/activities/hooks/useActivityById'; +import { SnackBarProviderScope } from '@/ui/feedback/snack-bar-manager/scopes/SnackBarProviderScope'; +import { mockedActivities } from '~/testing/mock-data/activities'; + +const mocks: MockedResponse[] = [ + { + request: { + query: gql` + query FindOneActivity($objectRecordId: UUID!) { + activity(filter: { id: { eq: $objectRecordId } }) { + __typename + createdAt + reminderAt + authorId + title + completedAt + updatedAt + body + dueAt + type + id + assigneeId + } + } + `, + variables: { objectRecordId: '1234' }, + }, + result: jest.fn(() => ({ + data: { + activity: mockedActivities[0], + }, + })), + }, +]; + +const Wrapper = ({ children }: { children: ReactNode }) => ( + + + + {children} + + + +); + +describe('useActivityById', () => { + it('works as expected', async () => { + const { result } = renderHook( + () => useActivityById({ activityId: '1234' }), + { wrapper: Wrapper }, + ); + + expect(result.current.loading).toBe(true); + + await waitFor(() => !result.current.loading); + + expect(result.current.activity).toEqual({ + __typename: 'Activity', + assigneeId: '374fe3a5-df1e-4119-afe0-2a62a2ba481e', + authorId: '374fe3a5-df1e-4119-afe0-2a62a2ba481e', + body: '', + comments: [], + completedAt: null, + createdAt: '2023-04-26T10:12:42.33625+00:00', + activityTargets: [], + dueAt: '2023-04-26T10:12:42.33625+00:00', + id: '3ecaa1be-aac7-463a-a38e-64078dd451d5', + reminderAt: null, + title: 'My very first note', + type: 'Note', + updatedAt: '2023-04-26T10:23:42.33625+00:00', + }); + }); +}); diff --git a/packages/twenty-front/src/modules/activities/hooks/__tests__/useActivityConnectionUtils.test.tsx b/packages/twenty-front/src/modules/activities/hooks/__tests__/useActivityConnectionUtils.test.tsx index 88da90b3a4..ddda904ee4 100644 --- a/packages/twenty-front/src/modules/activities/hooks/__tests__/useActivityConnectionUtils.test.tsx +++ b/packages/twenty-front/src/modules/activities/hooks/__tests__/useActivityConnectionUtils.test.tsx @@ -104,14 +104,6 @@ describe('useActivityConnectionUtils', () => { expect(activityWithConnection).toBeDefined(); - console.log( - JSON.stringify({ - mockActivityWithConnectionRelation, - activityWithConnection, - mockActivityWithArrayRelation, - }), - ); - expect(activityWithConnection.activityTargets.edges[0].node.id).toEqual( mockActivityWithConnectionRelation.activityTargets.edges[0].node.id, ); diff --git a/packages/twenty-front/src/modules/activities/hooks/__tests__/useActivityTargetObjectRecords.test.tsx b/packages/twenty-front/src/modules/activities/hooks/__tests__/useActivityTargetObjectRecords.test.tsx new file mode 100644 index 0000000000..0a1b8f7b40 --- /dev/null +++ b/packages/twenty-front/src/modules/activities/hooks/__tests__/useActivityTargetObjectRecords.test.tsx @@ -0,0 +1,223 @@ +import { ReactNode } from 'react'; +import { MockedProvider, MockedResponse } from '@apollo/client/testing'; +import { act, renderHook, waitFor } from '@testing-library/react'; +import gql from 'graphql-tag'; +import { RecoilRoot, useSetRecoilState } from 'recoil'; + +import { useActivityTargetObjectRecords } from '@/activities/hooks/useActivityTargetObjectRecords'; +import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState'; +import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; +import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock'; +import { SnackBarProviderScope } from '@/ui/feedback/snack-bar-manager/scopes/SnackBarProviderScope'; +import { mockedActivities } from '~/testing/mock-data/activities'; +import { mockedCompaniesData } from '~/testing/mock-data/companies'; +import { mockedPeopleData } from '~/testing/mock-data/people'; +import { mockWorkspaceMembers } from '~/testing/mock-data/workspace-members'; + +const defaultResponseData = { + pageInfo: { + hasNextPage: false, + startCursor: '', + endCursor: '', + }, + totalCount: 1, +}; + +const mockActivityTarget = { + __typename: 'ActivityTarget', + updatedAt: '2021-08-03T19:20:06.000Z', + createdAt: '2021-08-03T19:20:06.000Z', + personId: '1', + activityId: '234', + companyId: '1', + id: '123', + person: { ...mockedPeopleData[0], __typename: 'Person', updatedAt: '' }, + company: { ...mockedCompaniesData[0], __typename: 'Company', updatedAt: '' }, + activity: mockedActivities[0], +}; + +const mocks: MockedResponse[] = [ + { + request: { + query: gql` + query FindManyActivityTargets( + $filter: ActivityTargetFilterInput + $orderBy: ActivityTargetOrderByInput + $lastCursor: String + $limit: Float + ) { + activityTargets( + filter: $filter + orderBy: $orderBy + first: $limit + after: $lastCursor + ) { + edges { + node { + __typename + updatedAt + createdAt + company { + __typename + xLink { + label + url + } + linkedinLink { + label + url + } + domainName + annualRecurringRevenue { + amountMicros + currencyCode + } + createdAt + address + updatedAt + name + accountOwnerId + employees + id + idealCustomerProfile + } + personId + activityId + companyId + id + activity { + __typename + createdAt + reminderAt + authorId + title + completedAt + updatedAt + body + dueAt + type + id + assigneeId + } + person { + __typename + xLink { + label + url + } + id + createdAt + city + email + jobTitle + name { + firstName + lastName + } + phone + linkedinLink { + label + url + } + updatedAt + avatarUrl + companyId + } + } + cursor + } + pageInfo { + hasNextPage + startCursor + endCursor + } + totalCount + } + } + `, + variables: { + filter: { activityId: { eq: '1234' } }, + limit: undefined, + orderBy: undefined, + }, + }, + result: jest.fn(() => ({ + data: { + activityTargets: { + ...defaultResponseData, + edges: [ + { + node: mockActivityTarget, + cursor: '1', + }, + ], + }, + }, + })), + }, +]; + +const mockObjectMetadataItems = getObjectMetadataItemsMock(); + +const Wrapper = ({ children }: { children: ReactNode }) => ( + + + + {children} + + + +); + +describe('useActivityTargetObjectRecords', () => { + it('returns default response', () => { + const { result } = renderHook( + () => useActivityTargetObjectRecords({ activityId: '1234' }), + { wrapper: Wrapper }, + ); + + expect(result.current).toEqual({ + activityTargetObjectRecords: [], + loadingActivityTargets: false, + }); + }); + + it('fetches records', async () => { + const { result } = renderHook( + () => { + const setCurrentWorkspaceMember = useSetRecoilState( + currentWorkspaceMemberState(), + ); + const setObjectMetadataItems = useSetRecoilState( + objectMetadataItemsState(), + ); + + const { activityTargetObjectRecords, loadingActivityTargets } = + useActivityTargetObjectRecords({ activityId: '1234' }); + return { + activityTargetObjectRecords, + loadingActivityTargets, + setCurrentWorkspaceMember, + setObjectMetadataItems, + }; + }, + { wrapper: Wrapper }, + ); + + act(() => { + result.current.setCurrentWorkspaceMember(mockWorkspaceMembers[0]); + result.current.setObjectMetadataItems(mockObjectMetadataItems); + }); + + expect(result.current.loadingActivityTargets).toBe(true); + + // Wait for activityTargets to complete fetching + await waitFor(() => !result.current.loadingActivityTargets); + + expect(mocks[0].result).toHaveBeenCalled(); + expect(result.current.activityTargetObjectRecords).toHaveLength(1); + expect( + result.current.activityTargetObjectRecords[0].targetObjectNameSingular, + ).toBe('person'); + }); +}); diff --git a/packages/twenty-front/src/modules/activities/hooks/__tests__/useActivityTargetsForTargetableObject.test.tsx b/packages/twenty-front/src/modules/activities/hooks/__tests__/useActivityTargetsForTargetableObject.test.tsx new file mode 100644 index 0000000000..e1e55e9c31 --- /dev/null +++ b/packages/twenty-front/src/modules/activities/hooks/__tests__/useActivityTargetsForTargetableObject.test.tsx @@ -0,0 +1,129 @@ +import { ReactNode } from 'react'; +import { MockedProvider, MockedResponse } from '@apollo/client/testing'; +import { act, renderHook, waitFor } from '@testing-library/react'; +import gql from 'graphql-tag'; +import { RecoilRoot, useSetRecoilState } from 'recoil'; + +import { useActivityTargetsForTargetableObject } from '@/activities/hooks/useActivityTargetsForTargetableObject'; +import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState'; +import { SnackBarProviderScope } from '@/ui/feedback/snack-bar-manager/scopes/SnackBarProviderScope'; +import { mockWorkspaceMembers } from '~/testing/mock-data/workspace-members'; + +const mockActivityTarget = { + __typename: 'ActivityTarget', + updatedAt: '2021-08-03T19:20:06.000Z', + createdAt: '2021-08-03T19:20:06.000Z', + personId: '1', + activityId: '234', + companyId: '1', + id: '123', +}; + +const defaultResponseData = { + pageInfo: { + hasNextPage: false, + startCursor: '', + endCursor: '', + }, + totalCount: 1, +}; + +const mocks: MockedResponse[] = [ + { + request: { + query: gql` + query FindManyActivityTargets( + $filter: ActivityTargetFilterInput + $orderBy: ActivityTargetOrderByInput + $lastCursor: String + $limit: Float + ) { + activityTargets( + filter: $filter + orderBy: $orderBy + first: $limit + after: $lastCursor + ) { + edges { + node { + __typename + updatedAt + createdAt + personId + activityId + companyId + id + } + cursor + } + pageInfo { + hasNextPage + startCursor + endCursor + } + totalCount + } + } + `, + variables: { + filter: { personId: { eq: '1234' } }, + limit: undefined, + orderBy: undefined, + }, + }, + result: jest.fn(() => ({ + data: { + activityTargets: { + ...defaultResponseData, + edges: [ + { + node: mockActivityTarget, + cursor: '1', + }, + ], + }, + }, + })), + }, +]; + +const Wrapper = ({ children }: { children: ReactNode }) => ( + + + + {children} + + + +); + +describe('useActivityTargetsForTargetableObject', () => { + it('works as expected', async () => { + const { result } = renderHook( + () => { + const setCurrentWorkspaceMember = useSetRecoilState( + currentWorkspaceMemberState(), + ); + + const res = useActivityTargetsForTargetableObject({ + targetableObject: { + id: '1234', + targetObjectNameSingular: 'person', + }, + }); + return { ...res, setCurrentWorkspaceMember }; + }, + { wrapper: Wrapper }, + ); + + act(() => { + result.current.setCurrentWorkspaceMember(mockWorkspaceMembers[0]); + }); + + expect(result.current.loadingActivityTargets).toBe(true); + + await waitFor(() => !result.current.loadingActivityTargets); + + expect(result.current.activityTargets).toEqual([mockActivityTarget]); + }); +}); diff --git a/packages/twenty-front/src/modules/activities/hooks/__tests__/useAttachRelationInBothDirections.test.tsx b/packages/twenty-front/src/modules/activities/hooks/__tests__/useAttachRelationInBothDirections.test.tsx new file mode 100644 index 0000000000..e55118b7a0 --- /dev/null +++ b/packages/twenty-front/src/modules/activities/hooks/__tests__/useAttachRelationInBothDirections.test.tsx @@ -0,0 +1,76 @@ +import { ReactNode } from 'react'; +import { MockedProvider, MockedResponse } from '@apollo/client/testing'; +import { act, renderHook } from '@testing-library/react'; +import { RecoilRoot, useSetRecoilState } from 'recoil'; + +import { useAttachRelationInBothDirections } from '@/activities/hooks/useAttachRelationInBothDirections'; +import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState'; +import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; +import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock'; +import { SnackBarProviderScope } from '@/ui/feedback/snack-bar-manager/scopes/SnackBarProviderScope'; +import { mockWorkspaceMembers } from '~/testing/mock-data/workspace-members'; + +const mocks: MockedResponse[] = []; + +const Wrapper = ({ children }: { children: ReactNode }) => ( + + + + {children} + + + +); + +const mockObjectMetadataItems = getObjectMetadataItemsMock(); + +describe('useAttachRelationInBothDirections', () => { + it('works as expected', () => { + const { result } = renderHook( + () => { + const setCurrentWorkspaceMember = useSetRecoilState( + currentWorkspaceMemberState(), + ); + const setObjectMetadataItems = useSetRecoilState( + objectMetadataItemsState(), + ); + + const res = useAttachRelationInBothDirections(); + return { + ...res, + setCurrentWorkspaceMember, + setObjectMetadataItems, + }; + }, + { wrapper: Wrapper }, + ); + + act(() => { + result.current.setCurrentWorkspaceMember(mockWorkspaceMembers[0]); + result.current.setObjectMetadataItems(mockObjectMetadataItems); + }); + const targetRecords = [ + { id: '5678', person: { id: '1234' } }, + { id: '91011', person: { id: '1234' } }, + ]; + + const forEachSpy = jest.spyOn(targetRecords, 'forEach'); + + act(() => { + result.current.attachRelationInBothDirections({ + sourceRecord: { + id: '1234', + company: { id: '5678' }, + }, + targetRecords, + sourceObjectNameSingular: 'person', + targetObjectNameSingular: 'company', + fieldNameOnSourceRecord: 'company', + fieldNameOnTargetRecord: 'person', + }); + }); + + // expect forEach to have been called on targetRecords + expect(forEachSpy).toHaveBeenCalled(); + }); +}); diff --git a/packages/twenty-front/src/modules/activities/hooks/__tests__/useCreateActivityInCache.test.tsx b/packages/twenty-front/src/modules/activities/hooks/__tests__/useCreateActivityInCache.test.tsx new file mode 100644 index 0000000000..08a571a2e7 --- /dev/null +++ b/packages/twenty-front/src/modules/activities/hooks/__tests__/useCreateActivityInCache.test.tsx @@ -0,0 +1,99 @@ +import { ReactNode } from 'react'; +import { MockedProvider, MockedResponse } from '@apollo/client/testing'; +import { act, renderHook } from '@testing-library/react'; +import gql from 'graphql-tag'; +import { RecoilRoot, useSetRecoilState } from 'recoil'; + +import { useCreateActivityInCache } from '@/activities/hooks/useCreateActivityInCache'; +import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState'; +import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; +import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock'; +import { SnackBarProviderScope } from '@/ui/feedback/snack-bar-manager/scopes/SnackBarProviderScope'; +import { mockWorkspaceMembers } from '~/testing/mock-data/workspace-members'; + +const mocks: MockedResponse[] = [ + { + request: { + query: gql` + query FindOneWorkspaceMember($objectRecordId: UUID!) { + workspaceMember(filter: { id: { eq: $objectRecordId } }) { + __typename + colorScheme + name { + firstName + lastName + } + locale + userId + avatarUrl + createdAt + updatedAt + id + } + } + `, + variables: { objectRecordId: '20202020-1553-45c6-a028-5a9064cce07f' }, + }, + result: jest.fn(() => ({ + data: { + workspaceMember: mockWorkspaceMembers[0], + }, + })), + }, +]; + +const Wrapper = ({ children }: { children: ReactNode }) => ( + + + + {children} + + + +); + +const mockObjectMetadataItems = getObjectMetadataItemsMock(); + +describe('useCreateActivityInCache', () => { + it('Should create activity in cache', async () => { + const { result } = renderHook( + () => { + const setCurrentWorkspaceMember = useSetRecoilState( + currentWorkspaceMemberState(), + ); + const setObjectMetadataItems = useSetRecoilState( + objectMetadataItemsState(), + ); + + const res = useCreateActivityInCache(); + return { + ...res, + setCurrentWorkspaceMember, + setObjectMetadataItems, + }; + }, + { wrapper: Wrapper }, + ); + + act(() => { + result.current.setCurrentWorkspaceMember(mockWorkspaceMembers[0]); + result.current.setObjectMetadataItems(mockObjectMetadataItems); + }); + + act(() => { + const res = result.current.createActivityInCache({ + type: 'Note', + targetableObjects: [ + { + targetObjectNameSingular: 'person', + id: '1234', + }, + ], + }); + + expect(res.createdActivityInCache).toHaveProperty('id'); + expect(res.createdActivityInCache).toHaveProperty('__typename'); + expect(res.createdActivityInCache).toHaveProperty('activityTargets'); + }); + }); +}); diff --git a/packages/twenty-front/src/modules/activities/hooks/__tests__/useCreateActivityInDB.test.tsx b/packages/twenty-front/src/modules/activities/hooks/__tests__/useCreateActivityInDB.test.tsx new file mode 100644 index 0000000000..5c982afaac --- /dev/null +++ b/packages/twenty-front/src/modules/activities/hooks/__tests__/useCreateActivityInDB.test.tsx @@ -0,0 +1,90 @@ +import { ReactNode } from 'react'; +import { MockedProvider, MockedResponse } from '@apollo/client/testing'; +import { act, renderHook } from '@testing-library/react'; +import gql from 'graphql-tag'; +import pick from 'lodash/pick'; +import { RecoilRoot } from 'recoil'; + +import { useCreateActivityInDB } from '@/activities/hooks/useCreateActivityInDB'; +import { SnackBarProviderScope } from '@/ui/feedback/snack-bar-manager/scopes/SnackBarProviderScope'; +import { mockedActivities } from '~/testing/mock-data/activities'; + +const mockedDate = '2024-03-15T12:00:00.000Z'; +const toISOStringMock = jest.fn(() => mockedDate); +global.Date.prototype.toISOString = toISOStringMock; + +const mockedActivity = { + ...pick(mockedActivities[0], [ + 'id', + 'title', + 'body', + 'type', + 'completedAt', + 'dueAt', + ]), + updatedAt: mockedDate, +}; + +const mocks: MockedResponse[] = [ + { + request: { + query: gql` + mutation CreateOneActivity($input: ActivityCreateInput!) { + createActivity(data: $input) { + __typename + createdAt + reminderAt + authorId + title + completedAt + updatedAt + body + dueAt + type + id + assigneeId + } + } + `, + variables: { + input: mockedActivity, + }, + }, + result: jest.fn(() => ({ + data: { + createActivity: { + ...mockedActivity, + __typename: 'Activity', + assigneeId: '', + authorId: '1', + reminderAt: null, + createdAt: mockedDate, + }, + }, + })), + }, +]; + +const Wrapper = ({ children }: { children: ReactNode }) => ( + + + + {children} + + + +); + +describe('useCreateActivityInDB', () => { + it('Should create activity in DB', async () => { + const { result } = renderHook(() => useCreateActivityInDB(), { + wrapper: Wrapper, + }); + + await act(async () => { + await result.current.createActivityInDB(mockedActivity); + }); + + expect(mocks[0].result).toHaveBeenCalled(); + }); +}); diff --git a/packages/twenty-front/src/modules/activities/hooks/__tests__/useDeleteActivityFromCache.test.tsx b/packages/twenty-front/src/modules/activities/hooks/__tests__/useDeleteActivityFromCache.test.tsx new file mode 100644 index 0000000000..e999f63944 --- /dev/null +++ b/packages/twenty-front/src/modules/activities/hooks/__tests__/useDeleteActivityFromCache.test.tsx @@ -0,0 +1,53 @@ +import { ReactNode } from 'react'; +import { MockedProvider } from '@apollo/client/testing'; +import { act, renderHook } from '@testing-library/react'; +import pick from 'lodash.pick'; +import { RecoilRoot } from 'recoil'; + +import { useDeleteActivityFromCache } from '@/activities/hooks/useDeleteActivityFromCache'; +import { triggerDeleteRecordsOptimisticEffect } from '@/apollo/optimistic-effect/utils/triggerDeleteRecordsOptimisticEffect'; +import { mockedActivities } from '~/testing/mock-data/activities'; + +const triggerDeleteRecordsOptimisticEffectMock = jest.fn(); + +// mock the triggerDeleteRecordsOptimisticEffect function +jest.mock( + '@/apollo/optimistic-effect/utils/triggerDeleteRecordsOptimisticEffect', + () => ({ + triggerDeleteRecordsOptimisticEffect: jest.fn(), + }), +); + +(triggerDeleteRecordsOptimisticEffect as jest.Mock).mockImplementation( + triggerDeleteRecordsOptimisticEffectMock, +); + +const Wrapper = ({ children }: { children: ReactNode }) => ( + + {children} + +); + +describe('useDeleteActivityFromCache', () => { + it('works as expected', () => { + const { result } = renderHook(() => useDeleteActivityFromCache(), { + wrapper: Wrapper, + }); + + act(() => { + result.current.deleteActivityFromCache( + pick(mockedActivities[0], [ + 'id', + 'title', + 'body', + 'type', + 'completedAt', + 'dueAt', + 'updatedAt', + ]), + ); + + expect(triggerDeleteRecordsOptimisticEffectMock).toHaveBeenCalledTimes(1); + }); + }); +}); diff --git a/packages/twenty-front/src/modules/activities/hooks/__tests__/useInjectIntoActivitiesQueries.test.tsx b/packages/twenty-front/src/modules/activities/hooks/__tests__/useInjectIntoActivitiesQueries.test.tsx new file mode 100644 index 0000000000..f965c403f3 --- /dev/null +++ b/packages/twenty-front/src/modules/activities/hooks/__tests__/useInjectIntoActivitiesQueries.test.tsx @@ -0,0 +1,60 @@ +import { ReactNode } from 'react'; +import { MockedProvider } from '@apollo/client/testing'; +import { act, renderHook } from '@testing-library/react'; +import { RecoilRoot } from 'recoil'; + +import { useInjectIntoActivitiesQueries } from '@/activities/hooks/useInjectIntoActivitiesQueries'; +import { useUpsertFindManyRecordsQueryInCache } from '@/object-record/cache/hooks/useUpsertFindManyRecordsQueryInCache'; +import { SnackBarProviderScope } from '@/ui/feedback/snack-bar-manager/scopes/SnackBarProviderScope'; +import { mockedActivities } from '~/testing/mock-data/activities'; + +const upsertFindManyRecordsQueryInCacheMock = jest.fn(); + +jest.mock( + '@/object-record/cache/hooks/useUpsertFindManyRecordsQueryInCache', + () => ({ + useUpsertFindManyRecordsQueryInCache: jest.fn(), + }), +); + +(useUpsertFindManyRecordsQueryInCache as jest.Mock).mockImplementation(() => ({ + upsertFindManyRecordsQueryInCache: upsertFindManyRecordsQueryInCacheMock, +})); + +const Wrapper = ({ children }: { children: ReactNode }) => ( + + + + {children} + + + +); + +describe('useInjectIntoActivitiesQueries', () => { + it('works as expected', () => { + const { result } = renderHook(() => useInjectIntoActivitiesQueries(), { + wrapper: Wrapper, + }); + + act(() => { + result.current.injectActivitiesQueries({ + activityToInject: mockedActivities[0], + activityTargetsToInject: [], + targetableObjects: [{ id: '123', targetObjectNameSingular: 'person' }], + }); + + expect(upsertFindManyRecordsQueryInCacheMock).toHaveBeenCalledTimes(1); + }); + + act(() => { + result.current.injectActivitiesQueries({ + activityToInject: mockedActivities[0], + activityTargetsToInject: [], + targetableObjects: [], + }); + + expect(upsertFindManyRecordsQueryInCacheMock).toHaveBeenCalledTimes(2); + }); + }); +}); diff --git a/packages/twenty-front/src/modules/activities/hooks/__tests__/useInjectIntoActivityTargetsQueries.test.tsx b/packages/twenty-front/src/modules/activities/hooks/__tests__/useInjectIntoActivityTargetsQueries.test.tsx new file mode 100644 index 0000000000..969b63943d --- /dev/null +++ b/packages/twenty-front/src/modules/activities/hooks/__tests__/useInjectIntoActivityTargetsQueries.test.tsx @@ -0,0 +1,64 @@ +import { ReactNode } from 'react'; +import { MockedProvider } from '@apollo/client/testing'; +import { act, renderHook } from '@testing-library/react'; +import { RecoilRoot } from 'recoil'; + +import { useInjectIntoActivityTargetsQueries } from '@/activities/hooks/useInjectIntoActivityTargetsQueries'; +import { useUpsertFindManyRecordsQueryInCache } from '@/object-record/cache/hooks/useUpsertFindManyRecordsQueryInCache'; +import { mockedActivities } from '~/testing/mock-data/activities'; + +const upsertFindManyRecordsQueryInCacheMock = jest.fn(); + +jest.mock( + '@/object-record/cache/hooks/useUpsertFindManyRecordsQueryInCache', + () => ({ + useUpsertFindManyRecordsQueryInCache: jest.fn(), + }), +); + +(useUpsertFindManyRecordsQueryInCache as jest.Mock).mockImplementation(() => ({ + upsertFindManyRecordsQueryInCache: upsertFindManyRecordsQueryInCacheMock, +})); + +const mockActivityTarget = { + __typename: 'ActivityTarget', + updatedAt: '2021-08-03T19:20:06.000Z', + createdAt: '2021-08-03T19:20:06.000Z', + personId: '1', + activityId: '234', + companyId: '1', + id: '123', + activity: mockedActivities[0], +}; + +const Wrapper = ({ children }: { children: ReactNode }) => ( + + {children} + +); + +describe('useInjectIntoActivityTargetsQueries', () => { + it('works as expected', () => { + const { result } = renderHook(() => useInjectIntoActivityTargetsQueries(), { + wrapper: Wrapper, + }); + + act(() => { + result.current.injectActivityTargetsQueries({ + activityTargetsToInject: [mockActivityTarget], + targetableObjects: [{ id: '123', targetObjectNameSingular: 'person' }], + }); + + expect(upsertFindManyRecordsQueryInCacheMock).toHaveBeenCalledTimes(1); + }); + + act(() => { + result.current.injectActivityTargetsQueries({ + activityTargetsToInject: [mockActivityTarget], + targetableObjects: [], + }); + + expect(upsertFindManyRecordsQueryInCacheMock).toHaveBeenCalledTimes(1); + }); + }); +}); diff --git a/packages/twenty-front/src/modules/activities/hooks/__tests__/useModifyActivityOnActivityTargetsCache.test.tsx b/packages/twenty-front/src/modules/activities/hooks/__tests__/useModifyActivityOnActivityTargetsCache.test.tsx new file mode 100644 index 0000000000..b5858858bd --- /dev/null +++ b/packages/twenty-front/src/modules/activities/hooks/__tests__/useModifyActivityOnActivityTargetsCache.test.tsx @@ -0,0 +1,44 @@ +import { ReactNode } from 'react'; +import { MockedProvider } from '@apollo/client/testing'; +import { act, renderHook } from '@testing-library/react'; +import { RecoilRoot } from 'recoil'; + +import { useModifyActivityOnActivityTargetsCache } from '@/activities/hooks/useModifyActivityOnActivityTargetCache'; +import { useModifyRecordFromCache } from '@/object-record/cache/hooks/useModifyRecordFromCache'; +import { mockedActivities } from '~/testing/mock-data/activities'; + +const useModifyRecordFromCacheMock = jest.fn(); + +jest.mock('@/object-record/cache/hooks/useModifyRecordFromCache', () => ({ + useModifyRecordFromCache: jest.fn(), +})); + +(useModifyRecordFromCache as jest.Mock).mockImplementation( + () => useModifyRecordFromCacheMock, +); + +const Wrapper = ({ children }: { children: ReactNode }) => ( + + {children} + +); + +describe('useModifyActivityOnActivityTargetsCache', () => { + it('works as expected', () => { + const { result } = renderHook( + () => useModifyActivityOnActivityTargetsCache(), + { + wrapper: Wrapper, + }, + ); + + act(() => { + result.current.modifyActivityOnActivityTargetsCache({ + activity: mockedActivities[0], + activityTargetIds: ['123', '456'], + }); + }); + + expect(useModifyRecordFromCacheMock).toHaveBeenCalled(); + }); +}); diff --git a/packages/twenty-front/src/modules/activities/hooks/__tests__/useModifyActivityTargetsOnActivityCache.test.tsx b/packages/twenty-front/src/modules/activities/hooks/__tests__/useModifyActivityTargetsOnActivityCache.test.tsx new file mode 100644 index 0000000000..cfc4bce55d --- /dev/null +++ b/packages/twenty-front/src/modules/activities/hooks/__tests__/useModifyActivityTargetsOnActivityCache.test.tsx @@ -0,0 +1,43 @@ +import { ReactNode } from 'react'; +import { MockedProvider } from '@apollo/client/testing'; +import { act, renderHook } from '@testing-library/react'; +import { RecoilRoot } from 'recoil'; + +import { useModifyActivityTargetsOnActivityCache } from '@/activities/hooks/useModifyActivityTargetsOnActivityCache'; +import { useModifyRecordFromCache } from '@/object-record/cache/hooks/useModifyRecordFromCache'; + +const useModifyRecordFromCacheMock = jest.fn(); + +jest.mock('@/object-record/cache/hooks/useModifyRecordFromCache', () => ({ + useModifyRecordFromCache: jest.fn(), +})); + +(useModifyRecordFromCache as jest.Mock).mockImplementation( + () => useModifyRecordFromCacheMock, +); + +const Wrapper = ({ children }: { children: ReactNode }) => ( + + {children} + +); + +describe('useModifyActivityTargetsOnActivityCache', () => { + it('works as expected', () => { + const { result } = renderHook( + () => useModifyActivityTargetsOnActivityCache(), + { + wrapper: Wrapper, + }, + ); + + act(() => { + result.current.modifyActivityTargetsOnActivityCache({ + activityId: '1234', + activityTargets: [], + }); + }); + + expect(useModifyRecordFromCacheMock).toHaveBeenCalled(); + }); +}); diff --git a/packages/twenty-front/src/modules/activities/hooks/__tests__/useOpenActivityRightDrawer.test.tsx b/packages/twenty-front/src/modules/activities/hooks/__tests__/useOpenActivityRightDrawer.test.tsx new file mode 100644 index 0000000000..2a323f3bde --- /dev/null +++ b/packages/twenty-front/src/modules/activities/hooks/__tests__/useOpenActivityRightDrawer.test.tsx @@ -0,0 +1,42 @@ +import { ReactNode } from 'react'; +import { MockedProvider } from '@apollo/client/testing'; +import { act, renderHook } from '@testing-library/react'; +import { RecoilRoot, useRecoilValue } from 'recoil'; + +import { useOpenActivityRightDrawer } from '@/activities/hooks/useOpenActivityRightDrawer'; +import { activityIdInDrawerState } from '@/activities/states/activityIdInDrawerState'; +import { viewableActivityIdState } from '@/activities/states/viewableActivityIdState'; + +const Wrapper = ({ children }: { children: ReactNode }) => ( + + {children} + +); + +describe('useOpenActivityRightDrawer', () => { + it('works as expected', () => { + const { result } = renderHook( + () => { + const openActivityRightDrawer = useOpenActivityRightDrawer(); + const viewableActivityId = useRecoilValue(viewableActivityIdState()); + const activityIdInDrawer = useRecoilValue(activityIdInDrawerState()); + return { + openActivityRightDrawer, + activityIdInDrawer, + viewableActivityId, + }; + }, + { + wrapper: Wrapper, + }, + ); + + expect(result.current.activityIdInDrawer).toBeNull(); + expect(result.current.viewableActivityId).toBeNull(); + act(() => { + result.current.openActivityRightDrawer('123'); + }); + expect(result.current.activityIdInDrawer).toBe('123'); + expect(result.current.viewableActivityId).toBe('123'); + }); +}); diff --git a/packages/twenty-front/src/modules/activities/hooks/__tests__/useOpenCreateActivityDrawer.test.tsx b/packages/twenty-front/src/modules/activities/hooks/__tests__/useOpenCreateActivityDrawer.test.tsx new file mode 100644 index 0000000000..ee294657c8 --- /dev/null +++ b/packages/twenty-front/src/modules/activities/hooks/__tests__/useOpenCreateActivityDrawer.test.tsx @@ -0,0 +1,63 @@ +import { ReactNode } from 'react'; +import { MockedProvider } from '@apollo/client/testing'; +import { act, renderHook } from '@testing-library/react'; +import { RecoilRoot, useRecoilValue, useSetRecoilState } from 'recoil'; + +import { useOpenCreateActivityDrawer } from '@/activities/hooks/useOpenCreateActivityDrawer'; +import { activityIdInDrawerState } from '@/activities/states/activityIdInDrawerState'; +import { viewableActivityIdState } from '@/activities/states/viewableActivityIdState'; +import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; +import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock'; + +const mockUUID = '37873e04-2f83-4468-9ab7-3f87da6cafad'; + +jest.mock('uuid', () => ({ + v4: () => mockUUID, +})); + +const Wrapper = ({ children }: { children: ReactNode }) => ( + + {children} + +); + +const mockObjectMetadataItems = getObjectMetadataItemsMock(); + +describe('useOpenCreateActivityDrawer', () => { + it('works as expected', async () => { + const { result } = renderHook( + () => { + const openActivityRightDrawer = useOpenCreateActivityDrawer(); + const viewableActivityId = useRecoilValue(viewableActivityIdState()); + const activityIdInDrawer = useRecoilValue(activityIdInDrawerState()); + const setObjectMetadataItems = useSetRecoilState( + objectMetadataItemsState(), + ); + return { + openActivityRightDrawer, + activityIdInDrawer, + viewableActivityId, + setObjectMetadataItems, + }; + }, + { + wrapper: Wrapper, + }, + ); + + act(() => { + result.current.setObjectMetadataItems(mockObjectMetadataItems); + }); + + expect(result.current.activityIdInDrawer).toBeNull(); + expect(result.current.viewableActivityId).toBeNull(); + await act(async () => { + result.current.openActivityRightDrawer({ + type: 'Note', + targetableObjects: [], + }); + }); + expect(result.current.activityIdInDrawer).toBe(mockUUID); + expect(result.current.viewableActivityId).toBe(mockUUID); + }); +}); diff --git a/packages/twenty-front/src/modules/activities/hooks/__tests__/useOpenCreateActivityDrawerForSelectedRowIds.test.tsx b/packages/twenty-front/src/modules/activities/hooks/__tests__/useOpenCreateActivityDrawerForSelectedRowIds.test.tsx new file mode 100644 index 0000000000..6a4ecc83de --- /dev/null +++ b/packages/twenty-front/src/modules/activities/hooks/__tests__/useOpenCreateActivityDrawerForSelectedRowIds.test.tsx @@ -0,0 +1,110 @@ +import { ReactNode } from 'react'; +import { MockedProvider } from '@apollo/client/testing'; +import { act, renderHook } from '@testing-library/react'; +import { RecoilRoot, useRecoilValue, useSetRecoilState } from 'recoil'; + +import { useOpenCreateActivityDrawer } from '@/activities/hooks/useOpenCreateActivityDrawer'; +import { useOpenCreateActivityDrawerForSelectedRowIds } from '@/activities/hooks/useOpenCreateActivityDrawerForSelectedRowIds'; +import { activityIdInDrawerState } from '@/activities/states/activityIdInDrawerState'; +import { viewableActivityIdState } from '@/activities/states/viewableActivityIdState'; +import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; +import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock'; +import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; +import { isRowSelectedComponentFamilyState } from '@/object-record/record-table/record-table-row/states/isRowSelectedComponentFamilyState'; +import { tableRowIdsComponentState } from '@/object-record/record-table/states/tableRowIdsComponentState'; + +const useOpenCreateActivityDrawerMock = jest.fn(); +jest.mock('@/activities/hooks/useOpenCreateActivityDrawer', () => ({ + useOpenCreateActivityDrawer: jest.fn(), +})); + +(useOpenCreateActivityDrawer as jest.Mock).mockImplementation( + () => useOpenCreateActivityDrawerMock, +); + +const Wrapper = ({ children }: { children: ReactNode }) => ( + + {children} + +); + +const mockObjectMetadataItems = getObjectMetadataItemsMock(); +const recordTableId = 'recordTableId'; +const tableRowIds = ['123', '456']; +const recordObject = { + id: '789', +}; + +describe('useOpenCreateActivityDrawerForSelectedRowIds', () => { + it('works as expected', async () => { + const { result } = renderHook( + () => { + const openCreateActivityDrawerForSelectedRowIds = + useOpenCreateActivityDrawerForSelectedRowIds(recordTableId); + const viewableActivityId = useRecoilValue(viewableActivityIdState()); + const activityIdInDrawer = useRecoilValue(activityIdInDrawerState()); + const setObjectMetadataItems = useSetRecoilState( + objectMetadataItemsState(), + ); + const scopeId = `${recordTableId}-scope`; + const setTableRowIds = useSetRecoilState( + tableRowIdsComponentState({ scopeId }), + ); + const setIsRowSelectedComponentFamilyState = useSetRecoilState( + isRowSelectedComponentFamilyState({ + scopeId, + familyKey: tableRowIds[0], + }), + ); + const setRecordStoreFamilyState = useSetRecoilState( + recordStoreFamilyState(tableRowIds[0]), + ); + return { + openCreateActivityDrawerForSelectedRowIds, + activityIdInDrawer, + viewableActivityId, + setObjectMetadataItems, + setTableRowIds, + setIsRowSelectedComponentFamilyState, + setRecordStoreFamilyState, + }; + }, + { + wrapper: Wrapper, + }, + ); + + act(() => { + result.current.setTableRowIds(tableRowIds); + result.current.setRecordStoreFamilyState(recordObject); + result.current.setIsRowSelectedComponentFamilyState(true); + result.current.setObjectMetadataItems(mockObjectMetadataItems); + }); + + expect(result.current.activityIdInDrawer).toBeNull(); + expect(result.current.viewableActivityId).toBeNull(); + await act(async () => { + result.current.openCreateActivityDrawerForSelectedRowIds( + 'Note', + 'person', + [{ id: '176', targetObjectNameSingular: 'person' }], + ); + }); + + expect(useOpenCreateActivityDrawerMock).toHaveBeenCalledWith({ + type: 'Note', + targetableObjects: [ + { + type: 'Custom', + targetObjectNameSingular: 'person', + id: '123', + targetObjectRecord: { id: '789' }, + }, + { + id: '176', + targetObjectNameSingular: 'person', + }, + ], + }); + }); +}); diff --git a/packages/twenty-front/src/modules/activities/hooks/__tests__/useRemoveFromActivitiesQueries.test.tsx b/packages/twenty-front/src/modules/activities/hooks/__tests__/useRemoveFromActivitiesQueries.test.tsx new file mode 100644 index 0000000000..6e2f5a5161 --- /dev/null +++ b/packages/twenty-front/src/modules/activities/hooks/__tests__/useRemoveFromActivitiesQueries.test.tsx @@ -0,0 +1,63 @@ +import { ReactNode } from 'react'; +import { MockedProvider } from '@apollo/client/testing'; +import { act, renderHook } from '@testing-library/react'; +import { RecoilRoot } from 'recoil'; + +import { useRemoveFromActivitiesQueries } from '@/activities/hooks/useRemoveFromActivitiesQueries'; +import { useReadFindManyRecordsQueryInCache } from '@/object-record/cache/hooks/useReadFindManyRecordsQueryInCache'; +import { useUpsertFindManyRecordsQueryInCache } from '@/object-record/cache/hooks/useUpsertFindManyRecordsQueryInCache'; + +const upsertFindManyRecordsQueryInCacheMock = jest.fn(); +const useReadFindManyRecordsQueryInCacheMock = jest.fn(() => [ + { activityId: '981' }, + { activityId: '345' }, +]); +jest.mock( + '@/object-record/cache/hooks/useReadFindManyRecordsQueryInCache', + () => ({ + useReadFindManyRecordsQueryInCache: jest.fn(), + }), +); +jest.mock( + '@/object-record/cache/hooks/useUpsertFindManyRecordsQueryInCache', + () => ({ + useUpsertFindManyRecordsQueryInCache: jest.fn(), + }), +); + +(useReadFindManyRecordsQueryInCache as jest.Mock).mockImplementation(() => ({ + readFindManyRecordsQueryInCache: useReadFindManyRecordsQueryInCacheMock, +})); + +(useUpsertFindManyRecordsQueryInCache as jest.Mock).mockImplementation(() => ({ + upsertFindManyRecordsQueryInCache: upsertFindManyRecordsQueryInCacheMock, +})); + +const Wrapper = ({ children }: { children: ReactNode }) => ( + + {children} + +); + +describe('useRemoveFromActivitiesQueries', () => { + it('works as expected', () => { + const { result } = renderHook(() => useRemoveFromActivitiesQueries(), { + wrapper: Wrapper, + }); + + act(() => { + result.current.removeFromActivitiesQueries({ + activityIdToRemove: '123', + targetableObjects: [], + }); + }); + + expect(upsertFindManyRecordsQueryInCacheMock).toHaveBeenCalledWith({ + objectRecordsToOverwrite: [{ activityId: '981' }, { activityId: '345' }], + queryVariables: { + filter: { id: { in: ['345', '981'] } }, + orderBy: undefined, + }, + }); + }); +}); diff --git a/packages/twenty-front/src/modules/activities/hooks/__tests__/useRemoveFromActivityTargetsQueries.test.tsx b/packages/twenty-front/src/modules/activities/hooks/__tests__/useRemoveFromActivityTargetsQueries.test.tsx new file mode 100644 index 0000000000..79e8ff6c8a --- /dev/null +++ b/packages/twenty-front/src/modules/activities/hooks/__tests__/useRemoveFromActivityTargetsQueries.test.tsx @@ -0,0 +1,72 @@ +import { ReactNode } from 'react'; +import { MockedProvider } from '@apollo/client/testing'; +import { act, renderHook } from '@testing-library/react'; +import { RecoilRoot } from 'recoil'; + +import { useRemoveFromActivityTargetsQueries } from '@/activities/hooks/useRemoveFromActivityTargetsQueries'; +import { useReadFindManyRecordsQueryInCache } from '@/object-record/cache/hooks/useReadFindManyRecordsQueryInCache'; +import { useUpsertFindManyRecordsQueryInCache } from '@/object-record/cache/hooks/useUpsertFindManyRecordsQueryInCache'; +import { mockedActivities } from '~/testing/mock-data/activities'; + +const upsertFindManyRecordsQueryInCacheMock = jest.fn(); +const useReadFindManyRecordsQueryInCacheMock = jest.fn(() => [ + { id: '981' }, + { id: '345' }, +]); +jest.mock( + '@/object-record/cache/hooks/useReadFindManyRecordsQueryInCache', + () => ({ + useReadFindManyRecordsQueryInCache: jest.fn(), + }), +); +jest.mock( + '@/object-record/cache/hooks/useUpsertFindManyRecordsQueryInCache', + () => ({ + useUpsertFindManyRecordsQueryInCache: jest.fn(), + }), +); + +(useReadFindManyRecordsQueryInCache as jest.Mock).mockImplementation(() => ({ + readFindManyRecordsQueryInCache: useReadFindManyRecordsQueryInCacheMock, +})); +(useUpsertFindManyRecordsQueryInCache as jest.Mock).mockImplementation(() => ({ + upsertFindManyRecordsQueryInCache: upsertFindManyRecordsQueryInCacheMock, +})); + +const Wrapper = ({ children }: { children: ReactNode }) => ( + + {children} + +); + +const mockActivityTarget = { + __typename: 'ActivityTarget', + updatedAt: '2021-08-03T19:20:06.000Z', + createdAt: '2021-08-03T19:20:06.000Z', + personId: '1', + activityId: '234', + companyId: '1', + id: '123', + activity: mockedActivities[0], +}; + +describe('useRemoveFromActivityTargetsQueries', () => { + it('works as expected', () => { + const { result } = renderHook(() => useRemoveFromActivityTargetsQueries(), { + wrapper: Wrapper, + }); + + act(() => { + result.current.removeFromActivityTargetsQueries({ + activityTargetsToRemove: [mockActivityTarget], + targetableObjects: [], + }); + }); + + expect(upsertFindManyRecordsQueryInCacheMock).toHaveBeenCalledWith({ + objectRecordsToOverwrite: [{ id: '981' }, { id: '345' }], + queryVariables: { filter: {} }, + depth: 2, + }); + }); +}); diff --git a/packages/twenty-front/src/modules/activities/hooks/__tests__/useUpsertActivity.test.tsx b/packages/twenty-front/src/modules/activities/hooks/__tests__/useUpsertActivity.test.tsx new file mode 100644 index 0000000000..fcfb2c94c2 --- /dev/null +++ b/packages/twenty-front/src/modules/activities/hooks/__tests__/useUpsertActivity.test.tsx @@ -0,0 +1,187 @@ +import { ReactNode } from 'react'; +import { MemoryRouter } from 'react-router-dom'; +import { MockedProvider, MockedResponse } from '@apollo/client/testing'; +import { act, renderHook } from '@testing-library/react'; +import gql from 'graphql-tag'; +import { RecoilRoot, useSetRecoilState } from 'recoil'; + +import { useCreateActivityInDB } from '@/activities/hooks/useCreateActivityInDB'; +import { useUpsertActivity } from '@/activities/hooks/useUpsertActivity'; +import { currentNotesQueryVariablesState } from '@/activities/notes/states/currentNotesQueryVariablesState'; +import { isActivityInCreateModeState } from '@/activities/states/isActivityInCreateModeState'; +import { currentCompletedTaskQueryVariablesState } from '@/activities/tasks/states/currentCompletedTaskQueryVariablesState'; +import { currentIncompleteTaskQueryVariablesState } from '@/activities/tasks/states/currentIncompleteTaskQueryVariablesState'; +import { objectShowPageTargetableObjectState } from '@/activities/timeline/states/objectShowPageTargetableObjectIdState'; +import { Activity } from '@/activities/types/Activity'; +import { mockedActivities } from '~/testing/mock-data/activities'; + +const newId = 'new-id'; +const activity = mockedActivities[0]; +const input: Partial = { id: newId }; + +const mockedDate = '2024-03-15T12:00:00.000Z'; +const toISOStringMock = jest.fn(() => mockedDate); +global.Date.prototype.toISOString = toISOStringMock; + +const useCreateActivityInDBMock = jest.fn(); + +jest.mock('@/activities/hooks/useCreateActivityInDB', () => ({ + useCreateActivityInDB: jest.fn(), +})); +(useCreateActivityInDB as jest.Mock).mockImplementation(() => ({ + createActivityInDB: useCreateActivityInDBMock, +})); + +const mocks: MockedResponse[] = [ + { + request: { + query: gql` + mutation UpdateOneActivity( + $idToUpdate: ID! + $input: ActivityUpdateInput! + ) { + updateActivity(id: $idToUpdate, data: $input) { + __typename + createdAt + reminderAt + authorId + title + completedAt + updatedAt + body + dueAt + type + id + assigneeId + } + } + `, + variables: { + idToUpdate: activity.id, + input: { id: 'new-id' }, + }, + }, + result: jest.fn(() => ({ + data: { + updateActivity: { ...activity, ...input }, + }, + })), + }, +]; + +const getWrapper = + (initialIndex: 0 | 1) => + ({ children }: { children: ReactNode }) => ( + + + + {children} + + + + ); + +describe('useUpsertActivity', () => { + it('updates an activity', async () => { + const { result } = renderHook(() => useUpsertActivity(), { + wrapper: getWrapper(0), + }); + + await act(async () => { + await result.current.upsertActivity({ + activity, + input, + }); + }); + + expect(mocks[0].result).toHaveBeenCalled(); + }); + + it('creates an activity on tasks page', async () => { + const { result } = renderHook( + () => { + const res = useUpsertActivity(); + const setIsActivityInCreateMode = useSetRecoilState( + isActivityInCreateModeState(), + ); + + return { ...res, setIsActivityInCreateMode }; + }, + { + wrapper: getWrapper(0), + }, + ); + + act(() => { + result.current.setIsActivityInCreateMode(true); + }); + + await act(async () => { + await result.current.upsertActivity({ + activity, + input: {}, + }); + }); + + expect(useCreateActivityInDBMock).toHaveBeenCalledTimes(1); + }); + + it('creates an activity on objects page', async () => { + const { result } = renderHook( + () => { + const res = useUpsertActivity(); + const setIsActivityInCreateMode = useSetRecoilState( + isActivityInCreateModeState(), + ); + const setObjectShowPageTargetableObject = useSetRecoilState( + objectShowPageTargetableObjectState, + ); + const setCurrentCompletedTaskQueryVariables = useSetRecoilState( + currentCompletedTaskQueryVariablesState, + ); + const setCurrentIncompleteTaskQueryVariables = useSetRecoilState( + currentIncompleteTaskQueryVariablesState, + ); + + const setCurrentNotesQueryVariables = useSetRecoilState( + currentNotesQueryVariablesState, + ); + + return { + ...res, + setIsActivityInCreateMode, + setObjectShowPageTargetableObject, + setCurrentCompletedTaskQueryVariables, + setCurrentIncompleteTaskQueryVariables, + setCurrentNotesQueryVariables, + }; + }, + { + wrapper: getWrapper(1), + }, + ); + + act(() => { + result.current.setIsActivityInCreateMode(true); + result.current.setObjectShowPageTargetableObject({ + id: '123', + targetObjectNameSingular: 'people', + }); + result.current.setCurrentCompletedTaskQueryVariables({}); + result.current.setCurrentIncompleteTaskQueryVariables({}); + result.current.setCurrentNotesQueryVariables({}); + }); + + await act(async () => { + await result.current.upsertActivity({ + activity, + input: {}, + }); + }); + + expect(useCreateActivityInDBMock).toHaveBeenCalledTimes(2); + }); +});