diff --git a/.changeset/moody-phones-admire.md b/.changeset/moody-phones-admire.md new file mode 100644 index 000000000000..bd5e2daa1514 --- /dev/null +++ b/.changeset/moody-phones-admire.md @@ -0,0 +1,5 @@ +--- +"@rocket.chat/meteor": patch +--- + +Fixes title missing in thread list for threads starting with attachment in E2EE rooms diff --git a/apps/meteor/client/hooks/useDecryptedMessage.spec.ts b/apps/meteor/client/hooks/useDecryptedMessage.spec.ts new file mode 100644 index 000000000000..62e77a77b096 --- /dev/null +++ b/apps/meteor/client/hooks/useDecryptedMessage.spec.ts @@ -0,0 +1,86 @@ +import { isE2EEMessage } from '@rocket.chat/core-typings'; +import { renderHook, waitFor } from '@testing-library/react'; + +import { e2e } from '../../app/e2e/client/rocketchat.e2e'; +import { useDecryptedMessage } from './useDecryptedMessage'; + +// Mock the dependencies +jest.mock('@rocket.chat/core-typings', () => ({ + isE2EEMessage: jest.fn(), +})); + +jest.mock('../../app/e2e/client/rocketchat.e2e', () => ({ + e2e: { + decryptMessage: jest.fn(), + }, +})); + +jest.mock('react-i18next', () => ({ + useTranslation: () => ({ + t: (key: string) => key, + }), +})); + +describe('useDecryptedMessage', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('should return the original message for non-E2EE messages', () => { + (isE2EEMessage as jest.MockedFunction).mockReturnValue(false); + const message = { msg: 'Hello, world!' }; + + const { result } = renderHook(() => useDecryptedMessage(message as any), { legacyRoot: true }); + + expect(result.current).toBe('Hello, world!'); + expect(e2e.decryptMessage).not.toHaveBeenCalled(); + }); + + it('should return decrypted message for E2EE messages', async () => { + (isE2EEMessage as jest.MockedFunction).mockReturnValue(true); + (e2e.decryptMessage as jest.Mock).mockResolvedValue({ msg: 'Decrypted message' }); + const message = { msg: 'Encrypted message' }; + const { result } = renderHook(() => useDecryptedMessage(message as any), { legacyRoot: true }); + + await waitFor(() => { + expect(result.current).not.toBe('E2E_message_encrypted_placeholder'); + }); + + expect(result.current).toBe('Decrypted message'); + expect(e2e.decryptMessage).toHaveBeenCalledWith(message); + }); + + it('should handle E2EE messages with attachments', async () => { + (isE2EEMessage as jest.MockedFunction).mockReturnValue(true); + (e2e.decryptMessage as jest.Mock).mockResolvedValue({ + attachments: [{ description: 'Attachment description' }], + }); + const message = { msg: 'Encrypted message with attachment' }; + + const { result } = renderHook(() => useDecryptedMessage(message as any), { legacyRoot: true }); + + await waitFor(() => { + expect(result.current).toBe('E2E_message_encrypted_placeholder'); + }); + + expect(result.current).toBe('Attachment description'); + expect(e2e.decryptMessage).toHaveBeenCalledWith(message); + }); + + it('should handle E2EE messages with attachments but no description', async () => { + (isE2EEMessage as jest.MockedFunction).mockReturnValue(true); + (e2e.decryptMessage as jest.Mock).mockResolvedValue({ + attachments: [{}], + }); + const message = { msg: 'Encrypted message with attachment' }; + + const { result } = renderHook(() => useDecryptedMessage(message as any), { legacyRoot: true }); + + await waitFor(() => { + expect(result.current).toBe('E2E_message_encrypted_placeholder'); + }); + + expect(result.current).toBe('Message_with_attachment'); + expect(e2e.decryptMessage).toHaveBeenCalledWith(message); + }); +}); diff --git a/apps/meteor/client/hooks/useDecryptedMessage.ts b/apps/meteor/client/hooks/useDecryptedMessage.ts index aa36ba1d34fd..f98012b11f2b 100644 --- a/apps/meteor/client/hooks/useDecryptedMessage.ts +++ b/apps/meteor/client/hooks/useDecryptedMessage.ts @@ -19,6 +19,14 @@ export const useDecryptedMessage = (message: IMessage): string => { if (decryptedMsg.msg) { setDecryptedMessage(decryptedMsg.msg); } + + if (decryptedMsg.attachments && decryptedMsg.attachments?.length > 0) { + if (decryptedMsg.attachments[0].description) { + setDecryptedMessage(decryptedMsg.attachments[0].description); + } else { + setDecryptedMessage(t('Message_with_attachment')); + } + } }); }, [message, t, setDecryptedMessage]);