From 872fb2bd49623d558c3828809350227393913463 Mon Sep 17 00:00:00 2001 From: "gitstart-app[bot]" <57568882+gitstart-app[bot]@users.noreply.github.com> Date: Mon, 18 Mar 2024 17:10:07 +0100 Subject: [PATCH] TWNTY-4450 - Add tests for `/modules/activities/emails` (#4520) * Add tests for `/modules/activities/emails` Co-authored-by: v1b3m Co-authored-by: Thiago Nascimbeni * Fix tests Co-authored-by: v1b3m Co-authored-by: Thiago Nascimbeni * Remove temporary changes Co-authored-by: v1b3m Co-authored-by: Thiago Nascimbeni --------- Co-authored-by: gitstart-twenty Co-authored-by: v1b3m Co-authored-by: Thiago Nascimbeni --- .../__tests__/useCalendarEvents.test.tsx | 53 ++++++++++ .../useOpenCalendarEventRightDrawer.test.tsx | 35 ++++++ .../emails/components/EmailThreadPreview.tsx | 2 +- .../hooks/__tests__/useEmailThread.test.tsx | 69 ++++++++++++ .../hooks/internal/useEmailThreadStates.ts | 2 +- .../activities/emails/hooks/useEmailThread.ts | 2 +- .../getTimelineThreadsFromCompanyId.test.ts | 16 +++ .../getTimelineThreadsFromPersonId.test.ts | 16 +++ .../components/RightDrawerEmailThread.tsx | 2 +- .../useRightDrawerEmailThread.test.tsx | 40 +++++++ .../hooks/useRightDrawerEmailThread.ts | 2 +- .../emailThreadsPageComponentState.ts | 0 .../lastViewableEmailThreadIdState.ts | 0 .../viewableEmailThreadIdState.ts | 0 .../getDisplayNameFromParticipant.test.ts | 100 ++++++++++++++++++ 15 files changed, 334 insertions(+), 5 deletions(-) create mode 100644 packages/twenty-front/src/modules/activities/calendar/hooks/__tests__/useCalendarEvents.test.tsx create mode 100644 packages/twenty-front/src/modules/activities/calendar/right-drawer/hooks/__tests__/useOpenCalendarEventRightDrawer.test.tsx create mode 100644 packages/twenty-front/src/modules/activities/emails/hooks/__tests__/useEmailThread.test.tsx create mode 100644 packages/twenty-front/src/modules/activities/emails/queries/__tests__/getTimelineThreadsFromCompanyId.test.ts create mode 100644 packages/twenty-front/src/modules/activities/emails/queries/__tests__/getTimelineThreadsFromPersonId.test.ts create mode 100644 packages/twenty-front/src/modules/activities/emails/right-drawer/hooks/__tests__/useRightDrawerEmailThread.test.tsx rename packages/twenty-front/src/modules/activities/emails/{state => states}/emailThreadsPageComponentState.ts (100%) rename packages/twenty-front/src/modules/activities/emails/{state => states}/lastViewableEmailThreadIdState.ts (100%) rename packages/twenty-front/src/modules/activities/emails/{state => states}/viewableEmailThreadIdState.ts (100%) create mode 100644 packages/twenty-front/src/modules/activities/emails/utils/__tests__/getDisplayNameFromParticipant.test.ts diff --git a/packages/twenty-front/src/modules/activities/calendar/hooks/__tests__/useCalendarEvents.test.tsx b/packages/twenty-front/src/modules/activities/calendar/hooks/__tests__/useCalendarEvents.test.tsx new file mode 100644 index 000000000..498cc5ff7 --- /dev/null +++ b/packages/twenty-front/src/modules/activities/calendar/hooks/__tests__/useCalendarEvents.test.tsx @@ -0,0 +1,53 @@ +import { act, renderHook } from '@testing-library/react'; + +import { useCalendarEvents } from '@/activities/calendar/hooks/useCalendarEvents'; +import { CalendarEvent } from '@/activities/calendar/types/CalendarEvent'; + +const calendarEvents: CalendarEvent[] = [ + { + id: '1234', + externalCreatedAt: '2024-02-17T20:45:43.854Z', + isFullDay: false, + startsAt: '2024-02-17T21:45:27.822Z', + visibility: 'METADATA', + }, + { + id: '5678', + externalCreatedAt: '2024-02-18T19:43:37.854Z', + isFullDay: false, + startsAt: '2024-02-18T21:43:27.754Z', + visibility: 'SHARE_EVERYTHING', + }, + { + id: '91011', + externalCreatedAt: '2024-02-19T20:45:20.854Z', + isFullDay: true, + startsAt: '2024-02-19T22:05:27.653Z', + visibility: 'METADATA', + }, + { + id: '121314', + externalCreatedAt: '2024-02-20T20:45:12.854Z', + isFullDay: true, + startsAt: '2024-02-20T23:15:23.150Z', + visibility: 'SHARE_EVERYTHING', + }, +]; + +describe('useCalendar', () => { + it('returns calendar events', () => { + const { result } = renderHook(() => useCalendarEvents(calendarEvents)); + + expect(result.current.currentCalendarEvent).toBe(calendarEvents[0]); + + expect(result.current.getNextCalendarEvent(calendarEvents[1])).toBe( + calendarEvents[0], + ); + + act(() => { + result.current.updateCurrentCalendarEvent(); + }); + + expect(result.current.currentCalendarEvent).toBe(calendarEvents[0]); + }); +}); diff --git a/packages/twenty-front/src/modules/activities/calendar/right-drawer/hooks/__tests__/useOpenCalendarEventRightDrawer.test.tsx b/packages/twenty-front/src/modules/activities/calendar/right-drawer/hooks/__tests__/useOpenCalendarEventRightDrawer.test.tsx new file mode 100644 index 000000000..04544ed53 --- /dev/null +++ b/packages/twenty-front/src/modules/activities/calendar/right-drawer/hooks/__tests__/useOpenCalendarEventRightDrawer.test.tsx @@ -0,0 +1,35 @@ +import { act, renderHook } from '@testing-library/react'; +import { RecoilRoot, useRecoilValue } from 'recoil'; + +import { useOpenCalendarEventRightDrawer } from '@/activities/calendar/right-drawer/hooks/useOpenCalendarEventRightDrawer'; +import { viewableCalendarEventIdState } from '@/activities/calendar/states/viewableCalendarEventIdState'; +import { isRightDrawerOpenState } from '@/ui/layout/right-drawer/states/isRightDrawerOpenState'; + +describe('useOpenCalendarEventRightDrawer', () => { + it('opens the right drawer with the calendar event', () => { + const { result } = renderHook( + () => { + const isRightDrawerOpen = useRecoilValue(isRightDrawerOpenState()); + const viewableCalendarEventId = useRecoilValue( + viewableCalendarEventIdState(), + ); + return { + ...useOpenCalendarEventRightDrawer(), + isRightDrawerOpen, + viewableCalendarEventId, + }; + }, + { wrapper: RecoilRoot }, + ); + + expect(result.current.isRightDrawerOpen).toBe(false); + expect(result.current.viewableCalendarEventId).toBeNull(); + + act(() => { + result.current.openCalendarEventRightDrawer('1234'); + }); + + expect(result.current.isRightDrawerOpen).toBe(true); + expect(result.current.viewableCalendarEventId).toBe('1234'); + }); +}); diff --git a/packages/twenty-front/src/modules/activities/emails/components/EmailThreadPreview.tsx b/packages/twenty-front/src/modules/activities/emails/components/EmailThreadPreview.tsx index 98f5cf004..8c7b10aae 100644 --- a/packages/twenty-front/src/modules/activities/emails/components/EmailThreadPreview.tsx +++ b/packages/twenty-front/src/modules/activities/emails/components/EmailThreadPreview.tsx @@ -4,7 +4,7 @@ import { useRecoilCallback } from 'recoil'; import { EmailThreadNotShared } from '@/activities/emails/components/EmailThreadNotShared'; import { useEmailThread } from '@/activities/emails/hooks/useEmailThread'; -import { emailThreadIdWhenEmailThreadWasClosedState } from '@/activities/emails/state/lastViewableEmailThreadIdState'; +import { emailThreadIdWhenEmailThreadWasClosedState } from '@/activities/emails/states/lastViewableEmailThreadIdState'; import { CardContent } from '@/ui/layout/card/components/CardContent'; import { useRightDrawer } from '@/ui/layout/right-drawer/hooks/useRightDrawer'; import { GRAY_SCALE } from '@/ui/theme/constants/GrayScale'; diff --git a/packages/twenty-front/src/modules/activities/emails/hooks/__tests__/useEmailThread.test.tsx b/packages/twenty-front/src/modules/activities/emails/hooks/__tests__/useEmailThread.test.tsx new file mode 100644 index 000000000..c2a1fdf3a --- /dev/null +++ b/packages/twenty-front/src/modules/activities/emails/hooks/__tests__/useEmailThread.test.tsx @@ -0,0 +1,69 @@ +import { act, renderHook } from '@testing-library/react'; +import { RecoilRoot, useRecoilState, useRecoilValue } from 'recoil'; + +import { useEmailThread } from '@/activities/emails/hooks/useEmailThread'; +import { viewableEmailThreadIdState } from '@/activities/emails/states/viewableEmailThreadIdState'; +import { isRightDrawerOpenState } from '@/ui/layout/right-drawer/states/isRightDrawerOpenState'; + +const viewableEmailThreadId = '1234'; + +describe('useEmailThread', () => { + it('should open email thread', () => { + const { result } = renderHook( + () => { + const emailThread = useEmailThread(); + const isRightDrawerOpen = useRecoilValue(isRightDrawerOpenState()); + const viewableEmailThreadId = useRecoilValue( + viewableEmailThreadIdState(), + ); + + return { ...emailThread, isRightDrawerOpen, viewableEmailThreadId }; + }, + { wrapper: RecoilRoot }, + ); + + expect(result.current.isRightDrawerOpen).toBe(false); + expect(result.current.viewableEmailThreadId).toBeNull(); + + act(() => { + result.current.openEmailThread(viewableEmailThreadId); + }); + + expect(result.current.isRightDrawerOpen).toBe(true); + expect(result.current.viewableEmailThreadId).toBe(viewableEmailThreadId); + }); + + it('should close email thread', () => { + const { result } = renderHook( + () => { + const emailThread = useEmailThread(); + const [isRightDrawerOpen, setIsRightDrawerOpen] = useRecoilState( + isRightDrawerOpenState(), + ); + const [viewableEmailThreadId, setViewableEmailThreadId] = + useRecoilState(viewableEmailThreadIdState()); + + return { + ...emailThread, + isRightDrawerOpen, + viewableEmailThreadId, + setIsRightDrawerOpen, + setViewableEmailThreadId, + }; + }, + { wrapper: RecoilRoot }, + ); + + act(() => { + result.current.setIsRightDrawerOpen(true); + result.current.setViewableEmailThreadId(viewableEmailThreadId); + }); + + act(() => { + result.current.openEmailThread(viewableEmailThreadId); + }); + + expect(result.current.isRightDrawerOpen).toBe(false); + expect(result.current.viewableEmailThreadId).toBeNull(); + }); +}); diff --git a/packages/twenty-front/src/modules/activities/emails/hooks/internal/useEmailThreadStates.ts b/packages/twenty-front/src/modules/activities/emails/hooks/internal/useEmailThreadStates.ts index 946a43e0f..0162ee6d4 100644 --- a/packages/twenty-front/src/modules/activities/emails/hooks/internal/useEmailThreadStates.ts +++ b/packages/twenty-front/src/modules/activities/emails/hooks/internal/useEmailThreadStates.ts @@ -1,4 +1,4 @@ -import { emailThreadsPageComponentState } from '@/activities/emails/state/emailThreadsPageComponentState'; +import { emailThreadsPageComponentState } from '@/activities/emails/states/emailThreadsPageComponentState'; import { TabListScopeInternalContext } from '@/ui/layout/tab/scopes/scope-internal-context/TabListScopeInternalContext'; import { useAvailableScopeIdOrThrow } from '@/ui/utilities/recoil-scope/scopes-internal/hooks/useAvailableScopeId'; import { extractComponentState } from '@/ui/utilities/state/component-state/utils/extractComponentState'; diff --git a/packages/twenty-front/src/modules/activities/emails/hooks/useEmailThread.ts b/packages/twenty-front/src/modules/activities/emails/hooks/useEmailThread.ts index a5fca6861..5ca934b73 100644 --- a/packages/twenty-front/src/modules/activities/emails/hooks/useEmailThread.ts +++ b/packages/twenty-front/src/modules/activities/emails/hooks/useEmailThread.ts @@ -1,7 +1,7 @@ import { useRecoilCallback } from 'recoil'; import { useOpenEmailThreadRightDrawer } from '@/activities/emails/right-drawer/hooks/useOpenEmailThreadRightDrawer'; -import { viewableEmailThreadIdState } from '@/activities/emails/state/viewableEmailThreadIdState'; +import { viewableEmailThreadIdState } from '@/activities/emails/states/viewableEmailThreadIdState'; import { useRightDrawer } from '@/ui/layout/right-drawer/hooks/useRightDrawer'; import { isRightDrawerOpenState } from '@/ui/layout/right-drawer/states/isRightDrawerOpenState'; diff --git a/packages/twenty-front/src/modules/activities/emails/queries/__tests__/getTimelineThreadsFromCompanyId.test.ts b/packages/twenty-front/src/modules/activities/emails/queries/__tests__/getTimelineThreadsFromCompanyId.test.ts new file mode 100644 index 000000000..9b3c3ba70 --- /dev/null +++ b/packages/twenty-front/src/modules/activities/emails/queries/__tests__/getTimelineThreadsFromCompanyId.test.ts @@ -0,0 +1,16 @@ +import { gql } from '@apollo/client'; + +import { getTimelineThreadsFromCompanyId } from '../getTimelineThreadsFromCompanyId'; + +jest.mock('@apollo/client', () => ({ + gql: jest.fn().mockImplementation((strings) => { + return strings.map((str: string) => str.trim()).join(' '); + }), +})); + +describe('getTimelineThreadsFromCompanyId query', () => { + test('should construct the query correctly', () => { + expect(gql).toHaveBeenCalled(); + expect(getTimelineThreadsFromCompanyId).toBeDefined(); + }); +}); diff --git a/packages/twenty-front/src/modules/activities/emails/queries/__tests__/getTimelineThreadsFromPersonId.test.ts b/packages/twenty-front/src/modules/activities/emails/queries/__tests__/getTimelineThreadsFromPersonId.test.ts new file mode 100644 index 000000000..66862b728 --- /dev/null +++ b/packages/twenty-front/src/modules/activities/emails/queries/__tests__/getTimelineThreadsFromPersonId.test.ts @@ -0,0 +1,16 @@ +import { gql } from '@apollo/client'; + +import { getTimelineThreadsFromPersonId } from '../getTimelineThreadsFromPersonId'; + +jest.mock('@apollo/client', () => ({ + gql: jest.fn().mockImplementation((strings) => { + return strings.map((str: string) => str.trim()).join(' '); + }), +})); + +describe('getTimelineThreadsFromPersonId query', () => { + test('should construct the query correctly', () => { + expect(gql).toHaveBeenCalled(); + expect(getTimelineThreadsFromPersonId).toBeDefined(); + }); +}); diff --git a/packages/twenty-front/src/modules/activities/emails/right-drawer/components/RightDrawerEmailThread.tsx b/packages/twenty-front/src/modules/activities/emails/right-drawer/components/RightDrawerEmailThread.tsx index c901644f6..fc71fdfe3 100644 --- a/packages/twenty-front/src/modules/activities/emails/right-drawer/components/RightDrawerEmailThread.tsx +++ b/packages/twenty-front/src/modules/activities/emails/right-drawer/components/RightDrawerEmailThread.tsx @@ -6,7 +6,7 @@ import { EmailThreadFetchMoreLoader } from '@/activities/emails/components/Email import { EmailThreadHeader } from '@/activities/emails/components/EmailThreadHeader'; import { EmailThreadMessage } from '@/activities/emails/components/EmailThreadMessage'; import { useRightDrawerEmailThread } from '@/activities/emails/right-drawer/hooks/useRightDrawerEmailThread'; -import { emailThreadIdWhenEmailThreadWasClosedState } from '@/activities/emails/state/lastViewableEmailThreadIdState'; +import { emailThreadIdWhenEmailThreadWasClosedState } from '@/activities/emails/states/lastViewableEmailThreadIdState'; import { RIGHT_DRAWER_CLICK_OUTSIDE_LISTENER_ID } from '@/ui/layout/right-drawer/constants/RightDrawerClickOutsideListener'; import { useClickOutsideListener } from '@/ui/utilities/pointer-event/hooks/useClickOutsideListener'; diff --git a/packages/twenty-front/src/modules/activities/emails/right-drawer/hooks/__tests__/useRightDrawerEmailThread.test.tsx b/packages/twenty-front/src/modules/activities/emails/right-drawer/hooks/__tests__/useRightDrawerEmailThread.test.tsx new file mode 100644 index 000000000..63f1b09b0 --- /dev/null +++ b/packages/twenty-front/src/modules/activities/emails/right-drawer/hooks/__tests__/useRightDrawerEmailThread.test.tsx @@ -0,0 +1,40 @@ +import { MockedProvider } from '@apollo/client/testing'; +import { renderHook } from '@testing-library/react'; +import { RecoilRoot } from 'recoil'; + +import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords'; + +import { useRightDrawerEmailThread } from '../useRightDrawerEmailThread'; + +jest.mock('@/object-record/hooks/useFindManyRecords', () => ({ + __esModule: true, + useFindManyRecords: jest.fn(), +})); + +describe('useRightDrawerEmailThread', () => { + it('should return correct values', async () => { + const mockMessages = [ + { id: '1', text: 'Message 1' }, + { id: '2', text: 'Message 2' }, + ]; + const mockFetchMoreRecords = jest.fn(); + (useFindManyRecords as jest.Mock).mockReturnValue({ + records: mockMessages, + loading: false, + fetchMoreRecords: mockFetchMoreRecords, + }); + + const { result } = renderHook(() => useRightDrawerEmailThread(), { + wrapper: ({ children }) => ( + + {children} + + ), + }); + + expect(result.current.thread).toBeDefined(); + expect(result.current.messages).toEqual(mockMessages); + expect(result.current.loading).toBeFalsy(); + expect(result.current.fetchMoreMessages).toBeInstanceOf(Function); + }); +}); diff --git a/packages/twenty-front/src/modules/activities/emails/right-drawer/hooks/useRightDrawerEmailThread.ts b/packages/twenty-front/src/modules/activities/emails/right-drawer/hooks/useRightDrawerEmailThread.ts index 7415ba501..dac62986f 100644 --- a/packages/twenty-front/src/modules/activities/emails/right-drawer/hooks/useRightDrawerEmailThread.ts +++ b/packages/twenty-front/src/modules/activities/emails/right-drawer/hooks/useRightDrawerEmailThread.ts @@ -3,7 +3,7 @@ import { useApolloClient } from '@apollo/client'; import gql from 'graphql-tag'; import { useRecoilValue } from 'recoil'; -import { viewableEmailThreadIdState } from '@/activities/emails/state/viewableEmailThreadIdState'; +import { viewableEmailThreadIdState } from '@/activities/emails/states/viewableEmailThreadIdState'; import { EmailThreadMessage as EmailThreadMessageType } from '@/activities/emails/types/EmailThreadMessage'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords'; diff --git a/packages/twenty-front/src/modules/activities/emails/state/emailThreadsPageComponentState.ts b/packages/twenty-front/src/modules/activities/emails/states/emailThreadsPageComponentState.ts similarity index 100% rename from packages/twenty-front/src/modules/activities/emails/state/emailThreadsPageComponentState.ts rename to packages/twenty-front/src/modules/activities/emails/states/emailThreadsPageComponentState.ts diff --git a/packages/twenty-front/src/modules/activities/emails/state/lastViewableEmailThreadIdState.ts b/packages/twenty-front/src/modules/activities/emails/states/lastViewableEmailThreadIdState.ts similarity index 100% rename from packages/twenty-front/src/modules/activities/emails/state/lastViewableEmailThreadIdState.ts rename to packages/twenty-front/src/modules/activities/emails/states/lastViewableEmailThreadIdState.ts diff --git a/packages/twenty-front/src/modules/activities/emails/state/viewableEmailThreadIdState.ts b/packages/twenty-front/src/modules/activities/emails/states/viewableEmailThreadIdState.ts similarity index 100% rename from packages/twenty-front/src/modules/activities/emails/state/viewableEmailThreadIdState.ts rename to packages/twenty-front/src/modules/activities/emails/states/viewableEmailThreadIdState.ts diff --git a/packages/twenty-front/src/modules/activities/emails/utils/__tests__/getDisplayNameFromParticipant.test.ts b/packages/twenty-front/src/modules/activities/emails/utils/__tests__/getDisplayNameFromParticipant.test.ts new file mode 100644 index 000000000..e7647d869 --- /dev/null +++ b/packages/twenty-front/src/modules/activities/emails/utils/__tests__/getDisplayNameFromParticipant.test.ts @@ -0,0 +1,100 @@ +import { EmailThreadMessageParticipant } from '@/activities/emails/types/EmailThreadMessageParticipant'; + +import { getDisplayNameFromParticipant } from '../getDisplayNameFromParticipant'; + +describe('getDisplayNameFromParticipant', () => { + const participantWithName: EmailThreadMessageParticipant = { + displayName: '', + handle: '', + role: 'from', + person: { + id: '1', + createdAt: '', + updatedAt: '', + deletedAt: null, + name: { + firstName: 'John', + lastName: 'Doe', + }, + avatarUrl: '', + jobTitle: '', + linkedinLink: { + url: '', + label: '', + }, + xLink: { + url: '', + label: '', + }, + city: '', + email: '', + phone: '', + companyId: '', + }, + workspaceMember: { + id: '1', + name: { + firstName: 'Jane', + lastName: 'Smith', + }, + locale: '', + createdAt: '', + updatedAt: '', + userEmail: '', + userId: '', + }, + }; + + const participantWithHandle: any = { + displayName: '', + handle: 'user_handle', + role: 'from', + }; + + const participantWithDisplayName: any = { + displayName: 'User123', + handle: '', + role: 'from', + }; + + const participantWithoutInfo: any = { + displayName: '', + handle: '', + role: 'from', + }; + + it('should return full name when shouldUseFullName is true', () => { + expect( + getDisplayNameFromParticipant({ + participant: participantWithName, + shouldUseFullName: true, + }), + ).toBe('John Doe'); + }); + + it('should return first name when shouldUseFullName is false', () => { + expect( + getDisplayNameFromParticipant({ participant: participantWithName }), + ).toBe('John'); + }); + + it('should return displayName if it is a non-empty string', () => { + expect( + getDisplayNameFromParticipant({ + participant: participantWithDisplayName, + }), + ).toBe('User123'); + }); + + it('should return handle if displayName is not available', () => { + expect( + getDisplayNameFromParticipant({ participant: participantWithHandle }), + ).toBe('user_handle'); + }); + + it('should return Unknown if no suitable information is available', () => { + expect( + getDisplayNameFromParticipant({ participant: participantWithoutInfo }), + ).toBe('Unknown'); + }); +});