From ca70cca4652f39cd40cd4b3effd9a6c04c300ff2 Mon Sep 17 00:00:00 2001 From: Irene Ryu Date: Tue, 3 Dec 2024 15:14:55 +0900 Subject: [PATCH] Resolve conflict after rebase from main --- .../GroupChannelProvider.spec.tsx | 0 .../useGroupChannel.spec.tsx | 0 .../__tests__/useMessageActions.spec.ts | 154 -------------- .../useMessageActions.spec.tsx | 188 ++++++++++++++++++ .../context/hooks/useMessageActions.ts | 4 +- 5 files changed, 190 insertions(+), 156 deletions(-) rename src/modules/GroupChannel/context/{__test__ => __tests__}/GroupChannelProvider.spec.tsx (100%) rename src/modules/GroupChannel/context/{__test__ => __tests__}/useGroupChannel.spec.tsx (100%) delete mode 100644 src/modules/GroupChannel/context/__tests__/useMessageActions.spec.ts rename src/modules/GroupChannel/context/{__test__ => __tests__}/useMessageActions.spec.tsx (50%) diff --git a/src/modules/GroupChannel/context/__test__/GroupChannelProvider.spec.tsx b/src/modules/GroupChannel/context/__tests__/GroupChannelProvider.spec.tsx similarity index 100% rename from src/modules/GroupChannel/context/__test__/GroupChannelProvider.spec.tsx rename to src/modules/GroupChannel/context/__tests__/GroupChannelProvider.spec.tsx diff --git a/src/modules/GroupChannel/context/__test__/useGroupChannel.spec.tsx b/src/modules/GroupChannel/context/__tests__/useGroupChannel.spec.tsx similarity index 100% rename from src/modules/GroupChannel/context/__test__/useGroupChannel.spec.tsx rename to src/modules/GroupChannel/context/__tests__/useGroupChannel.spec.tsx diff --git a/src/modules/GroupChannel/context/__tests__/useMessageActions.spec.ts b/src/modules/GroupChannel/context/__tests__/useMessageActions.spec.ts deleted file mode 100644 index b20163832..000000000 --- a/src/modules/GroupChannel/context/__tests__/useMessageActions.spec.ts +++ /dev/null @@ -1,154 +0,0 @@ -import { renderHook } from '@testing-library/react-hooks'; -import { useMessageActions } from '../hooks/useMessageActions'; -import { UserMessageCreateParams, FileMessageCreateParams } from '@sendbird/chat/message'; - -const mockEventHandlers = { - message: { - onSendMessageFailed: jest.fn(), - onUpdateMessageFailed: jest.fn(), - onFileUploadFailed: jest.fn(), - }, -}; - -jest.mock('../../../../hooks/useSendbirdStateContext', () => ({ - __esModule: true, - default: () => ({ - eventHandlers: mockEventHandlers, - }), -})); - -describe('useMessageActions', () => { - const mockParams = { - sendUserMessage: jest.fn(), - sendFileMessage: jest.fn(), - sendMultipleFilesMessage: jest.fn(), - updateUserMessage: jest.fn(), - scrollToBottom: jest.fn(), - replyType: 'NONE', - }; - - beforeEach(() => { - jest.clearAllMocks(); - }); - - describe('processParams', () => { - it('should handle successful user message', async () => { - const { result } = renderHook(() => useMessageActions(mockParams)); - const params: UserMessageCreateParams = { message: 'test' }; - - await result.current.sendUserMessage(params); - - expect(mockParams.sendUserMessage).toHaveBeenCalledWith( - expect.objectContaining({ message: 'test' }), - expect.any(Function), - ); - }); - - it('should handle void return from onBeforeSendFileMessage', async () => { - const onBeforeSendFileMessage = jest.fn(); - const { result } = renderHook(() => useMessageActions({ - ...mockParams, - onBeforeSendFileMessage, - }), - ); - - const fileParams: FileMessageCreateParams = { - file: new File([], 'test.txt'), - }; - - await result.current.sendFileMessage(fileParams); - - expect(onBeforeSendFileMessage).toHaveBeenCalled(); - expect(mockParams.sendFileMessage).toHaveBeenCalledWith( - expect.objectContaining(fileParams), - expect.any(Function), - ); - }); - - it('should handle file upload error', async () => { - // Arrange - const error = new Error('Upload failed'); - const onBeforeSendFileMessage = jest.fn().mockRejectedValue(error); - const fileParams: FileMessageCreateParams = { - file: new File([], 'test.txt'), - fileName: 'test.txt', - }; - - const { result } = renderHook(() => useMessageActions({ - ...mockParams, - onBeforeSendFileMessage, - }), - ); - - await expect(async () => { - await result.current.sendFileMessage(fileParams); - }).rejects.toThrow('Upload failed'); - - // Wait for next tick to ensure all promises are resolved - await new Promise(process.nextTick); - - expect(onBeforeSendFileMessage).toHaveBeenCalled(); - expect(mockEventHandlers.message.onFileUploadFailed).toHaveBeenCalledWith(error); - expect(mockEventHandlers.message.onSendMessageFailed).toHaveBeenCalledWith( - expect.objectContaining({ - file: fileParams.file, - fileName: fileParams.fileName, - }), - error, - ); - }); - - it('should handle message update error', async () => { - // Arrange - const error = new Error('Update failed'); - const onBeforeUpdateUserMessage = jest.fn().mockRejectedValue(error); - const messageParams = { - messageId: 1, - message: 'update message', - }; - - const { result } = renderHook(() => useMessageActions({ - ...mockParams, - onBeforeUpdateUserMessage, - }), - ); - - await expect(async () => { - await result.current.updateUserMessage(messageParams.messageId, { - message: messageParams.message, - }); - }).rejects.toThrow('Update failed'); - - // Wait for next tick to ensure all promises are resolved - await new Promise(process.nextTick); - - expect(onBeforeUpdateUserMessage).toHaveBeenCalled(); - expect(mockEventHandlers.message.onUpdateMessageFailed).toHaveBeenCalledWith( - expect.objectContaining({ - message: messageParams.message, - }), - error, - ); - }); - - it('should preserve modified params from onBefore handlers', async () => { - const onBeforeSendUserMessage = jest.fn().mockImplementation((params) => ({ - ...params, - message: 'modified', - })); - - const { result } = renderHook(() => useMessageActions({ - ...mockParams, - onBeforeSendUserMessage, - }), - ); - - await result.current.sendUserMessage({ message: 'original' }); - - expect(mockParams.sendUserMessage).toHaveBeenCalledWith( - expect.objectContaining({ message: 'modified' }), - expect.any(Function), - ); - }); - }); -}); diff --git a/src/modules/GroupChannel/context/__test__/useMessageActions.spec.tsx b/src/modules/GroupChannel/context/__tests__/useMessageActions.spec.tsx similarity index 50% rename from src/modules/GroupChannel/context/__test__/useMessageActions.spec.tsx rename to src/modules/GroupChannel/context/__tests__/useMessageActions.spec.tsx index 821fc009e..9f3b1ffd6 100644 --- a/src/modules/GroupChannel/context/__test__/useMessageActions.spec.tsx +++ b/src/modules/GroupChannel/context/__tests__/useMessageActions.spec.tsx @@ -1,6 +1,65 @@ import { renderHook } from '@testing-library/react-hooks'; +import { UserMessageCreateParams, FileMessageCreateParams } from '@sendbird/chat/message'; + import { useMessageActions } from '../hooks/useMessageActions'; +const mockEventHandlers = { + message: { + onSendMessageFailed: jest.fn(), + onUpdateMessageFailed: jest.fn(), + onFileUploadFailed: jest.fn(), + }, +}; +const mockChannel = { + url: 'test-channel', + members: [{ userId: '1', nickname: 'user1' }], +}; +const mockGetChannel = jest.fn().mockResolvedValue(mockChannel); +const mockMessageCollection = { + dispose: jest.fn(), + setMessageCollectionHandler: jest.fn(), + initialize: jest.fn().mockResolvedValue(null), + loadPrevious: jest.fn(), + loadNext: jest.fn(), +}; +jest.mock('../../../../lib/Sendbird/context/hooks/useSendbird', () => ({ + __esModule: true, + default: jest.fn(() => ({ + state: { + eventHandlers: mockEventHandlers, + stores: { + sdkStore: { + sdk: { + groupChannel: { + getChannel: mockGetChannel, + addGroupChannelHandler: jest.fn(), + removeGroupChannelHandler: jest.fn(), + }, + createMessageCollection: jest.fn().mockReturnValue(mockMessageCollection), + }, + initialized: true, + }, + }, + config: { + markAsReadScheduler: { + push: jest.fn(), + }, + groupChannel: { + replyType: 'NONE', + threadReplySelectType: 'PARENT', + }, + groupChannelSettings: { + enableMessageSearch: true, + }, + isOnline: true, + pubSub: { + subscribe: () => ({ remove: jest.fn() }), + }, + }, + }, + })), +})); + describe('useMessageActions', () => { // Setup common mocks const mockSendUserMessage = jest.fn(); @@ -183,4 +242,133 @@ describe('useMessageActions', () => { ); }); }); + + describe('processParams', () => { + const mockParams = { + sendUserMessage: jest.fn(), + sendFileMessage: jest.fn(), + sendMultipleFilesMessage: jest.fn(), + updateUserMessage: jest.fn(), + scrollToBottom: jest.fn(), + replyType: 'NONE', + }; + it('should handle successful user message', async () => { + const { result } = renderHook(() => useMessageActions(mockParams)); + const params: UserMessageCreateParams = { message: 'test' }; + + await result.current.sendUserMessage(params); + + expect(mockParams.sendUserMessage).toHaveBeenCalledWith( + expect.objectContaining({ message: 'test' }), + expect.any(Function), + ); + }); + + it('should handle void return from onBeforeSendFileMessage', async () => { + const onBeforeSendFileMessage = jest.fn(); + const { result } = renderHook(() => useMessageActions({ + ...mockParams, + onBeforeSendFileMessage, + }), + ); + + const fileParams: FileMessageCreateParams = { + file: new File([], 'test.txt'), + }; + + await result.current.sendFileMessage(fileParams); + + expect(onBeforeSendFileMessage).toHaveBeenCalled(); + expect(mockParams.sendFileMessage).toHaveBeenCalledWith( + expect.objectContaining(fileParams), + expect.any(Function), + ); + }); + + it('should handle file upload error', async () => { + // Arrange + const error = new Error('Upload failed'); + const onBeforeSendFileMessage = jest.fn().mockRejectedValue(error); + const fileParams: FileMessageCreateParams = { + file: new File([], 'test.txt'), + fileName: 'test.txt', + }; + + const { result } = renderHook(() => useMessageActions({ + ...mockParams, + onBeforeSendFileMessage, + }), + ); + + await expect(async () => { + await result.current.sendFileMessage(fileParams); + }).rejects.toThrow('Upload failed'); + + // Wait for next tick to ensure all promises are resolved + await new Promise(process.nextTick); + + expect(onBeforeSendFileMessage).toHaveBeenCalled(); + expect(mockEventHandlers.message.onFileUploadFailed).toHaveBeenCalledWith(error); + expect(mockEventHandlers.message.onSendMessageFailed).toHaveBeenCalledWith( + expect.objectContaining({ + file: fileParams.file, + fileName: fileParams.fileName, + }), + error, + ); + }); + + it('should handle message update error', async () => { + // Arrange + const error = new Error('Update failed'); + const onBeforeUpdateUserMessage = jest.fn().mockRejectedValue(error); + const messageParams = { + messageId: 1, + message: 'update message', + }; + + const { result } = renderHook(() => useMessageActions({ + ...mockParams, + onBeforeUpdateUserMessage, + }), + ); + + await expect(async () => { + await result.current.updateUserMessage(messageParams.messageId, { + message: messageParams.message, + }); + }).rejects.toThrow('Update failed'); + + // Wait for next tick to ensure all promises are resolved + await new Promise(process.nextTick); + + expect(onBeforeUpdateUserMessage).toHaveBeenCalled(); + expect(mockEventHandlers.message.onUpdateMessageFailed).toHaveBeenCalledWith( + expect.objectContaining({ + message: messageParams.message, + }), + error, + ); + }); + + it('should preserve modified params from onBefore handlers', async () => { + const onBeforeSendUserMessage = jest.fn().mockImplementation((params) => ({ + ...params, + message: 'modified', + })); + + const { result } = renderHook(() => useMessageActions({ + ...mockParams, + onBeforeSendUserMessage, + }), + ); + + await result.current.sendUserMessage({ message: 'original' }); + + expect(mockParams.sendUserMessage).toHaveBeenCalledWith( + expect.objectContaining({ message: 'modified' }), + expect.any(Function), + ); + }); + }); }); diff --git a/src/modules/GroupChannel/context/hooks/useMessageActions.ts b/src/modules/GroupChannel/context/hooks/useMessageActions.ts index 3c023b7a9..c936fdd0d 100644 --- a/src/modules/GroupChannel/context/hooks/useMessageActions.ts +++ b/src/modules/GroupChannel/context/hooks/useMessageActions.ts @@ -21,7 +21,7 @@ import { VOICE_MESSAGE_MIME_TYPE, } from '../../../../utils/consts'; import type { CoreMessageType } from '../../../../utils'; -import useSendbirdStateContext from '../../../../hooks/useSendbirdStateContext'; +import useSendbird from '../../../../lib/Sendbird/context/hooks/useSendbird'; import type { GroupChannelState, OnBeforeHandler } from '../types'; type MessageListDataSource = ReturnType; @@ -70,7 +70,7 @@ export function useMessageActions(params: Params): MessageActions { quoteMessage, replyType, } = params; - const { eventHandlers } = useSendbirdStateContext(); + const { state: { eventHandlers } } = useSendbird(); const buildInternalMessageParams = useCallback( (basicParams: T): T => { const messageParams = { ...basicParams } as T;