TWNTY-4450 - Add tests for /modules/activities/emails (#4520)
* Add tests for `/modules/activities/emails` Co-authored-by: v1b3m <vibenjamin6@gmail.com> Co-authored-by: Thiago Nascimbeni <tnascimbeni@gmail.com> * Fix tests Co-authored-by: v1b3m <vibenjamin6@gmail.com> Co-authored-by: Thiago Nascimbeni <tnascimbeni@gmail.com> * Remove temporary changes Co-authored-by: v1b3m <vibenjamin6@gmail.com> Co-authored-by: Thiago Nascimbeni <tnascimbeni@gmail.com> --------- Co-authored-by: gitstart-twenty <gitstart-twenty@users.noreply.github.com> Co-authored-by: v1b3m <vibenjamin6@gmail.com> Co-authored-by: Thiago Nascimbeni <tnascimbeni@gmail.com>
This commit is contained in:
committed by
GitHub
parent
bdbd77c696
commit
872fb2bd49
@ -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]);
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -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');
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -4,7 +4,7 @@ import { useRecoilCallback } from 'recoil';
|
|||||||
|
|
||||||
import { EmailThreadNotShared } from '@/activities/emails/components/EmailThreadNotShared';
|
import { EmailThreadNotShared } from '@/activities/emails/components/EmailThreadNotShared';
|
||||||
import { useEmailThread } from '@/activities/emails/hooks/useEmailThread';
|
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 { CardContent } from '@/ui/layout/card/components/CardContent';
|
||||||
import { useRightDrawer } from '@/ui/layout/right-drawer/hooks/useRightDrawer';
|
import { useRightDrawer } from '@/ui/layout/right-drawer/hooks/useRightDrawer';
|
||||||
import { GRAY_SCALE } from '@/ui/theme/constants/GrayScale';
|
import { GRAY_SCALE } from '@/ui/theme/constants/GrayScale';
|
||||||
|
|||||||
@ -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();
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -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 { TabListScopeInternalContext } from '@/ui/layout/tab/scopes/scope-internal-context/TabListScopeInternalContext';
|
||||||
import { useAvailableScopeIdOrThrow } from '@/ui/utilities/recoil-scope/scopes-internal/hooks/useAvailableScopeId';
|
import { useAvailableScopeIdOrThrow } from '@/ui/utilities/recoil-scope/scopes-internal/hooks/useAvailableScopeId';
|
||||||
import { extractComponentState } from '@/ui/utilities/state/component-state/utils/extractComponentState';
|
import { extractComponentState } from '@/ui/utilities/state/component-state/utils/extractComponentState';
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { useRecoilCallback } from 'recoil';
|
import { useRecoilCallback } from 'recoil';
|
||||||
|
|
||||||
import { useOpenEmailThreadRightDrawer } from '@/activities/emails/right-drawer/hooks/useOpenEmailThreadRightDrawer';
|
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 { useRightDrawer } from '@/ui/layout/right-drawer/hooks/useRightDrawer';
|
||||||
import { isRightDrawerOpenState } from '@/ui/layout/right-drawer/states/isRightDrawerOpenState';
|
import { isRightDrawerOpenState } from '@/ui/layout/right-drawer/states/isRightDrawerOpenState';
|
||||||
|
|
||||||
|
|||||||
@ -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();
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -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();
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -6,7 +6,7 @@ import { EmailThreadFetchMoreLoader } from '@/activities/emails/components/Email
|
|||||||
import { EmailThreadHeader } from '@/activities/emails/components/EmailThreadHeader';
|
import { EmailThreadHeader } from '@/activities/emails/components/EmailThreadHeader';
|
||||||
import { EmailThreadMessage } from '@/activities/emails/components/EmailThreadMessage';
|
import { EmailThreadMessage } from '@/activities/emails/components/EmailThreadMessage';
|
||||||
import { useRightDrawerEmailThread } from '@/activities/emails/right-drawer/hooks/useRightDrawerEmailThread';
|
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 { RIGHT_DRAWER_CLICK_OUTSIDE_LISTENER_ID } from '@/ui/layout/right-drawer/constants/RightDrawerClickOutsideListener';
|
||||||
import { useClickOutsideListener } from '@/ui/utilities/pointer-event/hooks/useClickOutsideListener';
|
import { useClickOutsideListener } from '@/ui/utilities/pointer-event/hooks/useClickOutsideListener';
|
||||||
|
|
||||||
|
|||||||
@ -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 }) => (
|
||||||
|
<MockedProvider mocks={[]} addTypename={false}>
|
||||||
|
<RecoilRoot>{children}</RecoilRoot>
|
||||||
|
</MockedProvider>
|
||||||
|
),
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(result.current.thread).toBeDefined();
|
||||||
|
expect(result.current.messages).toEqual(mockMessages);
|
||||||
|
expect(result.current.loading).toBeFalsy();
|
||||||
|
expect(result.current.fetchMoreMessages).toBeInstanceOf(Function);
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -3,7 +3,7 @@ import { useApolloClient } from '@apollo/client';
|
|||||||
import gql from 'graphql-tag';
|
import gql from 'graphql-tag';
|
||||||
import { useRecoilValue } from 'recoil';
|
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 { EmailThreadMessage as EmailThreadMessageType } from '@/activities/emails/types/EmailThreadMessage';
|
||||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||||
import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords';
|
import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords';
|
||||||
|
|||||||
@ -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');
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user