Skip to content

fix: resolve deep links by room id for channels and groups - #7111

Open
Rohit3523 wants to merge 24 commits into
developfrom
private-channel-deeplink-fail
Open

fix: resolve deep links by room id for channels and groups#7111
Rohit3523 wants to merge 24 commits into
developfrom
private-channel-deeplink-fail

Conversation

@Rohit3523

@Rohit3523 Rohit3523 commented Apr 7, 2026

Copy link
Copy Markdown
Member

Proposed changes

Deep links to a room sometimes carry a room id in the path segment instead of a room name (e.g. rocketchat://room?host=...&path=group/6997e23f362b278aeb3d369b).

The previous implementation passed that path segment straight to the REST groups.info / channels.info endpoint as roomName. Those endpoints only ever match a room name exactly, so whenever the link contained an id for a group, the lookup returned "not found" and the deep link failed to open the room.

This PR makes room resolution for both group and channel deep links use the getRoomByTypeAndName method, which resolves both a room name and a room id — with no code anymore tied to "name-only" REST params.

Issue(s)

https://rocketchat.atlassian.net/browse/CORE-1857

How to test or reproduce

  1. Open the app and log in.
  2. Deep link to a group using its name → the group opens.
  3. Deep link to the same group using its id in the path (path=group/<id>) → the group now opens (previously failed).
  4. Repeat for a channel using its name and its id in path=channel/<name|id> → the channel opens in both cases.

Screenshots

N/A — deep-link behavior change, no visual change.

Types of changes

  • Bugfix (non-breaking change which fixes an issue)

Checklist

  • I have read the CONTRIBUTING doc
  • I have signed the CLA
  • Lint and unit tests pass locally with my changes
  • I have added tests that prove my fix is effective or that my feature works (if applicable)
  • I have added necessary documentation (if applicable)
  • Any dependent changes have been merged and published in downstream modules

Further comments

The previous implementation used two different REST endpoints (channels.info for channels, groups.info for groups) with a roomName param, so it silently missed id-based links. We consolidated resolution on the DDP getRoomByTypeAndName, which the server supports for both c and p room types, matching here also used by the in-app Directory. A regression test was added and the e2e coverage was adjusted to fixed reusable fixtures (old group fixtures no longer exist on the QA server).

Summary by CodeRabbit

  • New Features

    • Improved channel and group deeplinks so links can open rooms by name or ID, even when a room ID is not included.
    • Added support for opening groups through the room-opening flow.
  • Bug Fixes

    • Improved handling of already-open rooms and invalid or unresolved deeplinks.
    • Preserved direct-message and explicit room-ID opening behavior.
  • Tests

    • Added coverage for channel and group deeplinks, successful openings, failures, and unsupported paths.
    • Added end-to-end checks for opening channels and groups by name and ID.

@coderabbitai

coderabbitai Bot commented Apr 7, 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
  • ✅ Review completed - (🔄 Check again to review again)

Walkthrough

canOpenRoom now resolves channel and group deeplinks through the shared room service. Groups open through the typed groups.open endpoint. Unit and Maestro tests cover name- and ID-based navigation, failures, and already-open groups.

Changes

Group deeplink behavior

Layer / File(s) Summary
Room resolution and opening
app/definitions/rest/v1/groups.ts, app/lib/methods/canOpenRoom.ts, app/lib/methods/canOpenRoom.test.ts
canOpenRoom resolves rooms by name or ID, opens groups with groups.open, returns unresolved failures as false, and preserves already-open handling. Unit tests cover these paths.
Deeplink test flow
.maestro/tests/assorted/channel-deeplink.yaml
The Maestro flow opens group and channel deeplinks by name and ID and verifies destination titles.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Deeplink
  participant canOpenRoom
  participant getRoomByTypeAndName
  participant groups.open
  Deeplink->>canOpenRoom: Provide channel or group path
  canOpenRoom->>getRoomByTypeAndName: Resolve room by name or ID
  getRoomByTypeAndName-->>canOpenRoom: Return resolved room
  canOpenRoom->>groups.open: Open group by room ID
  groups.open-->>canOpenRoom: Return success or already-open error
  canOpenRoom-->>Deeplink: Return resolved room or false
Loading
🚥 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
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.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main change: resolving channel and group deeplinks by room ID.

Warning

Review ran into problems

🔥 Problems

Errors were encountered while retrieving linked issues.

Errors (1)
  • CORE-1857: 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.

@Rohit3523
Rohit3523 had a problem deploying to experimental_ios_build April 7, 2026 22:42 — with GitHub Actions Error
@Rohit3523
Rohit3523 had a problem deploying to experimental_android_build April 7, 2026 22:42 — with GitHub Actions Error
@Rohit3523
Rohit3523 had a problem deploying to official_android_build April 7, 2026 22:42 — with GitHub Actions Error

@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.

🧹 Nitpick comments (2)
app/lib/methods/canOpenRoom.ts (2)

45-54: Potential redundant API call for GROUP type.

For ERoomTypes.GROUP without rid, the code now:

  1. Calls getRoomByTypeAndName('p', name) at line 32
  2. Then calls groups.info with { roomName: name } at line 48

This results in two API calls to fetch room information. Since you already have result._id from line 32, consider reusing that data or passing roomId to the info endpoint to avoid the redundant call.

♻️ Suggested approach
 		// if it's a group we need to check if you can open
 		if (type === ERoomTypes.GROUP) {
 			try {
 				const result = await getRoomByTypeAndName('p', name);
 				// RC 0.61.0
 				// `@ts-ignore`
 				await sdk.post(`${restTypes[type]}.open`, { roomId: result._id });
+				// Return room info directly since we already have it
+				if (!rid) {
+					return {
+						...result,
+						rid: result._id
+					};
+				}
 			} catch (e: any) {
 				if (!(e.data && /is already open/.test(e.data.error))) {
 					return false;
 				}
+				// Room is already open, still need to fetch info if no rid
 			}
 		}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/lib/methods/canOpenRoom.ts` around lines 45 - 54, The GROUP branch is
making a redundant API call: you already fetch the group via
getRoomByTypeAndName('p', name) (result._id) earlier, then call groups.info when
rid is missing; update canOpenRoom to reuse the previously obtained room object
or pass the roomId to the info endpoint instead of calling groups.info with
roomName—specifically, modify the logic around getRoomByTypeAndName and the
block handling ERoomTypes.GROUP so that if you have result._id (or a room
object), you set room.rid = result._id and return that room directly (or call
groups.info with { roomId: result._id } if more details are required),
eliminating the extra groups.info call.

36-40: Error handling may mask failures from getRoomByTypeAndName.

If getRoomByTypeAndName fails for reasons other than "room is already open" (e.g., room not found, network error), the code returns false at line 38. This is likely correct behavior, but the error condition at line 37 only checks for the "already open" case from sdk.post, not from getRoomByTypeAndName.

If getRoomByTypeAndName throws an error (e.g., room not found by name/ID), it will hit this catch block and return false. This may be intentional, but consider whether a more specific error should be propagated or logged for debugging deeplink failures.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/lib/methods/canOpenRoom.ts` around lines 36 - 40, The catch currently
around both getRoomByTypeAndName and sdk.post can swallow errors from
getRoomByTypeAndName; split the error handling so getRoomByTypeAndName failures
are not mistaken for the "already open" sdk.post case. Specifically, call
getRoomByTypeAndName (the function) in its own try/catch and either propagate or
log/return a distinct error for failures, then wrap only the sdk.post call in a
try/catch that checks e.data && /is already open/ to return false; rethrow or
surface other unexpected errors instead of returning false.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@app/lib/methods/canOpenRoom.ts`:
- Around line 45-54: The GROUP branch is making a redundant API call: you
already fetch the group via getRoomByTypeAndName('p', name) (result._id)
earlier, then call groups.info when rid is missing; update canOpenRoom to reuse
the previously obtained room object or pass the roomId to the info endpoint
instead of calling groups.info with roomName—specifically, modify the logic
around getRoomByTypeAndName and the block handling ERoomTypes.GROUP so that if
you have result._id (or a room object), you set room.rid = result._id and return
that room directly (or call groups.info with { roomId: result._id } if more
details are required), eliminating the extra groups.info call.
- Around line 36-40: The catch currently around both getRoomByTypeAndName and
sdk.post can swallow errors from getRoomByTypeAndName; split the error handling
so getRoomByTypeAndName failures are not mistaken for the "already open"
sdk.post case. Specifically, call getRoomByTypeAndName (the function) in its own
try/catch and either propagate or log/return a distinct error for failures, then
wrap only the sdk.post call in a try/catch that checks e.data && /is already
open/ to return false; rethrow or surface other unexpected errors instead of
returning false.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 43a644fe-331b-49fc-b446-7d4e57c30d05

📥 Commits

Reviewing files that changed from the base of the PR and between 87229ae and b0c8994.

📒 Files selected for processing (1)
  • app/lib/methods/canOpenRoom.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{js,jsx,ts,tsx,json}

📄 CodeRabbit inference engine (CLAUDE.md)

Configure Prettier with tabs, single quotes, 130 character width, no trailing commas, arrow parens avoid, and bracket same line

Files:

  • app/lib/methods/canOpenRoom.ts
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use ESLint with @rocket.chat/eslint-config base configuration including React, React Native, TypeScript, and Jest plugins

Files:

  • app/lib/methods/canOpenRoom.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use TypeScript with strict mode enabled and configure baseUrl to app/ for import resolution

**/*.{ts,tsx}: Use TypeScript for type safety; add explicit type annotations to function parameters and return types
Prefer interfaces over type aliases for defining object shapes in TypeScript
Use enums for sets of related constants rather than magic strings or numbers

Files:

  • app/lib/methods/canOpenRoom.ts
**/*.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{js,ts,jsx,tsx}: Use descriptive names for functions, variables, and classes that clearly convey their purpose
Write comments that explain the 'why' behind code decisions, not the 'what'
Keep functions small and focused on a single responsibility
Use const by default, let when reassignment is needed, and avoid var
Prefer async/await over .then() chains for handling asynchronous operations
Use explicit error handling with try/catch blocks for async operations
Avoid deeply nested code; refactor complex logic into helper functions

Files:

  • app/lib/methods/canOpenRoom.ts
🧠 Learnings (1)
📚 Learning: 2026-04-07T17:49:17.519Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat.ReactNative PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-07T17:49:17.519Z
Learning: Applies to app/lib/database/model/**/*.{ts,tsx} : Place database models in app/lib/database/model/ for entities like Message, Room, Subscription, User, Thread, Upload, Server, CustomEmoji, Permission, and Role

Applied to files:

  • app/lib/methods/canOpenRoom.ts
🔇 Additional comments (1)
app/lib/methods/canOpenRoom.ts (1)

30-41: The fix may not fully address the PR objective when name is actually a group ID.

According to the PR objectives, the deeplink can contain either a group name or a group ID. The current implementation still passes name directly to getRoomByTypeAndName('p', name). If name is actually an ID (not a room name), this call might fail depending on how the API handles the parameter.

Additionally, the magic string 'p' for the room type could benefit from a brief comment or constant.

[raise_major_issue, request_verification]

#!/bin/bash
# Description: Check how getRoomByTypeAndName is implemented and whether it can accept both IDs and names

# Find the implementation of getRoomByTypeAndName
ast-grep --pattern 'export function getRoomByTypeAndName($$$) { $$$ }'

# Also search for its definition in restApi
rg -n -A 20 'getRoomByTypeAndName' --type ts

@Rohit3523
Rohit3523 had a problem deploying to experimental_android_build April 23, 2026 21:53 — with GitHub Actions Error
@Rohit3523
Rohit3523 had a problem deploying to official_android_build April 23, 2026 21:53 — with GitHub Actions Error
@Rohit3523
Rohit3523 had a problem deploying to experimental_ios_build April 23, 2026 21:53 — with GitHub Actions Error
@Rohit3523
Rohit3523 had a problem deploying to official_android_build April 25, 2026 21:34 — with GitHub Actions Error
@Rohit3523
Rohit3523 had a problem deploying to experimental_android_build April 25, 2026 21:34 — with GitHub Actions Error
@Rohit3523
Rohit3523 had a problem deploying to experimental_ios_build April 25, 2026 21:34 — with GitHub Actions Error

@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: 4

Caution

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

⚠️ Outside diff range comments (2)
app/lib/methods/canOpenRoom.ts (2)

51-60: ⚠️ Potential issue | 🟡 Minor

Narrowing the fallback to CHANNEL is fine, but couple it with the regression fix above.

Removing ERoomTypes.GROUP from this fallback is reasonable now that GROUP has its own dedicated block, but it amplifies the “is already open” regression flagged at lines 30–47: there is no longer a safety net that calls groups.info for GROUP. Once the GROUP block is fixed to always return the resolved room, this narrowing is consistent.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/lib/methods/canOpenRoom.ts` around lines 51 - 60, The narrowing of the
fallback to ERoomTypes.CHANNEL removed the safety-net for GROUP; update
canOpenRoom.ts so the GROUP path mirrors the CHANNEL fallback: when type ===
ERoomTypes.GROUP and no rid, call sdk.get(`${restTypes[type]}.info`, params)
(same as the CHANNEL block), extract the room from result[type], set room.rid =
room._id and return the room; also ensure the primary GROUP handling block (the
earlier regression) always returns the resolved room object so the new fallback
is consistent with the fixed GROUP logic.

30-47: ⚠️ Potential issue | 🔴 Critical

Regression: room data is lost when group is already open.

When sdk.post('groups.open', …) throws the “is already open” error, control jumps to the catch block where response (declared with const inside the try) is out of scope, so the fetched room cannot be returned. Execution then falls through to the lines below — and because the CHANNEL-only fallback at line 51 no longer covers GROUP, open() ends up returning false, leaving the user on the room list. Previously, the ${restTypes[type]}.info fallback handled this case for groups.

🐛 Suggested fix — return the resolved room even when the open call reports it was already open
 		// if it's a group we need to check if you can open
 		if (type === ERoomTypes.GROUP) {
+			let response;
 			try {
-				const response = await getRoomByTypeAndName('p', name);
+				response = await getRoomByTypeAndName('p', name);
 				// RC 0.61.0
 				// `@ts-ignore`
 				await sdk.post('groups.open', { roomId: response._id });
-
-				return {
-					...response,
-					rid: response._id
-				};
 			} catch (e: any) {
-				console.log('e', e);
 				if (!(e.data && /is already open/.test(e.data.error))) {
 					return false;
 				}
 			}
+			if (response) {
+				return {
+					...response,
+					rid: response._id
+				};
+			}
 		}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/lib/methods/canOpenRoom.ts` around lines 30 - 47, Regression: when
sdk.post('groups.open', ...) throws the "is already open" error the const
response is out of scope in the catch, so the room data is lost and false is
returned. Fix by hoisting response (declare let response outside the try),
assign it via getRoomByTypeAndName(...) inside the try, and in the catch detect
the "is already open" case (e.data && /is already open/.test(e.data.error)) and
return the resolved room (e.g., return { ...response, rid: response._id }); also
remove/replace the debugging console.log; referenced symbols:
getRoomByTypeAndName, sdk.post('groups.open'), response, and the catch block in
canOpenRoom.ts.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.maestro/tests/assorted/group-deeplink.yaml:
- Around line 21-23: The test uses a flat selector for the extendedWaitUntil
step—change the visible selector from the string form to the nested testID form
used elsewhere: replace extendedWaitUntil.visible: 'discussion-with-name' with a
nested object using id: 'discussion-with-name' (i.e., extendedWaitUntil.visible
-> id) for both occurrences; update the same pattern for any other
extendedWaitUntil.visible entries to maintain consistency with the project's
testID matching convention and ensure the selector uses visible: { id:
'discussion-with-name' } under the extendedWaitUntil block.
- Around line 15-30: Fix the duplicated comment and ensure the first test
exercises name resolution: change the second block's comment from "# open group
using name" to "# open group using id" to match the assertion expecting
'discussion-with-id', and verify the first deeplink env.link value ('link:
'https://go.rocket.chat/room?host=mobile.qa.rocket.chat&path=group/4t6Mw3K4M9JLeHuCH'')
is a human-readable room name used for name-resolution; if that token is
actually a Meteor-style room ID, replace it with a real human-readable group
slug (e.g., 'private-deeplink-test') so the runFlow (file 'open-deeplink.yaml')
plus the 'discussion-with-name' assertion exercises the name resolution path
while the second block plus 'discussion-with-id' exercises the ID path.

In `@app/lib/methods/canOpenRoom.ts`:
- Line 42: In canOpenRoom.ts inside the canOpenRoom function remove the debug
console.log('e', e) statement; instead either propagate the error or log it via
the module's standard logger (do not leave a raw console.log). Locate the catch
block referencing the variable e, delete the console.log line and replace with a
call to the existing logging/error handling utility used in this module (or
rethrow e) so production logs won't be spammed or leak error payloads.
- Around line 30-40: The code in canOpenRoom (inside the ERoomTypes.GROUP
branch) uses response._id without validating that getRoomByTypeAndName returned
a value; update the logic in that block (the call to getRoomByTypeAndName and
subsequent sdk.post('groups.open', { roomId: response._id })) to explicitly
check that response and response._id exist (e.g., if (!response?._id) return
false) before calling sdk.post and before returning the room object, and keep
the existing try/catch for sdk.post errors so only post-call errors are handled
there; ensure you reference getRoomByTypeAndName and sdk.post('groups.open')
when making the change.

---

Outside diff comments:
In `@app/lib/methods/canOpenRoom.ts`:
- Around line 51-60: The narrowing of the fallback to ERoomTypes.CHANNEL removed
the safety-net for GROUP; update canOpenRoom.ts so the GROUP path mirrors the
CHANNEL fallback: when type === ERoomTypes.GROUP and no rid, call
sdk.get(`${restTypes[type]}.info`, params) (same as the CHANNEL block), extract
the room from result[type], set room.rid = room._id and return the room; also
ensure the primary GROUP handling block (the earlier regression) always returns
the resolved room object so the new fallback is consistent with the fixed GROUP
logic.
- Around line 30-47: Regression: when sdk.post('groups.open', ...) throws the
"is already open" error the const response is out of scope in the catch, so the
room data is lost and false is returned. Fix by hoisting response (declare let
response outside the try), assign it via getRoomByTypeAndName(...) inside the
try, and in the catch detect the "is already open" case (e.data && /is already
open/.test(e.data.error)) and return the resolved room (e.g., return {
...response, rid: response._id }); also remove/replace the debugging
console.log; referenced symbols: getRoomByTypeAndName, sdk.post('groups.open'),
response, and the catch block in canOpenRoom.ts.
🪄 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: 8a2b3530-2a29-47ee-b688-5b7ad497d1c4

📥 Commits

Reviewing files that changed from the base of the PR and between b0c8994 and 97fc070.

📒 Files selected for processing (2)
  • .maestro/tests/assorted/group-deeplink.yaml
  • app/lib/methods/canOpenRoom.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: ESLint and Test / run-eslint-and-test
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{js,ts,jsx,tsx}: Use descriptive names for functions, variables, and classes that clearly convey their purpose
Write comments that explain the 'why' behind code decisions, not the 'what'
Keep functions small and focused on a single responsibility
Use const by default, let when reassignment is needed, and avoid var
Prefer async/await over .then() chains for handling asynchronous operations
Use explicit error handling with try/catch blocks for async operations
Avoid deeply nested code; refactor complex logic into helper functions

Files:

  • app/lib/methods/canOpenRoom.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Use TypeScript for type safety; add explicit type annotations to function parameters and return types
Prefer interfaces over type aliases for defining object shapes in TypeScript
Use enums for sets of related constants rather than magic strings or numbers

**/*.{ts,tsx}: Use TypeScript with strict mode enabled and baseUrl set to app/ for module imports
Support iOS 13.4+ and Android 6.0+ as minimum target platforms

Files:

  • app/lib/methods/canOpenRoom.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx,js,jsx}: Use tabs for indentation with single quotes, 130 character line width, no trailing commas, and avoid arrow function parentheses when possible
Use ESLint with @rocket.chat/eslint-config base including React, React Native, TypeScript, and Jest plugins

Files:

  • app/lib/methods/canOpenRoom.ts
🧠 Learnings (2)
📚 Learning: 2026-03-05T14:28:10.004Z
Learnt from: Rohit3523
Repo: RocketChat/Rocket.Chat.ReactNative PR: 6997
File: .maestro/tests/room/message-markdown-click.yaml:28-39
Timestamp: 2026-03-05T14:28:10.004Z
Learning: In Maestro YAML selector fields (text, id) within the Rocket.Chat React Native repository, use the contains pattern '.*keyword.*' (leading and trailing '.*') for matching text. The pattern '.*keyword*.' is incorrect and will fail to match cases where the keyword appears at the end of the element's text. This guideline applies to all Maestro YAML selector fields across the codebase.

Applied to files:

  • .maestro/tests/assorted/group-deeplink.yaml
📚 Learning: 2026-04-22T22:57:58.545Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat.ReactNative PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-22T22:57:58.545Z
Learning: Applies to app/lib/database/model/**/*.{ts,tsx} : Define WatermelonDB models in app/lib/database/model/ directory for Message, Room, Subscription, User, Thread, Upload, Server, CustomEmoji, Permission, Role, etc.

Applied to files:

  • app/lib/methods/canOpenRoom.ts
🔇 Additional comments (1)
.maestro/tests/assorted/group-deeplink.yaml (1)

9-13: Verify that open-deeplink.yaml properly launches the app from cold-start after killApp.

The pattern you identified is correct: login-with-deeplink.yaml runs once for the suite, then each scenario does killApp followed by open-deeplink.yaml. However, open-deeplink.yaml uses only openLink: ${link} without explicit app restart logic—confirm that this properly relaunches the app with the deeplink (rather than assuming a warm session). If the auth tokens don't persist through the kill-restart cycle or the deeplink handler doesn't activate on cold-start, the second scenario could silently fail to reach an authenticated state, and the 60000ms wait would mask the race condition. Local testing with the app fully killed is necessary to validate.

Comment thread .maestro/tests/assorted/group-deeplink.yaml Outdated
Comment thread .maestro/tests/assorted/group-deeplink.yaml Outdated
Comment thread app/lib/methods/canOpenRoom.ts Outdated
Comment thread app/lib/methods/canOpenRoom.ts Outdated
@Rohit3523
Rohit3523 marked this pull request as ready for review August 6, 2026 15:26
@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@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.

🧹 Nitpick comments (1)
app/lib/methods/canOpenRoom.test.ts (1)

26-35: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚖️ Poor tradeoff

Add explicit return types to the new async test callbacks.

Use Promise<void> for each added async it callback. Apply the same rule to the other added callback functions where applicable.

Proposed change
-	it('returns room when getRoomByTypeAndName succeeds and groups.open succeeds', async () => {
+	it('returns room when getRoomByTypeAndName succeeds and groups.open succeeds', async (): Promise<void> => {

As per coding guidelines, “add explicit type annotations to function parameters and return types.”

🤖 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 `@app/lib/methods/canOpenRoom.test.ts` around lines 26 - 35, Add an explicit
Promise<void> return type to the async callback in the canOpenRoom test case,
and apply the same annotation to every other newly added async it/test callback
in this diff. Keep the test behavior and assertions unchanged.

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.

Nitpick comments:
In `@app/lib/methods/canOpenRoom.test.ts`:
- Around line 26-35: Add an explicit Promise<void> return type to the async
callback in the canOpenRoom test case, and apply the same annotation to every
other newly added async it/test callback in this diff. Keep the test behavior
and assertions unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 5df86ac2-5784-493b-9aae-220d7917cf72

📥 Commits

Reviewing files that changed from the base of the PR and between 41e87a8 and 2d1a8f0.

📒 Files selected for processing (4)
  • .maestro/tests/assorted/group-deeplink.yaml
  • app/definitions/rest/v1/groups.ts
  • app/lib/methods/canOpenRoom.test.ts
  • app/lib/methods/canOpenRoom.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • .maestro/tests/assorted/group-deeplink.yaml
📜 Review details
⏰ Context from checks skipped due to timeout. (3)
  • GitHub Check: ESLint and Test / run-eslint-and-test
  • GitHub Check: E2E Shard Preflight
  • GitHub Check: format
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{js,ts,jsx,tsx}: Use descriptive names for functions, variables, and classes that clearly convey their purpose
Write comments that explain the 'why' behind code decisions, not the 'what'
Keep functions small and focused on a single responsibility
Use const by default, let when reassignment is needed, and avoid var
Prefer async/await over .then() chains for handling asynchronous operations
Use explicit error handling with try/catch blocks for async operations
Avoid deeply nested code; refactor complex logic into helper functions

Files:

  • app/definitions/rest/v1/groups.ts
  • app/lib/methods/canOpenRoom.ts
  • app/lib/methods/canOpenRoom.test.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Use TypeScript for type safety; add explicit type annotations to function parameters and return types
Prefer interfaces over type aliases for defining object shapes in TypeScript
Use enums for sets of related constants rather than magic strings or numbers

Files:

  • app/definitions/rest/v1/groups.ts
  • app/lib/methods/canOpenRoom.ts
  • app/lib/methods/canOpenRoom.test.ts
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{js,jsx,ts,tsx}: Format JavaScript and TypeScript code with Oxfmt using the repository configuration: tabs, single quotes, 130-character width, no trailing commas, omitted arrow-function parentheses where possible, and same-line brackets.
Follow Oxlint rules configured in .oxlintrc.json, including the import, React, Jest, TypeScript, and React Native plugins.

Files:

  • app/definitions/rest/v1/groups.ts
  • app/lib/methods/canOpenRoom.ts
  • app/lib/methods/canOpenRoom.test.ts
🧠 Learnings (2)
📚 Learning: 2026-04-30T17:07:51.020Z
Learnt from: diegolmello
Repo: RocketChat/Rocket.Chat.ReactNative PR: 7274
File: app/lib/services/voip/MediaCallEvents.ts:0-0
Timestamp: 2026-04-30T17:07:51.020Z
Learning: In this Rocket.Chat React Native codebase, the ESLint rule `no-void: error` is enforced. When you see a promise returned from an async call that is not awaited (a “floating promise”), do not silence it with the `void somePromise()` pattern. Instead, handle the promise explicitly by attaching `.catch(...)` (or otherwise awaiting/handling the error) so unhandled-rejection risks are addressed in a way that satisfies the existing ESLint configuration.

Applied to files:

  • app/definitions/rest/v1/groups.ts
  • app/lib/methods/canOpenRoom.ts
  • app/lib/methods/canOpenRoom.test.ts
📚 Learning: 2026-06-25T18:37:25.526Z
Learnt from: diegolmello
Repo: RocketChat/Rocket.Chat.ReactNative PR: 7434
File: app/views/ScreenLockConfigView.test.tsx:16-22
Timestamp: 2026-06-25T18:37:25.526Z
Learning: In Rocket.Chat ReactNative tests that mock selectors for `useAppSelector`, don’t require the mocked selector input to be typed as `IApplicationState` when the fixture only includes a partial Redux state slice (e.g., only `server` and `settings`). Requiring the full `IApplicationState` type in that scenario forces unsafe `as IApplicationState` casts and undermines type-safety. For these narrowly scoped selector-mock fixtures, use a less strict type (e.g., `any`) to keep the mock focused on the slice under test.

Applied to files:

  • app/lib/methods/canOpenRoom.test.ts
🔇 Additional comments (2)
app/definitions/rest/v1/groups.ts (1)

93-97: LGTM!

app/lib/methods/canOpenRoom.ts (1)

5-5: LGTM!

Also applies to: 22-48

@Rohit3523 Rohit3523 changed the title fix: deeplinking fails to open group when group id is provided in link fix: resolve deep links by room id for channels and groups Aug 6, 2026
@Rohit3523

Copy link
Copy Markdown
Member Author

🧹 Nitpick comments (1)

app/lib/methods/canOpenRoom.test.ts (1)> 26-35: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚖️ Poor tradeoff

Add explicit return types to the new async test callbacks.
Use Promise<void> for each added async it callback. Apply the same rule to the other added callback functions where applicable.

Proposed change

-	it('returns room when getRoomByTypeAndName succeeds and groups.open succeeds', async () => {
+	it('returns room when getRoomByTypeAndName succeeds and groups.open succeeds', async (): Promise<void> => {

As per coding guidelines, “add explicit type annotations to function parameters and return types.”

🤖 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 `@app/lib/methods/canOpenRoom.test.ts` around lines 26 - 35, Add an explicit
Promise<void> return type to the async callback in the canOpenRoom test case,
and apply the same annotation to every other newly added async it/test callback
in this diff. Keep the test behavior and assertions unchanged.

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.

Nitpick comments:
In `@app/lib/methods/canOpenRoom.test.ts`:
- Around line 26-35: Add an explicit Promise<void> return type to the async
callback in the canOpenRoom test case, and apply the same annotation to every
other newly added async it/test callback in this diff. Keep the test behavior
and assertions unchanged.

ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 5df86ac2-5784-493b-9aae-220d7917cf72

📥 Commits
Reviewing files that changed from the base of the PR and between 41e87a8 and 2d1a8f0.

📒 Files selected for processing (4)

  • .maestro/tests/assorted/group-deeplink.yaml
  • app/definitions/rest/v1/groups.ts
  • app/lib/methods/canOpenRoom.test.ts
  • app/lib/methods/canOpenRoom.ts

🚧 Files skipped from review as they are similar to previous changes (1)

  • .maestro/tests/assorted/group-deeplink.yaml

📜 Review details

Adding Promise to every it() callback in canOpenRoom.test.ts would deviate from the surrounding test suite and add noise with no lint backing.

@OtavioStasiak OtavioStasiak 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.

lint is failing after update with develop...
Fix it and run e2e tests, all tests must pass.


# open group using name
- killApp
- runFlow:

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.

The flow hardcodes four things that data-setup.js never creates: the room names discussion-with-name / discussion-with-id and the ids 6a74cb92d09f52225dd8f0af / 8Lhm98suz3bGKMuK2. They only resolve because someone created them by
hand on mobile.qa.rocket.chat — the group id is a 24-char Mongo ObjectId while RC room ids are 17-char randoms (8Lhm98suz3bGKMuK2), which gives it away. When that server is reset or those rooms are renamed, this flow fails and the
failure will read as a product regression in deeplinking rather than missing test data.

data-setup.js already exposes exactly what this needs — createRandomRoom(username, password, type) returns { _id, name } — so both the name case and the id case can provision themselves, following the pattern in
tests/room/discussion.yaml:

onFlowStart:
- runFlow: '../../helpers/setup.yaml'
onFlowComplete:
- evalScript: ${output.utils.deleteCreatedUsers()}

  • evalScript: ${output.user = output.utils.createUser()}
  • evalScript: ${output.group = output.utils.createRandomRoom(output.user.username, output.user.password, 'p')}
  • evalScript: ${output.channel = output.utils.createRandomRoom(output.user.username, output.user.password, 'c')}

then path=group/${output.group.name} and path=group/${output.group._id}, asserting room-view-title-${output.group.name} in both cases. Same for the channel. That also drops the dependency on the shared admin account, which the four
killApp + deeplink steps currently mutate state for.

Two cases that are closer to the bug this PR fixes and aren't covered:

  1. A private group with a closed subscription. All four rooms are already open for the admin, so groups.open in canOpenRoom never actually does anything here — the one branch the fix reorders (resolve room → then open, instead of
    open → then fetch info) is untested end-to-end. output.utils.post('rooms.hide', user, pass, { roomId }) before the deeplink makes it real.
  2. A public channel the user is not a member of — the new code resolves it via canAccessRoomAsync rather than channels.info + view-c-room, and that's a genuine behavior difference worth pinning.

Non-blocking, but (1) is the one I'd push for, since it's the branch the fix actually restructures.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants