Skip to content

chore: remove emojione in favor of native emojis#39411

Open
sampaiodiego wants to merge 29 commits into
developfrom
remove-joypixel
Open

chore: remove emojione in favor of native emojis#39411
sampaiodiego wants to merge 29 commits into
developfrom
remove-joypixel

Conversation

@sampaiodiego

@sampaiodiego sampaiodiego commented Mar 6, 2026

Copy link
Copy Markdown
Member

Replace Emojione with Native Unicode Emojis

Summary

This PR removes the dependency on Emojione and transitions Rocket.Chat to use native Unicode emojis across the platform. All emojis will now be stored and processed as standard Unicode characters directly in the database.

Why this change

Emojione introduced an additional abstraction layer (shortcodes + image mapping) that increases complexity, impacts performance, and limits interoperability with modern protocols.

By adopting native Unicode emojis, we align Rocket.Chat with current standards used across messaging platforms and protocols.

Performance Improvements

  • Reduced payload size: Unicode emojis are significantly smaller than image-based representations or shortcode mappings.
  • Faster rendering: Native emojis are rendered directly by the client/OS, eliminating image lookups and replacements.
  • Lower processing overhead: No need for parsing, conversion, or maintaining emoji dictionaries.
  • Database efficiency: Storing raw Unicode reduces storage complexity and improves query performance.

Improved Compatibility (Matrix & Open Protocols)

  • Matrix-native support: Matrix uses Unicode emojis by default. This change ensures seamless compatibility with Matrix federation.
  • No translation layer needed: Eliminates the need to convert between Emojione shortcodes and Matrix events.
  • Better interoperability: Messages retain their original emoji representation across federated systems and external clients.
  • Standards alignment: Moves Rocket.Chat closer to protocol-native communication without proprietary transformations.

Developer & Maintenance Benefits

  • Simplifies the codebase by removing emoji parsing/mapping logic
  • Reduces dependency on third-party emoji libraries
  • Easier to maintain and extend
  • Fewer edge cases when handling emoji rendering across platforms

Migration Notes

  • Existing messages using Emojione shortcodes will NOT be converted to their corresponding Unicode equivalents.
  • Emojis will now be different in each OS.
  • Custom emojis remain unaffected.

Result

A simpler, faster, and more interoperable emoji system that:

  • Improves performance across clients and backend
  • Reduces technical debt
  • Enables cleaner Matrix federation
  • Aligns Rocket.Chat with modern messaging standards

CORE-1980

Summary by CodeRabbit

  • New Features
    • Added native emoji rendering backed by emoji data (including improved ZWJ/compound sequence handling).
    • Emoji picker/composer now insert the Unicode character when available (fallback to shortcode).
    • PDF transcript emoji rendering is generated locally.
  • Bug Fixes
    • Improved emoji shortcode-to-Unicode conversion across message previews, notifications, reactions, and federation flows; updated reaction emoji DOM selectors.
  • Documentation
    • Updated “Powered by” branding to Rocket.Chat and removed JoyPixels credit wording.
  • Tests
    • Updated e2e/unit expectations and locators for the new emoji behavior and UI changes (including removal of the EmojiPicker footer).

@dionisio-bot

dionisio-bot Bot commented Mar 6, 2026

Copy link
Copy Markdown
Contributor

Looks like this PR is not ready to merge, because of the following issues:

  • This PR is missing the 'stat: QA assured' label

Please fix the issues and try again

If you have any trouble, please check the PR guidelines

@changeset-bot

changeset-bot Bot commented Mar 6, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 5b2264f

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@coderabbitai

coderabbitai Bot commented Mar 6, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

This PR replaces emojione-based emoji data and conversion paths with native/emojibase-backed code across Meteor and EE packages. It also updates rendering, picker behavior, parser support, tests, and cleanup files to use the new emoji classes and shortname mapping.

Changes

Native emoji migration

Layer / File(s) Summary
Native emoji contracts
apps/meteor/app/emoji-native/lib/*, apps/meteor/app/emoji/lib/rocketchat.ts
New emoji dataset builders, lookup helpers, and shared emoji list types are defined from emojibase data and legacy shortcode mappings.
Meteor bootstrap and package wiring
apps/meteor/client/views/root/*, apps/meteor/client/importPackages.ts, apps/meteor/server/importPackages.ts, apps/meteor/app/emoji-native/server/*, apps/meteor/app/emoji/client/lib.ts, apps/meteor/app/lib/server/lib/sendNotificationsOnMessage.ts, apps/meteor/package.json, ee/packages/*/package.json
Meteor startup, package imports, and server callbacks switch to the native emoji package and its local conversion helpers.
Message emoji conversion
apps/meteor/client/lib/utils/normalizeMessagePreview/*, apps/meteor/client/views/room/composer/messageBox/MessageBox.tsx, apps/meteor/client/views/room/providers/ComposerPopupProvider.tsx, apps/meteor/client/views/room/contextualBar/ExportMessages/useExportMessagesAsPDFMutation.tsx, packages/message-parser/src/grammar.pegjs, packages/message-parser/tests/emoji.test.ts
Preview, composer, popup, export, and parser paths convert shortnames through local helpers and native emoji data.
Emoji rendering and picker UI
apps/meteor/app/theme/client/imports/components/emoji.css, apps/meteor/client/components/Emoji.tsx, apps/meteor/client/lib/{customEmoji.ts,detectEmoji.ts,renderEmoji.ts}, apps/meteor/app/emoji/client/emojiParser.ts, apps/meteor/client/views/composer/EmojiPicker/*, packages/ui-avatar/src/components/MessageAvatar.tsx, packages/ui-client/src/components/EmojiPicker/EmojiPickerPreview.tsx
Emoji styling, parser checks, picker items, and avatar and preview components use the new custom-emoji classes and simplified markup.
Downstream consumers
ee/packages/federation-matrix/*, ee/packages/pdf-worker/*
Federation matrix and PDF worker code switch to emojibase-based emoji conversion and local rendering helpers.
Validation and cleanup
apps/meteor/tests/e2e/page-objects/home-channel.ts, apps/meteor/tests/e2e/federation/tests/messaging/{dm,private,public}.spec.ts, apps/meteor/tests/e2e/{message-composer,messaging}.spec.ts, apps/meteor/tests/unit/app/reactions/server/setReaction.spec.ts, apps/meteor/client/lib/utils/normalizeMessagePreview/normalizeMessagePreview.spec.ts, README.md, apps/meteor/.stylelintignore, apps/meteor/app/emoji-emojione/..., apps/meteor/definition/externals/emojione.d.ts, eslint.config.mjs, packages/i18n/src/locales/*
Tests, locale strings, docs, ignore rules, and removed emojione files update the visible checks and leftover migration files.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Suggested labels

type: feature

Suggested reviewers

  • KevLehman
  • tassoevan
  • MartinSchoeler
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: replacing Emojione with native Unicode emojis.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Warning

Review ran into problems

🔥 Problems

Errors were encountered while retrieving linked issues.

Errors (1)
  • CORE-1980: Request failed with status code 401

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@codecov

codecov Bot commented Mar 6, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 99.11950% with 14 lines in your changes missing coverage. Please review.
✅ Project coverage is 70.51%. Comparing base (64af832) to head (5b2264f).
⚠️ Report is 13 commits behind head on develop.

Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff             @@
##           develop   #39411      +/-   ##
===========================================
+ Coverage    70.09%   70.51%   +0.42%     
===========================================
  Files         3363     3370       +7     
  Lines       129716   131506    +1790     
  Branches     22444    22552     +108     
===========================================
+ Hits         90925    92736    +1811     
+ Misses       35479    35461      -18     
+ Partials      3312     3309       -3     
Flag Coverage Δ
unit 70.58% <99.11%> (+0.58%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@ggazzo

ggazzo commented Mar 6, 2026

Copy link
Copy Markdown
Member

@copilot when inserting an emoji using the picker or autocomplete, use the UTF-8 encoding unless it's a custom emoji,
When you're typing and finish the emoji name, also replace it with UTF-8.

Copilot AI commented Mar 6, 2026

Copy link
Copy Markdown
Contributor

@ggazzo I've opened a new pull request, #39432, to work on those changes. Once the pull request is ready, I'll request review from you.

@MartinSchoeler MartinSchoeler left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whenever the user adds an emoji using the emoji picker, the result should be an unicode character being added to the message composer, only show the shortcode as fallback for custom emojis or emojis that don't have an unicode counterpart

Steps to reproduce:

Open emoji picker
Select an emoji

Expected behavior:

An unicode emoji character should be added. (Example 🙈)

Actual behavior:

A shortname is added. (Example 🙈)

@ggazzo

ggazzo commented Mar 9, 2026

Copy link
Copy Markdown
Member

Whenever the user adds an emoji using the emoji picker, the result should be an unicode character being added to the message composer, only show the shortcode as fallback for custom emojis or emojis that don't have an unicode counterpart

Steps to reproduce:

Open emoji picker Select an emoji

Expected behavior:

An unicode emoji character should be added. (Example 🙈)

Actual behavior:

A shortname is added. (Example 🙈)

@copilot

Copilot AI commented Mar 9, 2026

Copy link
Copy Markdown
Contributor

@ggazzo I've opened a new pull request, #39474, to work on those changes. Once the pull request is ready, I'll request review from you.

@MartinSchoeler MartinSchoeler marked this pull request as ready for review June 25, 2026 20:23
@MartinSchoeler MartinSchoeler requested review from a team as code owners June 25, 2026 20:23
@coderabbitai coderabbitai Bot added the type: feature Pull requests that introduces new feature label Jun 25, 2026

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

8 issues found across 97 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/meteor/client/views/room/providers/ComposerPopupProvider.tsx">

<violation number="1" location="apps/meteor/client/views/room/providers/ComposerPopupProvider.tsx:255">
P2: Alias emoji selections can still insert shortcode text instead of Unicode. This leaves a mixed storage path after the migration and breaks the native-emoji-only behavior for alias hits.</violation>
</file>

<file name="ee/packages/federation-matrix/src/events/reaction.ts">

<violation number="1" location="ee/packages/federation-matrix/src/events/reaction.ts:42">
P2: `reactionKey` from federated events is used without validation before conversion. Missing/non-string keys can propagate invalid reaction identifiers into reaction add/remove updates.</violation>
</file>

<file name="apps/meteor/client/views/composer/EmojiPicker/EmojiCategoryRow.tsx">

<violation number="1" location="apps/meteor/client/views/composer/EmojiPicker/EmojiCategoryRow.tsx:53">
P3: Uses hardcoded `'rocket'` instead of shared `CUSTOM_CATEGORY` constant. If category key changes, custom emoji styling condition silently stops matching.</violation>
</file>

<file name="apps/meteor/app/emoji-native/lib/generateEmojiData.ts">

<violation number="1" location="apps/meteor/app/emoji-native/lib/generateEmojiData.ts:100">
P1: Multi-skin-tone variants are keyed with only the first tone, causing key collisions and wrong emoji mappings. Mixed-tone entries should not be flattened to a single `_toneN` key.</violation>
</file>

<file name="ee/packages/federation-matrix/src/FederationMatrix.ts">

<violation number="1" location="ee/packages/federation-matrix/src/FederationMatrix.ts:522">
P2: Skin-tone reaction shortcodes are not converted to Unicode before Matrix calls. This breaks federated add/remove reactions for those emojis by sending literal `:...:` keys.</violation>
</file>

Note: This PR contains a large number of files. cubic only reviews up to 40 files per PR, so some files may not have been reviewed. cubic prioritizes the most important files to review.
On a pro plan you can use ultrareview for larger PRs.

Re-trigger cubic

Comment thread ee/packages/federation-matrix/package.json
for (const skin of emojiData.skins) {
if (!skin.tone) continue;

const toneNum = Array.isArray(skin.tone) ? skin.tone[0] : skin.tone;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Multi-skin-tone variants are keyed with only the first tone, causing key collisions and wrong emoji mappings. Mixed-tone entries should not be flattened to a single _toneN key.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/meteor/app/emoji-native/lib/generateEmojiData.ts, line 100:

<comment>Multi-skin-tone variants are keyed with only the first tone, causing key collisions and wrong emoji mappings. Mixed-tone entries should not be flattened to a single `_toneN` key.</comment>

<file context>
@@ -0,0 +1,129 @@
+			for (const skin of emojiData.skins) {
+				if (!skin.tone) continue;
+
+				const toneNum = Array.isArray(skin.tone) ? skin.tone[0] : skin.tone;
+				const toneKey = `:${primaryShortcode}_tone${toneNum}:`;
+				const skinHex = hexFromEmoji(skin.emoji);
</file context>

Comment thread apps/meteor/app/emoji-native/lib/shortnameToUnicode.ts Outdated
Comment thread ee/packages/pdf-worker/src/templates/ChatTranscript/markup/emoji.ts
getValue: (item) => `${item._id.substring(1)}`,
getValue: (item) => {
const emojiEntry = emoji.list[item._id];
return emojiEntry && 'unicode' in emojiEntry ? (emojiEntry.unicode ?? item._id) : item._id;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Alias emoji selections can still insert shortcode text instead of Unicode. This leaves a mixed storage path after the migration and breaks the native-emoji-only behavior for alias hits.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/meteor/client/views/room/providers/ComposerPopupProvider.tsx, line 255:

<comment>Alias emoji selections can still insert shortcode text instead of Unicode. This leaves a mixed storage path after the migration and breaks the native-emoji-only behavior for alias hits.</comment>

<file context>
@@ -249,7 +250,10 @@ const ComposerPopupProvider = ({ children, room }: ComposerPopupProviderProps) =
-					getValue: (item) => `${item._id.substring(1)}`,
+					getValue: (item) => {
+						const emojiEntry = emoji.list[item._id];
+						return emojiEntry && 'unicode' in emojiEntry ? (emojiEntry.unicode ?? item._id) : item._id;
+					},
 					renderItem: ({ item }) => <ComposerBoxPopupEmoji {...item} />,
</file context>

}

const reactionKey = emojione.shortnameToUnicode(reaction);
const reactionKey = shortnameToUnicode(reaction);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Skin-tone reaction shortcodes are not converted to Unicode before Matrix calls. This breaks federated add/remove reactions for those emojis by sending literal :...: keys.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At ee/packages/federation-matrix/src/FederationMatrix.ts, line 522:

<comment>Skin-tone reaction shortcodes are not converted to Unicode before Matrix calls. This breaks federated add/remove reactions for those emojis by sending literal `:...:` keys.</comment>

<file context>
@@ -519,7 +519,7 @@ export class FederationMatrix extends ServiceClass implements IFederationMatrixS
 			}
 
-			const reactionKey = emojione.shortnameToUnicode(reaction);
+			const reactionKey = shortnameToUnicode(reaction);
 
 			const userMui = isUserNativeFederated(user) ? user.federation.mui : `@${user.username}:${this.serverName}`;
</file context>

@@ -2,7 +2,8 @@ import { Message, FederationMatrix } from '@rocket.chat/core-services';
import { federationSDK } from '@rocket.chat/federation-sdk';

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: reactionKey from federated events is used without validation before conversion. Missing/non-string keys can propagate invalid reaction identifiers into reaction add/remove updates.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At ee/packages/federation-matrix/src/events/reaction.ts, line 42:

<comment>`reactionKey` from federated events is used without validation before conversion. Missing/non-string keys can propagate invalid reaction identifiers into reaction add/remove updates.</comment>

<file context>
@@ -38,7 +39,7 @@ export function reaction() {
 			}
 
-			const reactionEmoji = emojione.toShort(reactionKey);
+			const reactionEmoji = unicodeToShortname(reactionKey);
 			await Message.reactToMessage(user._id, reactionEmoji, rcMessage._id, true);
 			await Messages.setFederationReactionEventId(internalUsername, rcMessage._id, reactionEmoji, eventId);
</file context>

key={emoji + category}
emoji={emoji}
image={image}
className={category === 'rocket' ? 'emojipicker--custom' : ''}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: Uses hardcoded 'rocket' instead of shared CUSTOM_CATEGORY constant. If category key changes, custom emoji styling condition silently stops matching.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/meteor/client/views/composer/EmojiPicker/EmojiCategoryRow.tsx, line 53:

<comment>Uses hardcoded `'rocket'` instead of shared `CUSTOM_CATEGORY` constant. If category key changes, custom emoji styling condition silently stops matching.</comment>

<file context>
@@ -46,7 +46,13 @@ const EmojiCategoryRow = ({ item, handleLoadMore, handleSelectEmoji }: EmojiCate
+					key={emoji + category}
+					emoji={emoji}
+					image={image}
+					className={category === 'rocket' ? 'emojipicker--custom' : ''}
+					onClick={handleSelectEmoji}
+				/>
</file context>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
ee/packages/federation-matrix/package.json (1)

44-44: 📐 Maintainability & Code Quality | 🟡 Minor

Restore lodash.debounce in ee/packages/federation-matrix/package.json
ee/packages/federation-matrix/src/events/member.ts still imports it, so this package is missing a direct runtime dependency.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ee/packages/federation-matrix/package.json` at line 44, The federation-matrix
package is missing a direct runtime dependency for a module still imported by
member.ts. Update the package.json dependencies for
ee/packages/federation-matrix to restore lodash.debounce alongside the existing
type package, so the import used in the member-related event code resolves at
runtime.
🧹 Nitpick comments (7)
apps/meteor/app/emoji-native/lib/getEmojiConfig.ts (1)

17-17: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Drop the inline implementation comments here.

The control flow is already compact enough to express intent without commentary. As per coding guidelines, **/*.{ts,tsx,js}: Avoid code comments in the implementation.

Also applies to: 39-42, 54-54, 62-62, 71-71

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/meteor/app/emoji-native/lib/getEmojiConfig.ts` at line 17, Remove the
inline implementation comments from getEmojiConfig and related blocks in the
same diff, since the logic in the reverse mapping and control flow should stand
on its own. Keep the code behavior unchanged and delete the comments near the
mapping construction and other marked spots so getEmojiConfig remains
comment-free in the implementation.

Source: Coding guidelines

apps/meteor/app/emoji-native/lib/generateEmojiData.ts (1)

5-5: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Remove implementation comments from this module.

These comments are carrying behavior that should live in names or helper boundaries instead. As per coding guidelines, **/*.{ts,tsx,js}: Avoid code comments in the implementation.

Also applies to: 55-55, 82-82, 87-87, 92-92, 96-96, 121-121

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/meteor/app/emoji-native/lib/generateEmojiData.ts` at line 5, Remove the
implementation comments from generateEmojiData.ts, including the mapping and
step-explanation comments around the emoji grouping logic. Keep the behavior in
the existing names/helpers such as the group/category mapping and related
functions, and delete the comment lines at the referenced spots so the module
contains no code comments.

Source: Coding guidelines

apps/meteor/app/emoji-native/server/lib.ts (1)

27-30: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Remove the implementation comments in this initializer.

This setup code is short enough to keep the intent in the statements themselves. As per coding guidelines, **/*.{ts,tsx,js}: Avoid code comments in the implementation.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/meteor/app/emoji-native/server/lib.ts` around lines 27 - 30, The
initializer in legacy shortcode registration contains implementation comments
that should be removed. Update the loop in the emoji-native server lib so the
intent is conveyed by the statements themselves, and delete the comment above
the legacy emojione shortcode registration and the inline note on the emoji.list
key check.

Source: Coding guidelines

apps/meteor/client/views/root/hooks/useNativeEmoji.ts (2)

13-52: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Prefer useEffect over useLayoutEffect for the emoji registration.

This effect synchronously iterates the full config.emojiList plus ~1400 legacyEmojioneMap entries and populates emoji.list. useLayoutEffect runs synchronously before the browser paints, so this bulk work blocks the first paint during startup. Since nothing here reads layout or needs to run before paint, useEffect would avoid the jank while keeping the same one-time behavior.

♻️ Suggested change
-	useLayoutEffect(() => {
+	useEffect(() => {
 		emoji.packages.native = {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/meteor/client/views/root/hooks/useNativeEmoji.ts` around lines 13 - 52,
The one-time emoji registration in useNativeEmoji is doing heavy synchronous
work before paint, so switch this effect from useLayoutEffect to useEffect. Keep
the same initialization logic for emoji.packages.native, emoji.list, and
emoji.dispatchUpdate, but run it after render since no layout measurement or
pre-paint behavior is needed.

15-15: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Avoid the as any cast on emojiCategories.

Casting to any here disables type checking on the shape passed into emoji.packages.native. Align the config.emojiCategories type with the expected emojiCategories type so mismatches are caught at compile time.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/meteor/client/views/root/hooks/useNativeEmoji.ts` at line 15, The
`useNativeEmoji` hook is bypassing type safety by casting
`config.emojiCategories` to `any` before passing it into
`emoji.packages.native`. Update the `config.emojiCategories` type or the
receiving `emoji.packages.native` contract so they match directly, and remove
the cast while keeping the call site in `useNativeEmoji` and the
`emojiCategories` property strongly typed.
apps/meteor/tests/e2e/federation/tests/messaging/private.spec.ts (1)

579-585: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Keep the reaction selector behind the page object boundary.

This change updates the class name correctly, but the spec still duplicates the same DOM selector across every reaction assertion. Please move it to a FederationChannel helper/locator so the emoji-rendering contract stays centralized. As per coding guidelines, apps/meteor/tests/e2e/**/*.{ts,spec.ts}: Store commonly used locators in variables/constants for reuse and apps/meteor/tests/e2e/**/*.{ts,spec.ts}: Follow Page Object Model pattern consistently in Playwright tests.

