From 8967e37bc8ef1224ffa4d31239de4e6bf02d9803 Mon Sep 17 00:00:00 2001 From: Nikola Naumovski Date: Wed, 14 Oct 2026 10:13:30 +0200 Subject: [PATCH] fix(Attachment): render giphy attachments in their own group with unique keys Giphy attachments were pushed into the `card` group while keyed with the length of the always-empty `giphy` group, so every giphy got the key `giphy-0`. A message with more than one giphy triggered the React duplicate-key warning and could reconcile the wrong element. Push them into the `giphy` group that ATTACHMENT_GROUPS_ORDER already reserves, so keys are unique and giphys render in their intended position, before link-preview cards. --- src/components/Attachment/Attachment.tsx | 2 +- .../Attachment/__tests__/Attachment.test.tsx | 31 +++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/components/Attachment/Attachment.tsx b/src/components/Attachment/Attachment.tsx index 588802028a..902321629a 100644 --- a/src/components/Attachment/Attachment.tsx +++ b/src/components/Attachment/Attachment.tsx @@ -186,7 +186,7 @@ const renderGroupedAttachments = ({ />, ); } else if (attachment.type === 'giphy') { - typeMap.card.push( + typeMap.giphy.push( { expect(imageElement.style.getPropertyValue('--original-width')).toBe('200'); }); }); + + it('should render multiple giphy attachments without duplicate keys', async () => { + const consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => null); + const giphies = Array.from({ length: 3 }, generateGiphyAttachment); + + renderComponent({ attachments: giphies }); + + await waitFor(() => { + expect(screen.getAllByTestId('giphy-attachment')).toHaveLength(giphies.length); + }); + const duplicateKeyWarnings = consoleErrorSpy.mock.calls.filter(([message]) => + String(message).includes('Encountered two children with the same key'), + ); + expect(duplicateKeyWarnings).toHaveLength(0); + consoleErrorSpy.mockRestore(); + }); + + it('should render giphy attachments in the giphy group, before cards', async () => { + const { container } = renderComponent({ + attachments: [ATTACHMENTS.scraped.image, ATTACHMENTS.scraped.giphy], + }); + + await waitFor(() => { + const renderedTestIds = Array.from( + container.querySelectorAll( + '[data-testid="giphy-attachment"], [data-testid="card-attachment"]', + ), + ).map((element) => element.getAttribute('data-testid')); + expect(renderedTestIds).toEqual(['giphy-attachment', 'card-attachment']); + }); + }); }); describe('combines scraped & uploaded content', () => {