diff --git a/.changeset/gold-falcons-hear.md b/.changeset/gold-falcons-hear.md new file mode 100644 index 000000000000..0e47de679ae3 --- /dev/null +++ b/.changeset/gold-falcons-hear.md @@ -0,0 +1,5 @@ +--- +'@rocket.chat/meteor': patch +--- + +Fixes an issue where a thread message was not scrolled to view when it was opened using its link. diff --git a/apps/meteor/client/views/room/contextualBar/Threads/components/ThreadMessageList.tsx b/apps/meteor/client/views/room/contextualBar/Threads/components/ThreadMessageList.tsx index 085ce657a6af..125c08ad67cf 100644 --- a/apps/meteor/client/views/room/contextualBar/Threads/components/ThreadMessageList.tsx +++ b/apps/meteor/client/views/room/contextualBar/Threads/components/ThreadMessageList.tsx @@ -66,9 +66,9 @@ const ThreadMessageList = ({ mainMessage }: ThreadMessageListProps): ReactElemen const messageGroupingPeriod = Number(useSetting('Message_GroupingPeriod')); const { messageListRef } = useMessageListNavigation(); - const listRef = useMergedRefs(listScrollRef, listJumpRef, messageListRef); + const listRef = useMergedRefs(listScrollRef, messageListRef); - const scrollRef = useMergedRefs(innerRef, listWrapperScrollRef); + const scrollRef = useMergedRefs(innerRef, listWrapperScrollRef, listJumpRef); return (
diff --git a/apps/meteor/tests/e2e/jump-to-thread-message.spec.ts b/apps/meteor/tests/e2e/jump-to-thread-message.spec.ts new file mode 100644 index 000000000000..da67d0601344 --- /dev/null +++ b/apps/meteor/tests/e2e/jump-to-thread-message.spec.ts @@ -0,0 +1,65 @@ +import type { IMessage } from '@rocket.chat/core-typings'; +import { Random } from '@rocket.chat/random'; + +import { Users } from './fixtures/userStates'; +import type { BaseTest } from './utils/test'; +import { expect, test } from './utils/test'; + +test.use({ storageState: Users.admin.state }); +test.describe.serial('Threads', () => { + let targetChannel: { name: string; _id: string }; + let threadMessage: IMessage; + let mainMessage: IMessage; + + const fillMessages = async (api: BaseTest['api']) => { + const { message: parentMessage } = await ( + await api.post('/chat.postMessage', { roomId: targetChannel._id, text: 'this is a message for reply' }) + ).json(); + mainMessage = parentMessage; + + // fill thread with messages + const largeSimpleMessage = 'This is a large message with a lot of text to create scroll view in thread'.repeat(5); + const { message: childMessage } = await ( + await api.post('/chat.postMessage', { roomId: targetChannel._id, text: largeSimpleMessage, tmid: parentMessage._id }) + ).json(); + threadMessage = childMessage; + + await Promise.all( + Array.from({ length: 5 }).map(() => + api.post('/chat.postMessage', { roomId: targetChannel._id, text: largeSimpleMessage, tmid: parentMessage._id }), + ), + ); + + // fill room with normal messages + await Promise.all( + Array.from({ length: 5 }).map(() => api.post('/chat.postMessage', { roomId: targetChannel._id, text: largeSimpleMessage })), + ); + }; + + test.beforeAll(async ({ api }) => { + targetChannel = (await (await api.post('/channels.create', { name: Random.id() })).json()).channel; + await fillMessages(api); + }); + + test.afterAll(({ api }) => api.post('/channels.delete', { roomId: targetChannel._id })); + + test('expect to jump scroll to a non-thread message on opening its message link', async ({ page }) => { + const messageLink = `/channel/${targetChannel.name}?msg=${mainMessage._id}`; + await page.goto(messageLink); + + const message = await page.locator(`[aria-label=\"Message list\"] [data-id=\"${mainMessage._id}\"]`); + + await expect(message).toBeVisible(); + await expect(message).toBeInViewport(); + }); + + test('expect to jump scroll to thread message on opening its message link', async ({ page }) => { + const threadMessageLink = `/channel/general?msg=${threadMessage._id}`; + await page.goto(threadMessageLink); + + const message = await page.locator(`[aria-label=\"Thread message list\"] [data-id=\"${threadMessage._id}\"]`); + + await expect(message).toBeVisible(); + await expect(message).toBeInViewport(); + }); +});