Also applies to: 606-612, 645-651, 668-682, 715-721, 738-751

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/meteor/tests/e2e/federation/tests/messaging/private.spec.ts` around
lines 579 - 585, The reaction emoji selector is duplicated in the spec instead
of being centralized behind the page object boundary. Move the
`span.rcx-message-reactions__emoji.emoji` locator into a `FederationChannel`
helper/locator and reuse it in the reaction assertions so the emoji-rendering
contract lives in one place. Update the related reaction checks in the
`private.spec.ts` flows to reference that helper consistently and keep the Page
Object Model boundary intact.

Source: Coding guidelines

apps/meteor/tests/e2e/federation/tests/messaging/dm.spec.ts (1)

668-674: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Move the reaction emoji locator into the page object.

These assertions hardcode the same CSS selector repeatedly in the spec, so the next class-name change will require another multi-hunk edit. Please expose a reusable reaction-emoji locator/helper on FederationChannel (and prefer a semantic locator there if the rendered emoji has an accessible name). As per coding guidelines, apps/meteor/tests/e2e/**/*.{ts,spec.ts}: Store commonly used locators in variables/constants for reuse and apps/meteor/tests/e2e/**/*.{ts,spec.ts}: Follow Page Object Model pattern consistently in Playwright tests.

Also applies to: 713-719, 768-774, 791-801, 854-860, 877-887

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/meteor/tests/e2e/federation/tests/messaging/dm.spec.ts` around lines 668
- 674, The reaction emoji selector is hardcoded across the dm spec, making
future class-name changes brittle. Add a reusable reaction-emoji locator/helper
on FederationChannel, preferably using a semantic locator if the emoji has an
accessible name, and update the spec assertions to call that page-object method
instead of repeating the CSS selector. Keep the locator centralized in the page
object and reuse it consistently in all affected reaction assertion blocks.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/meteor/app/emoji-native/lib/generateEmojiData.ts`:
- Around line 97-101: The mixed-tone skin key generation in generateEmojiData.ts
collapses array-based skin.tone values by using only the first element, so
distinct mixed-tone variants can overwrite each other. Update the tone key
construction in the loop over emojiData.skins to either encode the full tone
tuple from skin.tone into the key or explicitly skip mixed-tone entries, and
keep the single-tone path intact for the existing primaryShortcode-based keys.

In `@apps/meteor/app/lib/server/lib/sendNotificationsOnMessage.ts`:
- Around line 195-201: Avoid mutating the shared attachments array in
sendNotificationsOnMessage when handling the first attachment. In
sendNotification(), replace the use of message.attachments.shift() with a
non-mutating read/copy so the same message object can be reused across
subscriptions without losing attachments; use the first-attachment handling
around firstAttachment and keep message.attachments unchanged for later
receivers.

In `@apps/meteor/client/views/composer/EmojiPicker/ToneSelector/ToneItem.tsx`:
- Around line 6-26: The ToneItem component is rendering toneEmoji through
dangerouslySetInnerHTML, which keeps the unsafe HTML injection warning active.
Update ToneItem to return JSX directly by mapping the tone value to the correct
emoji character and rendering it inside a span with className="emoji" rather
than building an HTML string, so the Box content no longer relies on raw HTML.

In
`@apps/meteor/client/views/room/contextualBar/ExportMessages/useExportMessagesAsPDFMutation.tsx`:
- Around line 36-54: `renderEmojiToDataURL` currently assumes every split code
point is valid, but `parseInt` can produce `NaN` and `String.fromCodePoint` will
throw on malformed input. Add a small validation step before building the emoji
string, and return an empty string early when any code point is invalid so the
PDF export path stays resilient. Use the `renderEmojiToDataURL` helper and its
`codePoints` parsing logic as the fix point.

In `@ee/packages/federation-matrix/src/utils/emojiConverter.ts`:
- Around line 30-37: The emoji skin-tone mapping in emojiConverter is only
populating _unicodeToShort for each skin, so shortnames like :<base>_toneN: are
not recognized by shortnameToUnicode and can be forwarded raw; update the
emoji.skins handling in the converter to register every value from
getShortcodes(skin.hexcode) in _shortToUnicode, while keeping the existing
unicode-to-short mapping behavior intact.

---

Outside diff comments:
In `@ee/packages/federation-matrix/package.json`:
- Line 44: The federation-matrix package is missing a direct runtime dependency
for a module still imported by member.ts. Update the package.json dependencies
for ee/packages/federation-matrix to restore lodash.debounce alongside the
existing type package, so the import used in the member-related event code
resolves at runtime.

---

Nitpick comments:
In `@apps/meteor/app/emoji-native/lib/generateEmojiData.ts`:
- Line 5: Remove the implementation comments from generateEmojiData.ts,
including the mapping and step-explanation comments around the emoji grouping
logic. Keep the behavior in the existing names/helpers such as the
group/category mapping and related functions, and delete the comment lines at
the referenced spots so the module contains no code comments.

In `@apps/meteor/app/emoji-native/lib/getEmojiConfig.ts`:
- Line 17: Remove the inline implementation comments from getEmojiConfig and
related blocks in the same diff, since the logic in the reverse mapping and
control flow should stand on its own. Keep the code behavior unchanged and
delete the comments near the mapping construction and other marked spots so
getEmojiConfig remains comment-free in the implementation.

In `@apps/meteor/app/emoji-native/server/lib.ts`:
- Around line 27-30: The initializer in legacy shortcode registration contains
implementation comments that should be removed. Update the loop in the
emoji-native server lib so the intent is conveyed by the statements themselves,
and delete the comment above the legacy emojione shortcode registration and the
inline note on the emoji.list key check.

In `@apps/meteor/client/views/root/hooks/useNativeEmoji.ts`:
- Around line 13-52: The one-time emoji registration in useNativeEmoji is doing
heavy synchronous work before paint, so switch this effect from useLayoutEffect
to useEffect. Keep the same initialization logic for emoji.packages.native,
emoji.list, and emoji.dispatchUpdate, but run it after render since no layout
measurement or pre-paint behavior is needed.
- Line 15: The `useNativeEmoji` hook is bypassing type safety by casting
`config.emojiCategories` to `any` before passing it into
`emoji.packages.native`. Update the `config.emojiCategories` type or the
receiving `emoji.packages.native` contract so they match directly, and remove
the cast while keeping the call site in `useNativeEmoji` and the
`emojiCategories` property strongly typed.

In `@apps/meteor/tests/e2e/federation/tests/messaging/dm.spec.ts`:
- Around line 668-674: The reaction emoji selector is hardcoded across the dm
spec, making future class-name changes brittle. Add a reusable reaction-emoji
locator/helper on FederationChannel, preferably using a semantic locator if the
emoji has an accessible name, and update the spec assertions to call that
page-object method instead of repeating the CSS selector. Keep the locator
centralized in the page object and reuse it consistently in all affected
reaction assertion blocks.

In `@apps/meteor/tests/e2e/federation/tests/messaging/private.spec.ts`:
- Around line 579-585: The reaction emoji selector is duplicated in the spec
instead of being centralized behind the page object boundary. Move the
`span.rcx-message-reactions__emoji.emoji` locator into a `FederationChannel`
helper/locator and reuse it in the reaction assertions so the emoji-rendering
contract lives in one place. Update the related reaction checks in the
`private.spec.ts` flows to reference that helper consistently and keep the Page
Object Model boundary intact.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 8c4d3270-90a2-43fe-8080-9e280d98e75b

📥 Commits

Reviewing files that changed from the base of the PR and between 64af832 and 4702b6e.

⛔ Files ignored due to path filters (12)
  • apps/meteor/client/components/UserInfo/__snapshots__/UserInfo.spec.tsx.snap is excluded by !**/*.snap
  • apps/meteor/public/packages/emojione/activity-sprites.png is excluded by !**/*.png
  • apps/meteor/public/packages/emojione/flags-sprites.png is excluded by !**/*.png
  • apps/meteor/public/packages/emojione/food-sprites.png is excluded by !**/*.png
  • apps/meteor/public/packages/emojione/modifier-sprites.png is excluded by !**/*.png
  • apps/meteor/public/packages/emojione/nature-sprites.png is excluded by !**/*.png
  • apps/meteor/public/packages/emojione/objects-sprites.png is excluded by !**/*.png
  • apps/meteor/public/packages/emojione/people-sprites.png is excluded by !**/*.png
  • apps/meteor/public/packages/emojione/regional-sprites.png is excluded by !**/*.png
  • apps/meteor/public/packages/emojione/symbols-sprites.png is excluded by !**/*.png
  • apps/meteor/public/packages/emojione/travel-sprites.png is excluded by !**/*.png
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (85)
  • README.md
  • apps/meteor/.stylelintignore
  • apps/meteor/app/emoji-emojione/.gitignore
  • apps/meteor/app/emoji-emojione/README.md
  • apps/meteor/app/emoji-emojione/client/activity-sprites.css
  • apps/meteor/app/emoji-emojione/client/emojione-sprites.css
  • apps/meteor/app/emoji-emojione/client/flags-sprites.css
  • apps/meteor/app/emoji-emojione/client/food-sprites.css
  • apps/meteor/app/emoji-emojione/client/index.ts
  • apps/meteor/app/emoji-emojione/client/modifier-sprites.css
  • apps/meteor/app/emoji-emojione/client/nature-sprites.css
  • apps/meteor/app/emoji-emojione/client/objects-sprites.css
  • apps/meteor/app/emoji-emojione/client/people-sprites.css
  • apps/meteor/app/emoji-emojione/client/regional-sprites.css
  • apps/meteor/app/emoji-emojione/client/symbols-sprites.css
  • apps/meteor/app/emoji-emojione/client/travel-sprites.css
  • apps/meteor/app/emoji-emojione/lib/emojiPicker.ts
  • apps/meteor/app/emoji-emojione/lib/emojione.tpl
  • apps/meteor/app/emoji-emojione/lib/generateEmojiIndex.mjs
  • apps/meteor/app/emoji-emojione/lib/getEmojiConfig.ts
  • apps/meteor/app/emoji-emojione/lib/isSetNotNull.ts
  • apps/meteor/app/emoji-emojione/server/lib.ts
  • apps/meteor/app/emoji-native/lib/generateEmojiData.ts
  • apps/meteor/app/emoji-native/lib/getEmojiConfig.ts
  • apps/meteor/app/emoji-native/lib/legacyEmojioneMap.ts
  • apps/meteor/app/emoji-native/lib/shortnameToUnicode.ts
  • apps/meteor/app/emoji-native/server/callbacks.ts
  • apps/meteor/app/emoji-native/server/index.ts
  • apps/meteor/app/emoji-native/server/lib.ts
  • apps/meteor/app/emoji/client/emojiParser.ts
  • apps/meteor/app/emoji/client/lib.ts
  • apps/meteor/app/emoji/lib/rocketchat.ts
  • apps/meteor/app/lib/server/lib/sendNotificationsOnMessage.ts
  • apps/meteor/app/theme/client/imports/components/emoji.css
  • apps/meteor/client/components/Emoji.tsx
  • apps/meteor/client/importPackages.ts
  • apps/meteor/client/lib/customEmoji.ts
  • apps/meteor/client/lib/utils/detectEmoji.ts
  • apps/meteor/client/lib/utils/normalizeMessagePreview/normalizeMessagePreview.spec.ts
  • apps/meteor/client/lib/utils/normalizeMessagePreview/normalizeMessagePreview.ts
  • apps/meteor/client/lib/utils/renderEmoji.ts
  • apps/meteor/client/views/composer/EmojiPicker/EmojiCategoryRow.tsx
  • apps/meteor/client/views/composer/EmojiPicker/EmojiElement.tsx
  • apps/meteor/client/views/composer/EmojiPicker/EmojiPicker.tsx
  • apps/meteor/client/views/composer/EmojiPicker/ToneSelector/ToneItem.tsx
  • apps/meteor/client/views/room/composer/messageBox/MessageBox.tsx
  • apps/meteor/client/views/room/contextualBar/ExportMessages/useExportMessagesAsPDFMutation.tsx
  • apps/meteor/client/views/room/providers/ComposerPopupProvider.tsx
  • apps/meteor/client/views/root/AppLayout.tsx
  • apps/meteor/client/views/root/hooks/useEmojiOne.ts
  • apps/meteor/client/views/root/hooks/useNativeEmoji.ts
  • apps/meteor/definition/externals/emojione.d.ts
  • apps/meteor/package.json
  • apps/meteor/server/importPackages.ts
  • apps/meteor/tests/e2e/federation/tests/messaging/dm.spec.ts
  • apps/meteor/tests/e2e/federation/tests/messaging/private.spec.ts
  • apps/meteor/tests/e2e/federation/tests/messaging/public.spec.ts
  • apps/meteor/tests/e2e/message-composer.spec.ts
  • apps/meteor/tests/e2e/messaging.spec.ts
  • apps/meteor/tests/e2e/page-objects/home-channel.ts
  • apps/meteor/tests/unit/app/reactions/server/setReaction.spec.ts
  • ee/apps/omnichannel-transcript/package.json
  • ee/apps/queue-worker/package.json
  • ee/packages/federation-matrix/package.json
  • ee/packages/federation-matrix/src/FederationMatrix.ts
  • ee/packages/federation-matrix/src/events/reaction.ts
  • ee/packages/federation-matrix/src/utils/emojiConverter.ts
  • ee/packages/omnichannel-services/package.json
  • ee/packages/pdf-worker/package.json
  • ee/packages/pdf-worker/src/templates/ChatTranscript/markup/blocks/BigEmojiBlock.tsx
  • ee/packages/pdf-worker/src/templates/ChatTranscript/markup/elements/EmojiSpan.tsx
  • ee/packages/pdf-worker/src/templates/ChatTranscript/markup/emoji.ts
  • ee/packages/pdf-worker/src/types/emoji-toolkit.ts
  • eslint.config.mjs
  • packages/i18n/src/locales/en.i18n.json
  • packages/i18n/src/locales/hi-IN.i18n.json
  • packages/i18n/src/locales/nb.i18n.json
  • packages/i18n/src/locales/nn.i18n.json
  • packages/i18n/src/locales/pt-BR.i18n.json
  • packages/i18n/src/locales/sv.i18n.json
  • packages/i18n/src/locales/zh.i18n.json
  • packages/message-parser/src/grammar.pegjs
  • packages/message-parser/tests/emoji.test.ts
  • packages/ui-avatar/src/components/MessageAvatar.tsx
  • packages/ui-client/src/components/EmojiPicker/EmojiPickerPreview.tsx
💤 Files with no reviewable changes (38)
  • apps/meteor/app/emoji-emojione/README.md
  • apps/meteor/app/emoji-emojione/client/emojione-sprites.css
  • apps/meteor/client/views/root/hooks/useEmojiOne.ts
  • apps/meteor/app/emoji-emojione/client/nature-sprites.css
  • apps/meteor/app/emoji-emojione/client/regional-sprites.css
  • apps/meteor/app/emoji-emojione/.gitignore
  • apps/meteor/app/emoji-emojione/lib/generateEmojiIndex.mjs
  • apps/meteor/app/emoji-emojione/client/modifier-sprites.css
  • apps/meteor/client/views/composer/EmojiPicker/EmojiPicker.tsx
  • apps/meteor/definition/externals/emojione.d.ts
  • apps/meteor/app/emoji-emojione/client/index.ts
  • apps/meteor/app/emoji-emojione/server/lib.ts
  • apps/meteor/app/emoji-emojione/client/activity-sprites.css
  • apps/meteor/app/emoji-emojione/client/food-sprites.css
  • ee/packages/omnichannel-services/package.json
  • apps/meteor/app/emoji-emojione/client/travel-sprites.css
  • ee/packages/pdf-worker/src/types/emoji-toolkit.ts
  • apps/meteor/app/emoji-emojione/client/flags-sprites.css
  • apps/meteor/app/emoji-emojione/lib/emojione.tpl
  • packages/i18n/src/locales/nn.i18n.json
  • eslint.config.mjs
  • apps/meteor/client/importPackages.ts
  • apps/meteor/app/emoji-emojione/client/objects-sprites.css
  • apps/meteor/app/emoji-emojione/lib/isSetNotNull.ts
  • packages/i18n/src/locales/hi-IN.i18n.json
  • packages/i18n/src/locales/pt-BR.i18n.json
  • ee/apps/queue-worker/package.json
  • apps/meteor/app/emoji-emojione/lib/getEmojiConfig.ts
  • apps/meteor/.stylelintignore
  • packages/i18n/src/locales/zh.i18n.json
  • packages/i18n/src/locales/en.i18n.json
  • apps/meteor/app/emoji-emojione/lib/emojiPicker.ts
  • apps/meteor/app/emoji-emojione/client/symbols-sprites.css
  • README.md
  • packages/i18n/src/locales/sv.i18n.json
  • apps/meteor/client/views/composer/EmojiPicker/EmojiElement.tsx
  • packages/i18n/src/locales/nb.i18n.json
  • ee/apps/omnichannel-transcript/package.json
📜 Review details
⏰ Context from checks skipped due to timeout. (4)
  • GitHub Check: cubic · AI code reviewer
  • GitHub Check: Hacktron Security Check
  • GitHub Check: 📦 Build Packages
  • GitHub Check: CodeQL-Build
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (.cursor/rules/playwright.mdc)

**/*.{ts,tsx,js}: Write concise, technical TypeScript/JavaScript with accurate typing in Playwright tests
Avoid code comments in the implementation

Files:

  • apps/meteor/client/lib/utils/normalizeMessagePreview/normalizeMessagePreview.spec.ts
  • apps/meteor/server/importPackages.ts
  • apps/meteor/app/emoji-native/server/callbacks.ts
  • apps/meteor/tests/e2e/message-composer.spec.ts
  • apps/meteor/tests/unit/app/reactions/server/setReaction.spec.ts
  • ee/packages/pdf-worker/src/templates/ChatTranscript/markup/elements/EmojiSpan.tsx
  • apps/meteor/app/emoji-native/lib/shortnameToUnicode.ts
  • apps/meteor/client/components/Emoji.tsx
  • ee/packages/pdf-worker/src/templates/ChatTranscript/markup/emoji.ts
  • apps/meteor/client/lib/utils/detectEmoji.ts
  • apps/meteor/app/emoji/lib/rocketchat.ts
  • packages/ui-client/src/components/EmojiPicker/EmojiPickerPreview.tsx
  • apps/meteor/tests/e2e/messaging.spec.ts
  • apps/meteor/app/emoji-native/lib/legacyEmojioneMap.ts
  • apps/meteor/client/views/room/composer/messageBox/MessageBox.tsx
  • apps/meteor/client/lib/utils/normalizeMessagePreview/normalizeMessagePreview.ts
  • apps/meteor/tests/e2e/page-objects/home-channel.ts
  • apps/meteor/client/views/root/AppLayout.tsx
  • apps/meteor/app/emoji-native/server/lib.ts
  • ee/packages/pdf-worker/src/templates/ChatTranscript/markup/blocks/BigEmojiBlock.tsx
  • packages/ui-avatar/src/components/MessageAvatar.tsx
  • ee/packages/federation-matrix/src/events/reaction.ts
  • apps/meteor/client/lib/customEmoji.ts
  • apps/meteor/client/views/composer/EmojiPicker/ToneSelector/ToneItem.tsx
  • packages/message-parser/tests/emoji.test.ts
  • apps/meteor/client/views/room/contextualBar/ExportMessages/useExportMessagesAsPDFMutation.tsx
  • apps/meteor/app/emoji-native/lib/getEmojiConfig.ts
  • apps/meteor/app/lib/server/lib/sendNotificationsOnMessage.ts
  • apps/meteor/client/views/root/hooks/useNativeEmoji.ts
  • ee/packages/federation-matrix/src/FederationMatrix.ts
  • apps/meteor/client/views/room/providers/ComposerPopupProvider.tsx
  • ee/packages/federation-matrix/src/utils/emojiConverter.ts
  • apps/meteor/client/lib/utils/renderEmoji.ts
  • apps/meteor/tests/e2e/federation/tests/messaging/private.spec.ts
  • apps/meteor/tests/e2e/federation/tests/messaging/dm.spec.ts
  • apps/meteor/app/emoji-native/lib/generateEmojiData.ts
  • apps/meteor/tests/e2e/federation/tests/messaging/public.spec.ts
  • apps/meteor/app/emoji/client/emojiParser.ts
  • apps/meteor/client/views/composer/EmojiPicker/EmojiCategoryRow.tsx
  • apps/meteor/app/emoji/client/lib.ts
**/*.spec.ts

📄 CodeRabbit inference engine (.cursor/rules/playwright.mdc)

**/*.spec.ts: Use descriptive test names that clearly communicate expected behavior in Playwright tests
Use .spec.ts extension for test files (e.g., login.spec.ts)

Files:

  • apps/meteor/client/lib/utils/normalizeMessagePreview/normalizeMessagePreview.spec.ts
  • apps/meteor/tests/e2e/message-composer.spec.ts
  • apps/meteor/tests/unit/app/reactions/server/setReaction.spec.ts
  • apps/meteor/tests/e2e/messaging.spec.ts
  • apps/meteor/tests/e2e/federation/tests/messaging/private.spec.ts
  • apps/meteor/tests/e2e/federation/tests/messaging/dm.spec.ts
  • apps/meteor/tests/e2e/federation/tests/messaging/public.spec.ts
apps/meteor/tests/e2e/**/*.spec.ts

📄 CodeRabbit inference engine (.cursor/rules/playwright.mdc)

apps/meteor/tests/e2e/**/*.spec.ts: All test files must be created in apps/meteor/tests/e2e/ directory
Avoid using page.locator() in Playwright tests - always prefer semantic locators such as page.getByRole(), page.getByLabel(), page.getByText(), or page.getByTitle()
Use test.beforeAll() and test.afterAll() for setup/teardown in Playwright tests
Use test.step() for complex test scenarios to improve organization in Playwright tests
Group related tests in the same file
Utilize Playwright fixtures (test, page, expect) for consistency in test files
Prefer web-first assertions (toBeVisible, toHaveText, etc.) in Playwright tests
Use expect matchers for assertions (toEqual, toContain, toBeTruthy, toHaveLength, etc.) instead of assert statements in Playwright tests
Use page.waitFor() with specific conditions instead of hardcoded timeouts in Playwright tests
Implement proper wait strategies for dynamic content in Playwright tests
Maintain test isolation between test cases in Playwright tests
Ensure clean state for each test execution in Playwright tests
Ensure tests run reliably in parallel without shared state conflicts

Files:

  • apps/meteor/tests/e2e/message-composer.spec.ts
  • apps/meteor/tests/e2e/messaging.spec.ts
  • apps/meteor/tests/e2e/federation/tests/messaging/private.spec.ts
  • apps/meteor/tests/e2e/federation/tests/messaging/dm.spec.ts
  • apps/meteor/tests/e2e/federation/tests/messaging/public.spec.ts
apps/meteor/tests/e2e/**/*.{ts,spec.ts}

📄 CodeRabbit inference engine (.cursor/rules/playwright.mdc)

apps/meteor/tests/e2e/**/*.{ts,spec.ts}: Store commonly used locators in variables/constants for reuse
Follow Page Object Model pattern consistently in Playwright tests

Files:

  • apps/meteor/tests/e2e/message-composer.spec.ts
  • apps/meteor/tests/e2e/messaging.spec.ts
  • apps/meteor/tests/e2e/page-objects/home-channel.ts
  • apps/meteor/tests/e2e/federation/tests/messaging/private.spec.ts
  • apps/meteor/tests/e2e/federation/tests/messaging/dm.spec.ts
  • apps/meteor/tests/e2e/federation/tests/messaging/public.spec.ts
apps/meteor/tests/e2e/page-objects/**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/playwright.mdc)

Utilize existing page objects pattern from apps/meteor/tests/e2e/page-objects/

Files:

  • apps/meteor/tests/e2e/page-objects/home-channel.ts
🧠 Learnings (11)
📚 Learning: 2026-02-10T16:32:42.586Z
Learnt from: tassoevan
Repo: RocketChat/Rocket.Chat PR: 38528
File: apps/meteor/client/startup/roles.ts:14-14
Timestamp: 2026-02-10T16:32:42.586Z
Learning: In Rocket.Chat's Meteor client code, DDP streams use EJSON and Date fields arrive as Date objects; do not manually construct new Date() in stream handlers (for example, in sdk.stream()). Only REST API responses return plain JSON where dates are strings, so implement explicit conversion there if needed. Apply this guidance to all TypeScript files under apps/meteor/client to ensure consistent date handling in DDP streams and REST responses.

Applied to files:

  • apps/meteor/client/lib/utils/normalizeMessagePreview/normalizeMessagePreview.spec.ts
  • apps/meteor/client/lib/utils/detectEmoji.ts
  • apps/meteor/client/lib/utils/normalizeMessagePreview/normalizeMessagePreview.ts
  • apps/meteor/client/lib/customEmoji.ts
  • apps/meteor/client/views/root/hooks/useNativeEmoji.ts
  • apps/meteor/client/lib/utils/renderEmoji.ts
📚 Learning: 2026-05-11T20:30:35.265Z
Learnt from: tassoevan
Repo: RocketChat/Rocket.Chat PR: 40480
File: apps/meteor/client/meteor/startup/accounts.ts:59-61
Timestamp: 2026-05-11T20:30:35.265Z
Learning: In Rocket.Chat’s Meteor client code, when calling `dispatchToastMessage` with `{ type: 'error' }`, pass the raw caught error object as `message` without manual normalization. `dispatchToastMessage` is designed to accept `message: unknown` for error toasts, so avoid converting errors to strings (e.g., `String(error)`) or extracting `error.message` before passing them.

Applied to files:

  • apps/meteor/client/lib/utils/normalizeMessagePreview/normalizeMessagePreview.spec.ts
  • apps/meteor/client/lib/utils/detectEmoji.ts
  • apps/meteor/client/lib/utils/normalizeMessagePreview/normalizeMessagePreview.ts
  • apps/meteor/client/lib/customEmoji.ts
  • apps/meteor/client/views/root/hooks/useNativeEmoji.ts
  • apps/meteor/client/lib/utils/renderEmoji.ts
📚 Learning: 2026-02-24T19:22:48.358Z
Learnt from: juliajforesti
Repo: RocketChat/Rocket.Chat PR: 38493
File: apps/meteor/tests/e2e/omnichannel/omnichannel-send-pdf-transcript.spec.ts:66-67
Timestamp: 2026-02-24T19:22:48.358Z
Learning: In Playwright end-to-end tests (e.g., under apps/meteor/tests/e2e/...), prefer locating elements by translated text (getByText) and ARIA roles (getByRole) over data-qa attributes. If translation values change, update the corresponding test locators accordingly. Never use data-qa locators. This guideline applies to all Playwright e2e test specs in the repository and helps keep tests robust to UI text changes and accessible semantics.

Applied to files:

  • apps/meteor/client/lib/utils/normalizeMessagePreview/normalizeMessagePreview.spec.ts
  • apps/meteor/tests/e2e/message-composer.spec.ts
  • apps/meteor/tests/unit/app/reactions/server/setReaction.spec.ts
  • apps/meteor/tests/e2e/messaging.spec.ts
  • apps/meteor/tests/e2e/federation/tests/messaging/private.spec.ts
  • apps/meteor/tests/e2e/federation/tests/messaging/dm.spec.ts
  • apps/meteor/tests/e2e/federation/tests/messaging/public.spec.ts
📚 Learning: 2026-02-26T19:25:44.063Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 38778
File: packages/ui-voip/src/providers/useMediaSession.ts:192-192
Timestamp: 2026-02-26T19:25:44.063Z
Learning: In the Rocket.Chat repository, do not reference Biome lint rules in code review feedback. Biome is not used even if biome.json exists; only reference Biome rules if there is explicit, project-wide usage documented. For TypeScript files, review lint implications without Biome guidance unless the project enables Biome rules.

Applied to files:

  • apps/meteor/client/lib/utils/normalizeMessagePreview/normalizeMessagePreview.spec.ts
  • apps/meteor/server/importPackages.ts
  • apps/meteor/app/emoji-native/server/callbacks.ts
  • apps/meteor/tests/e2e/message-composer.spec.ts
  • apps/meteor/tests/unit/app/reactions/server/setReaction.spec.ts
  • apps/meteor/app/emoji-native/lib/shortnameToUnicode.ts
  • ee/packages/pdf-worker/src/templates/ChatTranscript/markup/emoji.ts
  • apps/meteor/client/lib/utils/detectEmoji.ts
  • apps/meteor/app/emoji/lib/rocketchat.ts
  • apps/meteor/tests/e2e/messaging.spec.ts
  • apps/meteor/app/emoji-native/lib/legacyEmojioneMap.ts
  • apps/meteor/client/lib/utils/normalizeMessagePreview/normalizeMessagePreview.ts
  • apps/meteor/tests/e2e/page-objects/home-channel.ts
  • apps/meteor/app/emoji-native/server/lib.ts
  • ee/packages/federation-matrix/src/events/reaction.ts
  • apps/meteor/client/lib/customEmoji.ts
  • packages/message-parser/tests/emoji.test.ts
  • apps/meteor/app/emoji-native/lib/getEmojiConfig.ts
  • apps/meteor/app/lib/server/lib/sendNotificationsOnMessage.ts
  • apps/meteor/client/views/root/hooks/useNativeEmoji.ts
  • ee/packages/federation-matrix/src/FederationMatrix.ts
  • ee/packages/federation-matrix/src/utils/emojiConverter.ts
  • apps/meteor/client/lib/utils/renderEmoji.ts
  • apps/meteor/tests/e2e/federation/tests/messaging/private.spec.ts
  • apps/meteor/tests/e2e/federation/tests/messaging/dm.spec.ts
  • apps/meteor/app/emoji-native/lib/generateEmojiData.ts
  • apps/meteor/tests/e2e/federation/tests/messaging/public.spec.ts
  • apps/meteor/app/emoji/client/emojiParser.ts
  • apps/meteor/app/emoji/client/lib.ts
📚 Learning: 2026-02-26T19:25:44.063Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 38778
File: packages/ui-voip/src/providers/useMediaSession.ts:192-192
Timestamp: 2026-02-26T19:25:44.063Z
Learning: In this repository (RocketChat/Rocket.Chat), Biome lint rules are not used even if a biome.json exists. When reviewing TypeScript files (e.g., packages/ui-voip/src/providers/useMediaSession.ts), ensure lint suggestions do not reference Biome-specific rules. Rely on general ESLint/TypeScript lint rules and project conventions instead.

Applied to files:

  • apps/meteor/client/lib/utils/normalizeMessagePreview/normalizeMessagePreview.spec.ts
  • apps/meteor/server/importPackages.ts
  • apps/meteor/app/emoji-native/server/callbacks.ts
  • apps/meteor/tests/e2e/message-composer.spec.ts
  • apps/meteor/tests/unit/app/reactions/server/setReaction.spec.ts
  • apps/meteor/app/emoji-native/lib/shortnameToUnicode.ts
  • ee/packages/pdf-worker/src/templates/ChatTranscript/markup/emoji.ts
  • apps/meteor/client/lib/utils/detectEmoji.ts
  • apps/meteor/app/emoji/lib/rocketchat.ts
  • apps/meteor/tests/e2e/messaging.spec.ts
  • apps/meteor/app/emoji-native/lib/legacyEmojioneMap.ts
  • apps/meteor/client/lib/utils/normalizeMessagePreview/normalizeMessagePreview.ts
  • apps/meteor/tests/e2e/page-objects/home-channel.ts
  • apps/meteor/app/emoji-native/server/lib.ts
  • ee/packages/federation-matrix/src/events/reaction.ts
  • apps/meteor/client/lib/customEmoji.ts
  • packages/message-parser/tests/emoji.test.ts
  • apps/meteor/app/emoji-native/lib/getEmojiConfig.ts
  • apps/meteor/app/lib/server/lib/sendNotificationsOnMessage.ts
  • apps/meteor/client/views/root/hooks/useNativeEmoji.ts
  • ee/packages/federation-matrix/src/FederationMatrix.ts
  • ee/packages/federation-matrix/src/utils/emojiConverter.ts
  • apps/meteor/client/lib/utils/renderEmoji.ts
  • apps/meteor/tests/e2e/federation/tests/messaging/private.spec.ts
  • apps/meteor/tests/e2e/federation/tests/messaging/dm.spec.ts
  • apps/meteor/app/emoji-native/lib/generateEmojiData.ts
  • apps/meteor/tests/e2e/federation/tests/messaging/public.spec.ts
  • apps/meteor/app/emoji/client/emojiParser.ts
  • apps/meteor/app/emoji/client/lib.ts
📚 Learning: 2026-03-06T18:10:15.268Z
Learnt from: tassoevan
Repo: RocketChat/Rocket.Chat PR: 39397
File: packages/gazzodown/src/code/CodeBlock.spec.tsx:47-68
Timestamp: 2026-03-06T18:10:15.268Z
Learning: In tests (especially those using testing-library/dom/jsdom) for Rocket.Chat components, the HTML <code> element has an implicit ARIA role of 'code'. Therefore, screen.getByRole('code') or screen.findByRole('code') will locate <code> elements even without a role attribute. Do not flag findByRole('code') as invalid in reviews; prefer using the implicit role instead of adding role="code" unless necessary for accessibility.

Applied to files:

  • apps/meteor/client/lib/utils/normalizeMessagePreview/normalizeMessagePreview.spec.ts
  • apps/meteor/tests/e2e/message-composer.spec.ts
  • apps/meteor/tests/unit/app/reactions/server/setReaction.spec.ts
  • apps/meteor/tests/e2e/messaging.spec.ts
  • apps/meteor/tests/e2e/federation/tests/messaging/private.spec.ts
  • apps/meteor/tests/e2e/federation/tests/messaging/dm.spec.ts
  • apps/meteor/tests/e2e/federation/tests/messaging/public.spec.ts
📚 Learning: 2026-05-06T12:21:44.083Z
Learnt from: juliajforesti
Repo: RocketChat/Rocket.Chat PR: 40256
File: apps/meteor/client/components/CreateDiscussion/CreateDiscussion.tsx:121-149
Timestamp: 2026-05-06T12:21:44.083Z
Learning: Field wrappers in rocket.chat/fuselage-forms (Field, FieldLabel, FieldRow, FieldError, FieldHint) auto-create htmlFor/id associations, aria-describedby, and role="alert" for errors. Do not manually set htmlFor, id, aria-describedby, or role attributes when using these wrappers. This automatic wiring does not apply to plain rocket.chat/fuselage components, which require explicit ID wiring per the accessibility docs. In code reviews, prefer using fuselage-forms wrappers for form fields and verify there is no unnecessary manual ID/aria wiring in files that use these wrappers. If a component uses plain fuselage components, ensure proper id wiring as per docs.

Applied to files:

  • apps/meteor/client/lib/utils/normalizeMessagePreview/normalizeMessagePreview.spec.ts
  • apps/meteor/server/importPackages.ts
  • apps/meteor/app/emoji-native/server/callbacks.ts
  • apps/meteor/tests/e2e/message-composer.spec.ts
  • apps/meteor/tests/unit/app/reactions/server/setReaction.spec.ts
  • ee/packages/pdf-worker/src/templates/ChatTranscript/markup/elements/EmojiSpan.tsx
  • apps/meteor/app/emoji-native/lib/shortnameToUnicode.ts
  • apps/meteor/client/components/Emoji.tsx
  • ee/packages/pdf-worker/src/templates/ChatTranscript/markup/emoji.ts
  • apps/meteor/client/lib/utils/detectEmoji.ts
  • apps/meteor/app/emoji/lib/rocketchat.ts
  • packages/ui-client/src/components/EmojiPicker/EmojiPickerPreview.tsx
  • apps/meteor/tests/e2e/messaging.spec.ts
  • apps/meteor/app/emoji-native/lib/legacyEmojioneMap.ts
  • apps/meteor/client/views/room/composer/messageBox/MessageBox.tsx
  • apps/meteor/client/lib/utils/normalizeMessagePreview/normalizeMessagePreview.ts
  • apps/meteor/tests/e2e/page-objects/home-channel.ts
  • apps/meteor/client/views/root/AppLayout.tsx
  • apps/meteor/app/emoji-native/server/lib.ts
  • ee/packages/pdf-worker/src/templates/ChatTranscript/markup/blocks/BigEmojiBlock.tsx
  • packages/ui-avatar/src/components/MessageAvatar.tsx
  • ee/packages/federation-matrix/src/events/reaction.ts
  • apps/meteor/client/lib/customEmoji.ts
  • apps/meteor/client/views/composer/EmojiPicker/ToneSelector/ToneItem.tsx
  • packages/message-parser/tests/emoji.test.ts
  • apps/meteor/client/views/room/contextualBar/ExportMessages/useExportMessagesAsPDFMutation.tsx
  • apps/meteor/app/emoji-native/lib/getEmojiConfig.ts
  • apps/meteor/app/lib/server/lib/sendNotificationsOnMessage.ts
  • apps/meteor/client/views/root/hooks/useNativeEmoji.ts
  • ee/packages/federation-matrix/src/FederationMatrix.ts
  • apps/meteor/client/views/room/providers/ComposerPopupProvider.tsx
  • ee/packages/federation-matrix/src/utils/emojiConverter.ts
  • apps/meteor/client/lib/utils/renderEmoji.ts
  • apps/meteor/tests/e2e/federation/tests/messaging/private.spec.ts
  • apps/meteor/tests/e2e/federation/tests/messaging/dm.spec.ts
  • apps/meteor/app/emoji-native/lib/generateEmojiData.ts
  • apps/meteor/tests/e2e/federation/tests/messaging/public.spec.ts
  • apps/meteor/app/emoji/client/emojiParser.ts
  • apps/meteor/client/views/composer/EmojiPicker/EmojiCategoryRow.tsx
  • apps/meteor/app/emoji/client/lib.ts
📚 Learning: 2026-02-24T19:39:42.247Z
Learnt from: juliajforesti
Repo: RocketChat/Rocket.Chat PR: 38493
File: apps/meteor/tests/e2e/page-objects/fragments/message.ts:7-7
Timestamp: 2026-02-24T19:39:42.247Z
Learning: In RocketChat e2e tests, avoid using data-qa attributes to locate elements. Prefer semantic locators such as getByRole, getByLabel, getByText, getByTitle and ARIA-based selectors. Apply this rule to all TypeScript files under apps/meteor/tests/e2e to improve test reliability, accessibility, and maintainability.

Applied to files:

  • apps/meteor/tests/e2e/message-composer.spec.ts
  • apps/meteor/tests/e2e/messaging.spec.ts
  • apps/meteor/tests/e2e/page-objects/home-channel.ts
  • apps/meteor/tests/e2e/federation/tests/messaging/private.spec.ts
  • apps/meteor/tests/e2e/federation/tests/messaging/dm.spec.ts
  • apps/meteor/tests/e2e/federation/tests/messaging/public.spec.ts
📚 Learning: 2026-03-27T14:52:56.865Z
Learnt from: dougfabris
Repo: RocketChat/Rocket.Chat PR: 39892
File: apps/meteor/client/views/room/contextualBar/Threads/Thread.tsx:150-155
Timestamp: 2026-03-27T14:52:56.865Z
Learning: In Rocket.Chat, there are two different `ModalBackdrop` components with different prop APIs. During review, confirm the import source: (1) `rocket.chat/fuselage` `ModalBackdrop` uses `ModalBackdropProps` based on `BoxProps` (so it supports `onClick` and other Box/DOM props) and does not have an `onDismiss` prop; (2) `rocket.chat/ui-client` `ModalBackdrop` uses a narrower props interface like `{ children?: ReactNode; onDismiss?: () => void }` and handles Escape keypress and outside mouse-up, and it does not forward arbitrary DOM props such as `onClick`. Flag mismatched props (e.g., `onDismiss` passed to the fuselage component or `onClick` passed to the ui-client component) and ensure the usage matches the correct component being imported.

Applied to files:

  • ee/packages/pdf-worker/src/templates/ChatTranscript/markup/elements/EmojiSpan.tsx
  • apps/meteor/client/components/Emoji.tsx
  • packages/ui-client/src/components/EmojiPicker/EmojiPickerPreview.tsx
  • apps/meteor/client/views/room/composer/messageBox/MessageBox.tsx
  • apps/meteor/client/views/root/AppLayout.tsx
  • ee/packages/pdf-worker/src/templates/ChatTranscript/markup/blocks/BigEmojiBlock.tsx
  • packages/ui-avatar/src/components/MessageAvatar.tsx
  • apps/meteor/client/views/composer/EmojiPicker/ToneSelector/ToneItem.tsx
  • apps/meteor/client/views/room/contextualBar/ExportMessages/useExportMessagesAsPDFMutation.tsx
  • apps/meteor/client/views/room/providers/ComposerPopupProvider.tsx
  • apps/meteor/client/views/composer/EmojiPicker/EmojiCategoryRow.tsx
📚 Learning: 2025-12-16T17:29:40.430Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 37834
File: apps/meteor/tests/e2e/page-objects/fragments/admin-flextab-emoji.ts:12-22
Timestamp: 2025-12-16T17:29:40.430Z
Learning: In all page-object files under apps/meteor/tests/e2e/page-objects/, import expect from ../../utils/test (Playwright's async expect) instead of from Jest. Jest's expect is synchronous and incompatible with web-first assertions like toBeVisible, which can cause TypeScript errors.

Applied to files:

  • apps/meteor/tests/e2e/page-objects/home-channel.ts
📚 Learning: 2025-12-09T20:01:00.324Z
Learnt from: sampaiodiego
Repo: RocketChat/Rocket.Chat PR: 37532
File: ee/packages/federation-matrix/src/FederationMatrix.ts:920-927
Timestamp: 2025-12-09T20:01:00.324Z
Learning: When reviewing federation invite handling in Rocket.Chat (specifically under ee/packages/federation-matrix), understand that rejecting an invite via federationSDK.rejectInvite() triggers an event-driven cleanup: a leave event is emitted and handled by handleLeave() in ee/packages/federation-matrix/src/events/member.ts, which calls Room.performUserRemoval() to remove the subscription. Do not add explicit cleanup in the reject branch of handleInvite(); rely on the existing leave-event flow for cleanup. If making changes, ensure this invariant remains and that any related paths still funnel cleanup through the leave event to avoid duplicate or missing removals.

Applied to files:

  • ee/packages/federation-matrix/src/events/reaction.ts
  • ee/packages/federation-matrix/src/FederationMatrix.ts
  • ee/packages/federation-matrix/src/utils/emojiConverter.ts
🪛 ast-grep (0.44.0)
apps/meteor/client/views/composer/EmojiPicker/ToneSelector/ToneItem.tsx

[warning] 25-25: Usage of dangerouslySetInnerHTML detected. This bypasses React's built-in XSS protection. Always sanitize HTML content using libraries like DOMPurify before injecting it into the DOM to prevent XSS attacks.
Context: dangerouslySetInnerHTML
Note: [CWE-79] Improper Neutralization of Input During Web Page Generation

(react-unsafe-html-injection)

apps/meteor/app/emoji-native/lib/getEmojiConfig.ts

[warning] 42-42: Regular expression constructed from variable input detected. This can lead to Regular Expression Denial of Service (ReDoS) attacks if the variable contains malicious patterns. Use libraries like 'recheck' to validate regex safety or use static patterns.
Context: new RegExp((:([a-zA-Z0-9_+-]+):)|(${unicodePattern}), 'g')
Note: [CWE-1333] Inefficient Regular Expression Complexity

(regexp-from-variable)

🔇 Additional comments (35)
apps/meteor/app/emoji/lib/rocketchat.ts (1)

21-35: LGTM!

apps/meteor/client/views/root/AppLayout.tsx (1)

32-32: LGTM!

Also applies to: 57-57

apps/meteor/app/emoji/client/lib.ts (1)

16-16: 🎯 Functional Correctness

No change needed packages.base.render is now a passthrough; shortcode conversion is handled by the native emoji package, and no remaining caller depends on the base renderer for that behavior.

apps/meteor/app/emoji-native/lib/legacyEmojioneMap.ts (1)

5-1410: LGTM!

apps/meteor/server/importPackages.ts (1)

18-18: LGTM!

apps/meteor/app/emoji-native/server/callbacks.ts (1)

4-12: LGTM!

apps/meteor/app/emoji-native/lib/shortnameToUnicode.ts (1)

5-19: 🚀 Performance & Scalability

No action needed: getEmojiData() is already cached. shortnameToUnicode() reuses the memoized emoji data, so it does not rebuild the map on each call.

			> Likely an incorrect or invalid review comment.
apps/meteor/package.json (1)

200-201: 🔒 Security & Privacy

No action needed for emojibase/emojibase-data ^16.0.0 is published for both packages, and emojibase-data 16.0.0 has no known advisories.

apps/meteor/app/lib/server/lib/sendNotificationsOnMessage.ts (1)

194-194: LGTM!

apps/meteor/client/lib/utils/normalizeMessagePreview/normalizeMessagePreview.ts (1)

5-10: LGTM!

ee/packages/pdf-worker/package.json (1)

24-24: LGTM!

ee/packages/pdf-worker/src/templates/ChatTranscript/markup/emoji.ts (1)

1-38: LGTM!

ee/packages/pdf-worker/src/templates/ChatTranscript/markup/blocks/BigEmojiBlock.tsx (1)

3-14: LGTM!

ee/packages/pdf-worker/src/templates/ChatTranscript/markup/elements/EmojiSpan.tsx (1)

4-8: LGTM!

apps/meteor/client/views/room/contextualBar/ExportMessages/useExportMessagesAsPDFMutation.tsx (1)

103-108: LGTM!

apps/meteor/client/views/room/composer/messageBox/MessageBox.tsx (1)

166-170: LGTM!

apps/meteor/client/views/room/providers/ComposerPopupProvider.tsx (1)

253-256: LGTM!

ee/packages/federation-matrix/src/utils/emojiConverter.ts (1)

47-50: 🎯 Functional Correctness | ⚡ Quick win

unicodeToShortname requires an exact unicode key match.

The lookup is a direct Map.get(text); an incoming Matrix reaction key that differs only by a presentation variation selector (U+FE0F) or other normalization from emojibase's emoji/skin.emoji value will miss and fall through to returning the raw unicode as the "shortname", which then gets persisted as the RC reaction name. The old emojione.toShort was tolerant of variation selectors — worth confirming this regression won't surface for common reactions.

ee/packages/federation-matrix/src/FederationMatrix.ts (1)

21-21: LGTM!

Also applies to: 522-522, 562-562

ee/packages/federation-matrix/src/events/reaction.ts (1)

42-42: LGTM!

Also applies to: 86-86

packages/message-parser/src/grammar.pegjs (1)

743-762: 🎯 Functional Correctness

No action needed. Standalone emojis from the affected blocks and multi-component ZWJ sequences are already covered by tests.

apps/meteor/tests/e2e/page-objects/home-channel.ts (1)

172-177: LGTM!

apps/meteor/tests/e2e/federation/tests/messaging/public.spec.ts (1)

575-581: LGTM!

Also applies to: 602-608, 640-646, 663-676, 709-715, 732-745

apps/meteor/tests/e2e/message-composer.spec.ts (1)

81-88: LGTM!

apps/meteor/tests/e2e/messaging.spec.ts (1)

245-245: LGTM!

apps/meteor/tests/unit/app/reactions/server/setReaction.spec.ts (1)

123-123: LGTM!

apps/meteor/app/theme/client/imports/components/emoji.css (1)

1-45: LGTM!

apps/meteor/client/components/Emoji.tsx (1)

22-31: LGTM!

apps/meteor/client/lib/customEmoji.ts (1)

98-130: LGTM!

apps/meteor/client/lib/utils/detectEmoji.ts (1)

3-14: LGTM!

apps/meteor/client/lib/utils/renderEmoji.ts (1)

24-57: LGTM!

apps/meteor/app/emoji/client/emojiParser.ts (1)

23-23: LGTM!

Also applies to: 35-59

apps/meteor/client/views/composer/EmojiPicker/EmojiCategoryRow.tsx (1)

49-55: LGTM!

packages/ui-client/src/components/EmojiPicker/EmojiPickerPreview.tsx (1)

9-9: LGTM!

packages/ui-avatar/src/components/MessageAvatar.tsx (1)

1-2: LGTM!

Also applies to: 14-23

Comment on lines +97 to +101
for (const skin of emojiData.skins) {
if (!skin.tone) continue;

const toneNum = Array.isArray(skin.tone) ? skin.tone[0] : skin.tone;
const toneKey = `:${primaryShortcode}_tone${toneNum}:`;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major

🧩 Analysis chain

🌐 Web query:

In emojibase 16.0.0, can Emoji.skins[].tone be an array for mixed-tone variants, and how are those variants represented?

💡 Result:

In Emojibase 16.0.0, the Emoji.tone property can indeed be an array to support multi-person skin tones [1][2][3]. For emojis representing a single person, Emoji.tone is a single number (1–5) corresponding to the standard skin tones (1: light, 2: medium-light, 3: medium, 4: medium-dark, 5: dark) [3][4]. For emojis that support mixed-tone variants (such as a handshake between two people), the tone property is represented as an array of these numbers (e.g., [1, 5]) [3][5]. Regarding the Emoji.skins array, it acts as a collection of variant emoji objects for a given base emoji [6][3]. Because this array includes both single and multi-person skin tone variations, it may contain more than the traditional five variations (sometimes up to 15 or more) [1][6]. These variants are stored as fully defined emoji objects within the skins array, each containing their own metadata, including their specific tone property (which will be an array for mixed-tone variants) [6][3].

Citations:


🏁 Script executed:

sed -n '1,220p' apps/meteor/app/emoji-native/lib/generateEmojiData.ts

Repository: RocketChat/Rocket.Chat

Length of output: 3423


🏁 Script executed:

sed -n '1,220p' apps/meteor/app/emoji-native/lib/generateEmojiData.ts

Repository: RocketChat/Rocket.Chat

Length of output: 3423


🏁 Script executed:

sed -n '1,220p' apps/meteor/app/emoji-native/lib/generateEmojiData.ts

Repository: RocketChat/Rocket.Chat

Length of output: 3423


🏁 Script executed:

sed -n '1,220p' apps/meteor/app/emoji-native/lib/generateEmojiData.ts

Repository: RocketChat/Rocket.Chat

Length of output: 3423


🏁 Script executed:

python3 - <<'PY'
import json, re, pathlib

# Find the package version references.
for path in ["package.json", "apps/meteor/package.json", "apps/meteor/app/emoji-native/package.json", "pnpm-lock.yaml", "package-lock.json", "yarn.lock"]:
    p = pathlib.Path(path)
    if p.exists():
        text = p.read_text(errors="ignore")
        if "emojibase" in text:
            print(f"== {path} ==")
            for m in re.finditer(r'emojibase[^"\n: ]*["\':\s]+([^"\n]+)', text):
                print(m.group(0)[:120])

# Inspect the installed/data JSON shape if present in repo.
candidates = [
    "node_modules/emojibase-data/en/data.json",
    "apps/meteor/app/emoji-native/lib/../../../../node_modules/emojibase-data/en/data.json",
    "apps/meteor/app/emoji-native/lib/../../../../packages/data/en/data.json",
]
for c in candidates:
    p = pathlib.Path(c)
    if p.exists():
        data = json.loads(p.read_text())
        arrays = []
        count = 0
        for e in data:
            skins = e.get("skins") or []
            for s in skins:
                tone = s.get("tone")
                if isinstance(tone, list):
                    arrays.append((e.get("hexcode"), s.get("hexcode"), tone))
                    count += 1
                    if count >= 20:
                        break
            if count >= 20:
                break
        print(f"== {c} ==")
        print(f"array_tone_count_sample={len(arrays)}")
        for item in arrays[:10]:
            print(item)
        break
PY

Repository: RocketChat/Rocket.Chat

Length of output: 499


🏁 Script executed:

python3 - <<'PY'
import json, re, pathlib

# Find the package version references.
for path in ["package.json", "apps/meteor/package.json", "apps/meteor/app/emoji-native/package.json", "pnpm-lock.yaml", "package-lock.json", "yarn.lock"]:
    p = pathlib.Path(path)
    if p.exists():
        text = p.read_text(errors="ignore")
        if "emojibase" in text:
            print(f"== {path} ==")
            for m in re.finditer(r'emojibase[^"\n: ]*["\':\s]+([^"\n]+)', text):
                print(m.group(0)[:120])

# Inspect the bundled data shape for skin tone arrays.
candidates = [
    "node_modules/emojibase-data/en/data.json",
    "apps/meteor/app/emoji-native/node_modules/emojibase-data/en/data.json",
]
for c in candidates:
    p = pathlib.Path(c)
    if p.exists():
        data = json.loads(p.read_text())
        arrays = []
        for e in data:
            for s in e.get("skins") or []:
                tone = s.get("tone")
                if isinstance(tone, list):
                    arrays.append((e.get("hexcode"), s.get("hexcode"), tone))
                    if len(arrays) >= 20:
                        break
            if len(arrays) >= 20:
                break
        print(f"== {c} ==")
        print(f"array_tone_count_sample={len(arrays)}")
        for item in arrays[:10]:
            print(item)
        break
PY

Repository: RocketChat/Rocket.Chat

Length of output: 499


Preserve all tone values in mixed-tone skin keys. skin.tone can be an array for mixed-tone variants, so skin.tone[0] collapses distinct variants onto the same :${primaryShortcode}_toneN: key. Encode the full tone tuple in the key or skip mixed-tone skins explicitly.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/meteor/app/emoji-native/lib/generateEmojiData.ts` around lines 97 - 101,
The mixed-tone skin key generation in generateEmojiData.ts collapses array-based
skin.tone values by using only the first element, so distinct mixed-tone
variants can overwrite each other. Update the tone key construction in the loop
over emojiData.skins to either encode the full tone tuple from skin.tone into
the key or explicitly skip mixed-tone entries, and keep the single-tone path
intact for the existing primaryShortcode-based keys.

