fix: Parsing emojis inside code blocks in attachment content using chat.postMessage API call (#35963)

Co-authored-by: Tasso Evangelista <2263066+tassoevan@users.noreply.github.com>
This commit is contained in:
Tiago Evangelista Pinto 2025-05-19 02:28:03 -03:00 committed by GitHub
parent 5a56b7b94e
commit 4896f43e33
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 191 additions and 96 deletions

View File

@ -0,0 +1,5 @@
---
"@rocket.chat/meteor": patch
---
Fixes emojis being parsed inside code blocks in text message attachment using `chat.postMessage` API call

View File

@ -23,6 +23,14 @@ export const emojiParser = (html: string) => {
const emojis = Array.from(checkEmojiOnly.querySelectorAll('.emoji:not(:empty), .emojione:not(:empty)'));
emojis.forEach((emojiElement) => {
const htmlElement = emojiElement.parentElement;
if (htmlElement && htmlElement.nodeName === 'CODE') {
emojiElement.replaceWith(emojiElement.getAttribute('title') ?? '');
}
});
let hasText = false;
if (!isIE11) {
@ -52,10 +60,11 @@ export const emojiParser = (html: string) => {
const { classList } = emojis[i];
classList.add('big');
}
html = checkEmojiOnly.innerHTML;
}
}
html = checkEmojiOnly.innerHTML;
// apostrophe (') back to &#39;
html = html.replace(/\'/g, '&#39;');

View File

@ -3,6 +3,8 @@ import type { ComponentPropsWithoutRef } from 'react';
type AttachmentTextProps = ComponentPropsWithoutRef<typeof Box>;
const AttachmentText = (props: AttachmentTextProps) => <Box mbe={4} mi={2} fontScale='p2' color='default' {...props} />;
const AttachmentText = (props: AttachmentTextProps) => (
<Box data-qa-type='message-attachment' mbe={4} mi={2} fontScale='p2' color='default' {...props} />
);
export default AttachmentText;

View File

@ -1,3 +1,4 @@
import { faker } from '@faker-js/faker';
import type { Page } from '@playwright/test';
import { createAuxContext } from './fixtures/createAuxContext';
@ -8,7 +9,7 @@ import { expect, test } from './utils/test';
test.use({ storageState: Users.user1.state });
test.describe.serial('Messaging', () => {
test.describe('Messaging', () => {
let poHomeChannel: HomeChannel;
let targetChannel: string;
@ -22,121 +23,195 @@ test.describe.serial('Messaging', () => {
await page.goto('/home');
});
test('should navigate on messages using keyboard', async ({ page }) => {
await poHomeChannel.sidenav.openChat(targetChannel);
await poHomeChannel.content.sendMessage('msg1');
await poHomeChannel.content.sendMessage('msg2');
test.describe.serial('Navigation', () => {
test('should navigate on messages using keyboard', async ({ page }) => {
await poHomeChannel.sidenav.openChat(targetChannel);
await poHomeChannel.content.sendMessage('msg1');
await poHomeChannel.content.sendMessage('msg2');
// move focus to the second message
await page.keyboard.press('Shift+Tab');
await expect(page.locator('[data-qa-type="message"]').last()).toBeFocused();
// move focus to the second message
await page.keyboard.press('Shift+Tab');
await expect(page.locator('[data-qa-type="message"]').last()).toBeFocused();
// move focus to the first system message
await page.keyboard.press('ArrowUp');
await page.keyboard.press('ArrowUp');
await expect(page.locator('[data-qa="system-message"]').first()).toBeFocused();
// move focus to the first system message
await page.keyboard.press('ArrowUp');
await page.keyboard.press('ArrowUp');
await expect(page.locator('[data-qa="system-message"]').first()).toBeFocused();
// move focus to the first typed message
await page.keyboard.press('ArrowDown');
await expect(page.locator('[data-qa-type="message"]:has-text("msg1")')).toBeFocused();
// move focus to the first typed message
await page.keyboard.press('ArrowDown');
await expect(page.locator('[data-qa-type="message"]:has-text("msg1")')).toBeFocused();
// move focus to the room title
await page.keyboard.press('Shift+Tab');
await expect(page.getByRole('button', { name: targetChannel }).first()).toBeFocused();
// move focus to the room title
await page.keyboard.press('Shift+Tab');
await expect(page.getByRole('button', { name: targetChannel }).first()).toBeFocused();
// refocus on the first typed message
await page.keyboard.press('Tab');
await page.keyboard.press('Tab');
await page.keyboard.press('Tab');
await expect(page.locator('[data-qa-type="message"]:has-text("msg1")')).toBeFocused();
// refocus on the first typed message
await page.keyboard.press('Tab');
await page.keyboard.press('Tab');
await page.keyboard.press('Tab');
await expect(page.locator('[data-qa-type="message"]:has-text("msg1")')).toBeFocused();
// move focus to the message toolbar
await page
.locator('[data-qa-type="message"]:has-text("msg1")')
.locator('[role=toolbar][aria-label="Message actions"]')
.getByRole('button', { name: 'Add reaction' })
.waitFor();
await page.keyboard.press('Tab');
await page.keyboard.press('Tab');
await expect(
page
// move focus to the message toolbar
await page
.locator('[data-qa-type="message"]:has-text("msg1")')
.locator('[role=toolbar][aria-label="Message actions"]')
.getByRole('button', { name: 'Add reaction' }),
).toBeFocused();
.getByRole('button', { name: 'Add reaction' })
.waitFor();
// move focus to the composer
await page.keyboard.press('Tab');
await page
.locator('[data-qa-type="message"]:has-text("msg2")')
.locator('[role=toolbar][aria-label="Message actions"]')
.getByRole('button', { name: 'Add reaction' })
.waitFor();
await page.keyboard.press('Tab');
await page.keyboard.press('Tab');
await expect(poHomeChannel.composer).toBeFocused();
await page.keyboard.press('Tab');
await page.keyboard.press('Tab');
await expect(
page
.locator('[data-qa-type="message"]:has-text("msg1")')
.locator('[role=toolbar][aria-label="Message actions"]')
.getByRole('button', { name: 'Add reaction' }),
).toBeFocused();
// move focus to the composer
await page.keyboard.press('Tab');
await page
.locator('[data-qa-type="message"]:has-text("msg2")')
.locator('[role=toolbar][aria-label="Message actions"]')
.getByRole('button', { name: 'Add reaction' })
.waitFor();
await page.keyboard.press('Tab');
await page.keyboard.press('Tab');
await expect(poHomeChannel.composer).toBeFocused();
});
test('should navigate properly on the user card', async ({ page }) => {
await poHomeChannel.sidenav.openChat(targetChannel);
// open UserCard
await page.keyboard.press('Shift+Tab');
await page.keyboard.press('ArrowUp');
await page.keyboard.press('Tab');
await page.keyboard.press('Space');
await expect(poHomeChannel.userCardToolbar).toBeVisible();
// close UserCard with Esc
await page.keyboard.press('Escape');
await expect(poHomeChannel.userCardToolbar).not.toBeVisible();
// with focus restored reopen toolbar
await page.keyboard.press('Space');
await expect(poHomeChannel.userCardToolbar).toBeVisible();
// close UserCard with button
await page.keyboard.press('Tab');
await page.keyboard.press('Tab');
await page.keyboard.press('Tab');
await page.keyboard.press('Space');
await expect(poHomeChannel.userCardToolbar).not.toBeVisible();
});
test('should not restore focus on the last focused if it was triggered by click', async ({ page }) => {
await poHomeChannel.sidenav.openChat(targetChannel);
await page.locator('[data-qa-type="message"]:has-text("msg1")').click();
await poHomeChannel.composer.click();
await page.keyboard.press('Shift+Tab');
await expect(page.locator('[data-qa-type="message"]:has-text("msg2")')).toBeFocused();
});
test('should not focus on the last message when focusing by click', async ({ page }) => {
await poHomeChannel.sidenav.openChat(targetChannel);
await page.locator('[data-qa-type="message"]:has-text("msg1")').click();
await expect(page.locator('[data-qa-type="message"]').last()).not.toBeFocused();
});
test('should focus the latest message when moving the focus on the list and theres no previous focus', async ({ page }) => {
await poHomeChannel.sidenav.openChat(targetChannel);
await page.getByRole('button', { name: targetChannel }).first().focus();
// move focus to the list
await page.keyboard.press('Tab');
await page.keyboard.press('Tab');
await page.keyboard.press('Tab');
await expect(page.locator('[data-qa-type="message"]').last()).toBeFocused();
await page.getByRole('button', { name: targetChannel }).first().focus();
// move focus to the list again
await page.keyboard.press('Tab');
await page.keyboard.press('Tab');
await page.keyboard.press('Tab');
await expect(page.locator('[data-qa-type="message"]').last()).toBeFocused();
});
});
test('should navigate properly on the user card', async ({ page }) => {
await poHomeChannel.sidenav.openChat(targetChannel);
test.describe('Message by "chat.postMessage" API method', () => {
test('expect show a message', async ({ api }) => {
const messageText = faker.lorem.sentence();
// open UserCard
await page.keyboard.press('Shift+Tab');
await page.keyboard.press('ArrowUp');
await page.keyboard.press('Tab');
await page.keyboard.press('Space');
await expect(poHomeChannel.userCardToolbar).toBeVisible();
await poHomeChannel.sidenav.openChat(targetChannel);
// close UserCard with Esc
await page.keyboard.press('Escape');
await expect(poHomeChannel.userCardToolbar).not.toBeVisible();
await api.post('/chat.postMessage', {
channel: targetChannel,
text: messageText,
});
// with focus restored reopen toolbar
await page.keyboard.press('Space');
await expect(poHomeChannel.userCardToolbar).toBeVisible();
await expect(poHomeChannel.content.lastUserMessageBody).toHaveText(messageText);
});
// close UserCard with button
await page.keyboard.press('Tab');
await page.keyboard.press('Tab');
await page.keyboard.press('Tab');
await page.keyboard.press('Space');
await expect(poHomeChannel.userCardToolbar).not.toBeVisible();
});
test('expect show attachment text', async ({ api }) => {
const messageText = faker.lorem.sentence();
const attachmentText = faker.lorem.sentence();
test('should not restore focus on the last focused if it was triggered by click', async ({ page }) => {
await poHomeChannel.sidenav.openChat(targetChannel);
await page.locator('[data-qa-type="message"]:has-text("msg1")').click();
await poHomeChannel.composer.click();
await page.keyboard.press('Shift+Tab');
await poHomeChannel.sidenav.openChat(targetChannel);
await expect(page.locator('[data-qa-type="message"]:has-text("msg2")')).toBeFocused();
});
await api.post('/chat.postMessage', {
channel: targetChannel,
text: messageText,
attachments: [
{
text: attachmentText,
},
],
});
test('should not focus on the last message when focusing by click', async ({ page }) => {
await poHomeChannel.sidenav.openChat(targetChannel);
await page.locator('[data-qa-type="message"]:has-text("msg1")').click();
await expect(poHomeChannel.content.lastUserMessageAttachment).toHaveText(attachmentText);
});
await expect(page.locator('[data-qa-type="message"]').last()).not.toBeFocused();
});
test('expect show attachment text with emoji', async ({ api }) => {
const messageText = faker.lorem.sentence();
const attachmentText = faker.lorem.sentence();
test('should focus the latest message when moving the focus on the list and theres no previous focus', async ({ page }) => {
await poHomeChannel.sidenav.openChat(targetChannel);
await page.getByRole('button', { name: targetChannel }).first().focus();
await poHomeChannel.sidenav.openChat(targetChannel);
// move focus to the list
await page.keyboard.press('Tab');
await page.keyboard.press('Tab');
await page.keyboard.press('Tab');
await expect(page.locator('[data-qa-type="message"]').last()).toBeFocused();
await api.post('/chat.postMessage', {
channel: targetChannel,
text: messageText,
attachments: [
{
text: `${attachmentText} B) `,
},
],
});
await page.getByRole('button', { name: targetChannel }).first().focus();
await expect(poHomeChannel.content.lastUserMessageAttachment).toHaveText(`${attachmentText} \ud83d\ude0e `);
});
// move focus to the list again
await page.keyboard.press('Tab');
await page.keyboard.press('Tab');
await page.keyboard.press('Tab');
await expect(page.locator('[data-qa-type="message"]').last()).toBeFocused();
test('expect show attachment text without emoji inside code block', async ({ api }) => {
const messageText = faker.lorem.sentence();
const attachmentText = faker.lorem.sentence();
await poHomeChannel.sidenav.openChat(targetChannel);
await api.post('/chat.postMessage', {
channel: targetChannel,
text: messageText,
attachments: [
{
text: `\`\`\`${attachmentText} B) \`\`\``,
},
],
});
await expect(poHomeChannel.content.lastUserMessageAttachment).toHaveText(`${attachmentText} B) `);
});
});
test.describe('Both contexts', () => {

View File

@ -47,6 +47,10 @@ export class HomeContent {
return this.lastUserMessage.locator('[data-qa-type="message-body"]');
}
get lastUserMessageAttachment(): Locator {
return this.page.locator('[data-qa-type="message-attachment"]').last();
}
get lastUserMessageNotSequential(): Locator {
return this.page.locator('[data-qa-type="message"][data-sequential="false"]').last();
}

View File

@ -8224,7 +8224,7 @@ __metadata:
storybook-dark-mode: "npm:^4.0.2"
typescript: "npm:~5.7.2"
peerDependencies:
"@rocket.chat/apps-engine": 1.51.0-rc.0
"@rocket.chat/apps-engine": 1.51.0
"@rocket.chat/eslint-config": 0.7.0
"@rocket.chat/fuselage": "*"
"@rocket.chat/fuselage-hooks": "*"