Comment on lines 195 to 201
const firstAttachment = message.attachments?.length && message.attachments.shift();

if (firstAttachment) {
firstAttachment.description =
typeof firstAttachment.description === 'string' ? emojione.shortnameToUnicode(firstAttachment.description) : undefined;
firstAttachment.text = typeof firstAttachment.text === 'string' ? emojione.shortnameToUnicode(firstAttachment.text) : undefined;
typeof firstAttachment.description === 'string' ? shortnameToUnicode(firstAttachment.description) : undefined;
firstAttachment.text = typeof firstAttachment.text === 'string' ? shortnameToUnicode(firstAttachment.text) : undefined;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find callers of sendNotification to see if `message` is shared/cloned per receiver
rg -nP -C4 '\bsendNotification\s*\(' apps/meteor/app/lib/server

Repository: RocketChat/Rocket.Chat

Length of output: 1029


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the sendNotification implementation and its call chain
FILE=apps/meteor/app/lib/server/lib/sendNotificationsOnMessage.ts

# Show the relevant function signature and surrounding logic
rg -n -C6 'async function sendNotification|function sendNotification|const sendNotification' "$FILE"

# Show the receiver loop and any message construction above it
sed -n '300,410p' "$FILE"

# Look for whether the message object is cloned or recreated before the loop
rg -n -C3 '\bmessage\b.*(clone|structuredClone|Object\.assign|spread)|({\s*\.\.\.message|message\s*=\s*\{)' "$FILE"

Repository: RocketChat/Rocket.Chat

Length of output: 4108


🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE=apps/meteor/app/lib/server/lib/sendNotificationsOnMessage.ts

echo "== sendNotification definition =="
sed -n '1,260p' "$FILE" | nl -ba | sed -n '1,260p' | rg -n 'sendNotification|attachments|shift\(\)|shortnameToUnicode|message\.attachments'

echo
echo "== sendNotification call sites =="
rg -n -C3 '\bsendNotification\s*\(' apps/meteor/app/lib/server

echo
echo "== other attachment mutations in file =="
rg -n -C2 'attachments\.(shift|splice|pop|unshift|push)|message\.attachments' "$FILE"

Repository: RocketChat/Rocket.Chat

Length of output: 230


🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE=apps/meteor/app/lib/server/lib/sendNotificationsOnMessage.ts

echo "== sendNotification definition =="
sed -n '1,260p' "$FILE" | nl -ba | sed -n '1,260p' | rg -n 'sendNotification|attachments|shift\(\)|shortnameToUnicode|message\.attachments'

echo
echo "== sendNotification call sites =="
rg -n -C3 '\bsendNotification\s*\(' apps/meteor/app/lib/server

echo
echo "== other attachment mutations in file =="
rg -n -C2 'attachments\.(shift|splice|pop|unshift|push)|message\.attachments' "$FILE"

Repository: RocketChat/Rocket.Chat

Length of output: 230


🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE=apps/meteor/app/lib/server/lib/sendNotificationsOnMessage.ts

echo "== relevant sections =="
sed -n '1,260p' "$FILE" | python3 - <<'PY'
import sys
for i, line in enumerate(sys.stdin, 1):
    if 40 <= i <= 240:
        print(f"{i}:{line}", end="")
PY

echo
echo "== call sites =="
rg -n -C4 '\bsendNotification\s*\(' apps/meteor/app/lib/server

echo
echo "== attachment mutation searches =="
rg -n -C3 'attachments\.(shift|splice|pop|unshift|push)|message\.attachments' "$FILE"

Repository: RocketChat/Rocket.Chat

Length of output: 188


🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE=apps/meteor/app/lib/server/lib/sendNotificationsOnMessage.ts

python3 - <<'PY'
from pathlib import Path

path = Path("apps/meteor/app/lib/server/lib/sendNotificationsOnMessage.ts")
lines = path.read_text().splitlines()

def show(start, end, title):
    print(f"== {title} ==")
    for i in range(start, end + 1):
        if 1 <= i <= len(lines):
            print(f"{i}:{lines[i-1]}")

show(1, 260, "top section")
print()
show(330, 390, "subscription loop")
PY

Repository: RocketChat/Rocket.Chat

Length of output: 10130


Avoid mutating message.attachments here. sendNotification() runs per subscription with the same message object, so shift() removes the first attachment for later receivers. Use a non-mutating read/copy instead (message.attachments?.[0] plus slice(1)).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/meteor/app/lib/server/lib/sendNotificationsOnMessage.ts` around lines
195 - 201, Avoid mutating the shared attachments array in
sendNotificationsOnMessage when handling the first attachment. In
sendNotification(), replace the use of message.attachments.shift() with a
non-mutating read/copy so the same message object can be reused across
subscriptions without losing attachments; use the first-attachment handling
around firstAttachment and keep message.attachments unchanged for later
receivers.

Comment thread apps/meteor/client/views/composer/EmojiPicker/ToneSelector/ToneItem.tsx Outdated
Comment on lines +36 to +54
const renderEmojiToDataURL = (codePoints: string): string => {
const emoji = String.fromCodePoint(...codePoints.split('-').map((codePoint) => parseInt(codePoint, 16)));

const canvas = document.createElement('canvas');
canvas.width = EMOJI_RENDER_SIZE;
canvas.height = EMOJI_RENDER_SIZE;

const ctx = canvas.getContext('2d');
if (!ctx) {
return '';
}

ctx.textBaseline = 'middle';
ctx.textAlign = 'center';
ctx.font = `${Math.floor(EMOJI_RENDER_SIZE * 0.8)}px "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji", "Noto Emoji", sans-serif`;
ctx.fillText(emoji, EMOJI_RENDER_SIZE / 2, EMOJI_RENDER_SIZE / 2);

return canvas.toDataURL('image/png');
};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Guard against malformed codepoints in renderEmojiToDataURL.

String.fromCodePoint(...) throws RangeError for NaN/out-of-range values, and parseInt returns NaN for unexpected input. A single malformed codepoint string would throw inside react-pdf's emoji builder and could abort PDF generation. A small validity check keeps export resilient.

🛡️ Proposed guard
 const renderEmojiToDataURL = (codePoints: string): string => {
-	const emoji = String.fromCodePoint(...codePoints.split('-').map((codePoint) => parseInt(codePoint, 16)));
+	const points = codePoints.split('-').map((codePoint) => parseInt(codePoint, 16));
+	if (points.some((point) => Number.isNaN(point) || point < 0 || point > 0x10ffff)) {
+		return '';
+	}
+	const emoji = String.fromCodePoint(...points);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const renderEmojiToDataURL = (codePoints: string): string => {
const emoji = String.fromCodePoint(...codePoints.split('-').map((codePoint) => parseInt(codePoint, 16)));
const canvas = document.createElement('canvas');
canvas.width = EMOJI_RENDER_SIZE;
canvas.height = EMOJI_RENDER_SIZE;
const ctx = canvas.getContext('2d');
if (!ctx) {
return '';
}
ctx.textBaseline = 'middle';
ctx.textAlign = 'center';
ctx.font = `${Math.floor(EMOJI_RENDER_SIZE * 0.8)}px "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji", "Noto Emoji", sans-serif`;
ctx.fillText(emoji, EMOJI_RENDER_SIZE / 2, EMOJI_RENDER_SIZE / 2);
return canvas.toDataURL('image/png');
};
const renderEmojiToDataURL = (codePoints: string): string => {
const points = codePoints.split('-').map((codePoint) => parseInt(codePoint, 16));
if (points.some((point) => Number.isNaN(point) || point < 0 || point > 0x10ffff)) {
return '';
}
const emoji = String.fromCodePoint(...points);
const canvas = document.createElement('canvas');
canvas.width = EMOJI_RENDER_SIZE;
canvas.height = EMOJI_RENDER_SIZE;
const ctx = canvas.getContext('2d');
if (!ctx) {
return '';
}
ctx.textBaseline = 'middle';
ctx.textAlign = 'center';
ctx.font = `${Math.floor(EMOJI_RENDER_SIZE * 0.8)}px "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji", "Noto Emoji", sans-serif`;
ctx.fillText(emoji, EMOJI_RENDER_SIZE / 2, EMOJI_RENDER_SIZE / 2);
return canvas.toDataURL('image/png');
};
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@apps/meteor/client/views/room/contextualBar/ExportMessages/useExportMessagesAsPDFMutation.tsx`
around lines 36 - 54, `renderEmojiToDataURL` currently assumes every split code
point is valid, but `parseInt` can produce `NaN` and `String.fromCodePoint` will
throw on malformed input. Add a small validation step before building the emoji
string, and return an empty string early when any code point is invalid so the
PDF export path stays resilient. Use the `renderEmojiToDataURL` helper and its
`codePoints` parsing logic as the fix point.

Comment on lines +30 to +37
if (emoji.skins) {
for (const skin of emoji.skins) {
const skinCodes = getShortcodes(skin.hexcode);
if (skinCodes.length > 0) {
_unicodeToShort.set(skin.emoji, `:${skinCodes[0]}:`);
}
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
rg -nP 'tone[1-5]|skin' ee/packages/federation-matrix/src apps/meteor/app/emoji-native -C2

Repository: RocketChat/Rocket.Chat

Length of output: 50379


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== emojiConverter.ts ==\n'
wc -l ee/packages/federation-matrix/src/utils/emojiConverter.ts
cat -n ee/packages/federation-matrix/src/utils/emojiConverter.ts | sed -n '1,220p'

printf '\n== FederationMatrix.ts reaction references ==\n'
rg -n "sendReaction|removeReaction|shortnameToUnicode|unicodeToShort|getShortcodes|tone[1-5]|skin" ee/packages/federation-matrix/src/FederationMatrix.ts ee/packages/federation-matrix/src -C 2

printf '\n== emoji-native reaction shortcode formats ==\n'
rg -n "_tone[1-5]|skin_tone|tone[1-5]" apps/meteor/app/emoji-native -C 2 --max-count 80

Repository: RocketChat/Rocket.Chat

Length of output: 23864


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== emojiConverter.ts ==\n'
wc -l ee/packages/federation-matrix/src/utils/emojiConverter.ts
cat -n ee/packages/federation-matrix/src/utils/emojiConverter.ts | sed -n '1,220p'

printf '\n== FederationMatrix.ts reaction references ==\n'
rg -n "sendReaction|removeReaction|shortnameToUnicode|unicodeToShort|getShortcodes|tone[1-5]|skin" ee/packages/federation-matrix/src/FederationMatrix.ts ee/packages/federation-matrix/src -C 2

printf '\n== emoji-native reaction shortcode formats ==\n'
rg -n "_tone[1-5]|skin_tone|tone[1-5]" apps/meteor/app/emoji-native -C 2 --max-count 80

Repository: RocketChat/Rocket.Chat

Length of output: 23864


Add skin-tone entries to shortnameToUnicode. RC uses skin-tone shortnames like :<base>_toneN:, but this code only registers them in _unicodeToShort, so sendReaction/removeReaction can forward the raw shortcode to Matrix. Add every skinCodes entry to _shortToUnicode, not just the first one.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ee/packages/federation-matrix/src/utils/emojiConverter.ts` around lines 30 -
37, The emoji skin-tone mapping in emojiConverter is only populating
_unicodeToShort for each skin, so shortnames like :<base>_toneN: are not
recognized by shortnameToUnicode and can be forwarded raw; update the
emoji.skins handling in the converter to register every value from
getShortcodes(skin.hexcode) in _shortToUnicode, while keeping the existing
unicode-to-short mapping behavior intact.

@gabriellsh gabriellsh left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Emoji size in the composer autocomplete got smaller:

Before:
Image

After:
Image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

type: feature Pull requests that introduces new feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants