Skip to content

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

Merged
Rohit3523 merged 32 commits into
developfrom
private-channel-deeplink-fail
Aug 21, 2026
Merged

fix: resolve deep links by room id for channels and groups#7111
Rohit3523 merged 32 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

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

Comment thread .maestro/tests/assorted/channel-deeplink.yaml
Comment thread app/lib/methods/canOpenRoom.ts

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

LGTM

@Rohit3523
Rohit3523 merged commit 293e082 into develop Aug 21, 2026
73 of 85 checks passed
@Rohit3523
Rohit3523 deleted the private-channel-deeplink-fail branch August 21, 2026 01:19
diegolmello added a commit that referenced this pull request Aug 31, 2026
* fix: render mentions, emojis, and inline elements inside headings (#6911)

* chore: OXC (#7515)

* chore: replace ESLint with Oxlint

Migrate linting from ESLint 8 to Oxlint. `pnpm lint` drops from ~1min to
~0.6s and 17 eslint packages are removed from devDependencies.

Config lives in `.oxlintrc.json`, generated with `@oxlint/migrate` from the
old `.eslintrc.js` and then tuned:

- `eslint-plugin-react-native` is loaded through `jsPlugins`, since Oxlint has
  no built-in equivalent.
- `import/extensions` is off. Its old options (`js: 'warning'`, ...) were not
  valid values for the rule, so it never reported anything under ESLint.
- `no-unused-vars` sets `caughtErrors: 'none'` to match the ESLint 8 default.
- `import/no-cycle` and the React Compiler rules report as warnings. They
  surface findings ESLint never showed, so they are not gated yet.

Rules with no Oxlint equivalent are dropped: `no-restricted-syntax` (the ban
on `React.*` member syntax), `import/order`, `import/no-unresolved` and
`import/named`.

ESLint 8 skipped dot-directories, so files under `.rnstorybook/` and
`.maestro/` were never linted. Oxlint does lint them, which surfaced four
violations that are fixed here.

The CI workflow keeps its filename and job id so branch protection checks
stay valid.

* chore: replace Prettier with Oxfmt

Migrate formatting from Prettier 2.8.8 to Oxfmt via `oxfmt --migrate prettier`.

- `.oxfmtrc.json` carries every previous Prettier option unchanged (tabs,
  single quotes, printWidth 130, no trailing comma, avoid arrow parens,
  bracketSameLine) plus the `.prettierignore` patterns as `ignorePatterns`.
  `sortPackageJson` is disabled to match previous behavior.
- `.prettierrc.js` and `.prettierignore` removed; `prettier` dropped from
  devDependencies.
- `prettier-lint` script renamed to `format-lint` and now runs `oxfmt`.
- 44 files reformatted: Oxfmt follows Prettier 3 style, so nested ternaries
  and `extends`/type-argument wrapping indent differently than under
  Prettier 2. No semantic changes.
- prettier.yml still ran `eslint --fix`, missed in the Oxlint migration; it
  now runs `oxfmt` and `oxlint --fix`. `react/exhaustive-deps` is allowed
  there because its autofix rewrites dependency arrays, which changes
  behavior and must not land unreviewed from CI.
- Workflow filename kept as prettier.yml to avoid disturbing branch
  protection checks, same as eslint.yml.

Verified: `pnpm lint` exit 0 (0 errors), `tsc` clean, 217/217 suites and
2032/2032 tests pass, `oxfmt --check` clean.

* chore: update lockfile for oxfmt

* chore: migrate typecheck to TypeScript 7.0 (#7516)

* chore: bump TypeScript to 6.0

Baseline hop ahead of the TypeScript 7.0 (native compiler) migration, so the
7.0 cut is a version swap against a config that is already 7.0-shaped.

TypeScript 6.0 raises both `moduleResolution: node10` and `baseUrl` as errors
rather than warnings, and `ignoreDeprecations: "6.0"` stops working in 7.0, so
clearing them properly is the only route:

- `moduleResolution` -> `bundler` (Metro is a bundler), which requires an
  esnext-shaped `module`.
- `baseUrl` removed. Exactly one import relied on it; it is now relative.
- `types` enumerated, since a resolution mode that honours package `exports`
  no longer auto-includes every `@types` package. `@types/node` becomes an
  explicit devDependency.

Honouring `exports` also stranded the bundled `.d.ts` of three dependencies
whose maps expose only JavaScript. Each gets a `types` condition via
patch-package; this is visible to the type checker only, as Metro ignores that
condition. A `paths` mapping was tried first and rejected, because the
jest-expo resolver reads `paths` and then loads those `.d.ts` files at runtime.

The inherited block of commented-out option documentation is dropped.

* chore: migrate typecheck to TypeScript 7.0

Replaces TypeScript 6.0.3 with the native Go compiler. The version is pinned
exactly, since the platform binaries ship as version-matched optional
dependencies; the lockfile records the linux-x64 target CI resolves.

Typecheck wall time drops from 5.77s on 5.9.3 to ~1.0s. No configuration
change was required: the 6.0 hop already left tsconfig in a 7.0-shaped state,
and the default parallelism saturates without `--checkers`.

`@react-navigation/core` needs a patch to type-check. TypeScript 7.0.2
resolves the mutual recursion between `StaticParamList` and
`ParamListForScreens` eagerly where earlier versions defer it, reports the
alias as circular, and degrades it to a non-generic symbol -- surfacing as
`TS2315: Type 'StaticParamList' is not generic` at our call sites. The patch
drops a `FlatType<>` wrapper from the alias, which only flattens intersections
for editor display, so the type is unchanged and the misfire stops.

* chore: Bump version to 4.76.0 (#7542)

* chore(ci): apply least privilege permission to GitHub Actions (#7350)

* chore: switch React Compiler to infer mode (#7545)

* ci: route Maestro e2e selection through sniffler impact analysis (#7476)

* fix(iOS): RoomItem Swipe not working after scroll (#7532)

* fix(ci): select shards for changes outside app and honor the release label (#7555)

* fix: delete background taller than its row on ServersHistory (#7536)

* fix: delete background taller than its row on server items

* chore: code improvements

---------

Co-authored-by: Diego Mello <diegolmello@gmail.com>

* fix: UIKit block messages rendering with smaller font size (#7531)

* fix: UIKit block messages rendering with smaller font size

* fix: snapshot

* fix(db): move deleteMessage finds and prepares inside the writer lock (#7550)

* fix: quote has no effect on older thread messages (#7535)

* fix: Quote has no effect on older thread messages

* fix: Quote has no effect on older thread messages

* chore: e2e test

* fix: e2e test

* chore: format code and fix lint issues

* fix(MessageComposer): resolve quoted thread messages and guard stale lookups

* fix: test

---------

Co-authored-by: OtavioStasiak <OtavioStasiak@users.noreply.github.com>

* fix(db): move persistMessage lookups and prepares inside the writer lock (#7551)

* fix:  test case 11 and 12 flaky tests (#7564)

* fix: test

* fix: room last messa test

* fix: jumptomessage test

* chore: remove comments

* fix: jump to message e2e test iOS

* remove unused comment

* fix(db): move sendMessage reads and prepares inside the writer lock (#7546)

* fix(db): move sendMessage reads and prepares inside the writer lock

* fix: test improvements

* chore: remove comments

* fix: Admin Panel content hidden behind bottom navigation bar (#7538)

* feat: add tabular numbers (#7568)

* feat: tabular numbers across the app, upgrade Inter to 4.1

* update snapshot

* chore: pin @rocket.chat/sdk to a specific commit hash (#7569)

* fix(e2ee): re-fetch subscription inside the write in toggleRoomE2EE (#7554)

* fix(e2ee): re-fetch subscription inside the write in toggleRoomE2EE

* code improvements

* removed unused comment

* fix: run handleDelete finds and prepares inside the writer lock (#7552)

* fix: run handleDelete finds and prepares inside the writer lock

* chore: reuse mockWMDB

* fix: crop screen hidden behind navigation bar on iOS 26 (#7529)

* fix: re-fetch message inside the write in getThreadName (#7557)

* fix: re-fetch message inside the write in getThreadName

* fix: re-fetch message inside the write in getThreadName

* chore: new test cases

* remove unecessary async

* fix(db): move decryptPendingMessages prepares inside the writer lock (#7548)

* fix(db): move decryptPendingMessages prepares inside the writer lock

* code improvements

* chore: new test case encryption

* chore: format code and fix lint issues

---------

Co-authored-by: OtavioStasiak <OtavioStasiak@users.noreply.github.com>

* fix(android): VideoConf notification accept and decline button hidden and touch not working (#7533)

* fix: in-app notification buttons ignoring taps on Android

* fix: Decline and Accept invisible on the incoming call notification

* fix: UIKit buttons not responding on some Android devices (#7573)

* fix: force Google account chooser on OAuth login (#7572)

* fix: ISO format support in markdown component (#6943)

* fix: resolve deep links by room id for channels and groups (#7111)

* Merge pull request #7570 from RocketChat/deeplink-saml-auth

feat: SAML deeplink auth

* fix: grant pull-requests write to build call sites in build-develop (#7599)

The reusable workflows build-android.yml and build-ios.yml declare
pull-requests: write on their upload jobs. GitHub validates these at
call time regardless of job conditionals, so build-develop.yml
(caller) must grant the permission or the workflow fails validation.
build-pr.yml already grants it; this mirrors that.

---------

Co-authored-by: Rohit Bansal <40559587+Rohit3523@users.noreply.github.com>
Co-authored-by: Yasmim Nagat <117310290+yasnagat@users.noreply.github.com>
Co-authored-by: Otávio Stasiak <91474186+OtavioStasiak@users.noreply.github.com>
Co-authored-by: OtavioStasiak <OtavioStasiak@users.noreply.github.com>
Co-authored-by: Yash Rajpal <58601732+yash-rajpal@users.noreply.github.com>
diegolmello added a commit that referenced this pull request Aug 31, 2026
* fix: render mentions, emojis, and inline elements inside headings (#6911)

* chore: OXC (#7515)

* chore: replace ESLint with Oxlint

Migrate linting from ESLint 8 to Oxlint. `pnpm lint` drops from ~1min to
~0.6s and 17 eslint packages are removed from devDependencies.

Config lives in `.oxlintrc.json`, generated with `@oxlint/migrate` from the
old `.eslintrc.js` and then tuned:

- `eslint-plugin-react-native` is loaded through `jsPlugins`, since Oxlint has
  no built-in equivalent.
- `import/extensions` is off. Its old options (`js: 'warning'`, ...) were not
  valid values for the rule, so it never reported anything under ESLint.
- `no-unused-vars` sets `caughtErrors: 'none'` to match the ESLint 8 default.
- `import/no-cycle` and the React Compiler rules report as warnings. They
  surface findings ESLint never showed, so they are not gated yet.

Rules with no Oxlint equivalent are dropped: `no-restricted-syntax` (the ban
on `React.*` member syntax), `import/order`, `import/no-unresolved` and
`import/named`.

ESLint 8 skipped dot-directories, so files under `.rnstorybook/` and
`.maestro/` were never linted. Oxlint does lint them, which surfaced four
violations that are fixed here.

The CI workflow keeps its filename and job id so branch protection checks
stay valid.

* chore: replace Prettier with Oxfmt

Migrate formatting from Prettier 2.8.8 to Oxfmt via `oxfmt --migrate prettier`.

- `.oxfmtrc.json` carries every previous Prettier option unchanged (tabs,
  single quotes, printWidth 130, no trailing comma, avoid arrow parens,
  bracketSameLine) plus the `.prettierignore` patterns as `ignorePatterns`.
  `sortPackageJson` is disabled to match previous behavior.
- `.prettierrc.js` and `.prettierignore` removed; `prettier` dropped from
  devDependencies.
- `prettier-lint` script renamed to `format-lint` and now runs `oxfmt`.
- 44 files reformatted: Oxfmt follows Prettier 3 style, so nested ternaries
  and `extends`/type-argument wrapping indent differently than under
  Prettier 2. No semantic changes.
- prettier.yml still ran `eslint --fix`, missed in the Oxlint migration; it
  now runs `oxfmt` and `oxlint --fix`. `react/exhaustive-deps` is allowed
  there because its autofix rewrites dependency arrays, which changes
  behavior and must not land unreviewed from CI.
- Workflow filename kept as prettier.yml to avoid disturbing branch
  protection checks, same as eslint.yml.

Verified: `pnpm lint` exit 0 (0 errors), `tsc` clean, 217/217 suites and
2032/2032 tests pass, `oxfmt --check` clean.

* chore: update lockfile for oxfmt

* chore: migrate typecheck to TypeScript 7.0 (#7516)

* chore: bump TypeScript to 6.0

Baseline hop ahead of the TypeScript 7.0 (native compiler) migration, so the
7.0 cut is a version swap against a config that is already 7.0-shaped.

TypeScript 6.0 raises both `moduleResolution: node10` and `baseUrl` as errors
rather than warnings, and `ignoreDeprecations: "6.0"` stops working in 7.0, so
clearing them properly is the only route:

- `moduleResolution` -> `bundler` (Metro is a bundler), which requires an
  esnext-shaped `module`.
- `baseUrl` removed. Exactly one import relied on it; it is now relative.
- `types` enumerated, since a resolution mode that honours package `exports`
  no longer auto-includes every `@types` package. `@types/node` becomes an
  explicit devDependency.

Honouring `exports` also stranded the bundled `.d.ts` of three dependencies
whose maps expose only JavaScript. Each gets a `types` condition via
patch-package; this is visible to the type checker only, as Metro ignores that
condition. A `paths` mapping was tried first and rejected, because the
jest-expo resolver reads `paths` and then loads those `.d.ts` files at runtime.

The inherited block of commented-out option documentation is dropped.

* chore: migrate typecheck to TypeScript 7.0

Replaces TypeScript 6.0.3 with the native Go compiler. The version is pinned
exactly, since the platform binaries ship as version-matched optional
dependencies; the lockfile records the linux-x64 target CI resolves.

Typecheck wall time drops from 5.77s on 5.9.3 to ~1.0s. No configuration
change was required: the 6.0 hop already left tsconfig in a 7.0-shaped state,
and the default parallelism saturates without `--checkers`.

`@react-navigation/core` needs a patch to type-check. TypeScript 7.0.2
resolves the mutual recursion between `StaticParamList` and
`ParamListForScreens` eagerly where earlier versions defer it, reports the
alias as circular, and degrades it to a non-generic symbol -- surfacing as
`TS2315: Type 'StaticParamList' is not generic` at our call sites. The patch
drops a `FlatType<>` wrapper from the alias, which only flattens intersections
for editor display, so the type is unchanged and the misfire stops.

* chore: Bump version to 4.76.0 (#7542)

* chore(ci): apply least privilege permission to GitHub Actions (#7350)

* chore: switch React Compiler to infer mode (#7545)

* ci: route Maestro e2e selection through sniffler impact analysis (#7476)

* fix(iOS): RoomItem Swipe not working after scroll (#7532)

* fix(ci): select shards for changes outside app and honor the release label (#7555)

* fix: delete background taller than its row on ServersHistory (#7536)

* fix: delete background taller than its row on server items

* chore: code improvements

---------

Co-authored-by: Diego Mello <diegolmello@gmail.com>

* fix: UIKit block messages rendering with smaller font size (#7531)

* fix: UIKit block messages rendering with smaller font size

* fix: snapshot

* fix(db): move deleteMessage finds and prepares inside the writer lock (#7550)

* fix: quote has no effect on older thread messages (#7535)

* fix: Quote has no effect on older thread messages

* fix: Quote has no effect on older thread messages

* chore: e2e test

* fix: e2e test

* chore: format code and fix lint issues

* fix(MessageComposer): resolve quoted thread messages and guard stale lookups

* fix: test

---------

Co-authored-by: OtavioStasiak <OtavioStasiak@users.noreply.github.com>

* fix(db): move persistMessage lookups and prepares inside the writer lock (#7551)

* fix:  test case 11 and 12 flaky tests (#7564)

* fix: test

* fix: room last messa test

* fix: jumptomessage test

* chore: remove comments

* fix: jump to message e2e test iOS

* remove unused comment

* fix(db): move sendMessage reads and prepares inside the writer lock (#7546)

* fix(db): move sendMessage reads and prepares inside the writer lock

* fix: test improvements

* chore: remove comments

* fix: Admin Panel content hidden behind bottom navigation bar (#7538)

* feat: add tabular numbers (#7568)

* feat: tabular numbers across the app, upgrade Inter to 4.1

* update snapshot

* chore: pin @rocket.chat/sdk to a specific commit hash (#7569)

* fix(e2ee): re-fetch subscription inside the write in toggleRoomE2EE (#7554)

* fix(e2ee): re-fetch subscription inside the write in toggleRoomE2EE

* code improvements

* removed unused comment

* fix: run handleDelete finds and prepares inside the writer lock (#7552)

* fix: run handleDelete finds and prepares inside the writer lock

* chore: reuse mockWMDB

* fix: crop screen hidden behind navigation bar on iOS 26 (#7529)

* fix: re-fetch message inside the write in getThreadName (#7557)

* fix: re-fetch message inside the write in getThreadName

* fix: re-fetch message inside the write in getThreadName

* chore: new test cases

* remove unecessary async

* fix(db): move decryptPendingMessages prepares inside the writer lock (#7548)

* fix(db): move decryptPendingMessages prepares inside the writer lock

* code improvements

* chore: new test case encryption

* chore: format code and fix lint issues

---------

Co-authored-by: OtavioStasiak <OtavioStasiak@users.noreply.github.com>

* fix(android): VideoConf notification accept and decline button hidden and touch not working (#7533)

* fix: in-app notification buttons ignoring taps on Android

* fix: Decline and Accept invisible on the incoming call notification

* fix: UIKit buttons not responding on some Android devices (#7573)

* fix: force Google account chooser on OAuth login (#7572)

* fix: ISO format support in markdown component (#6943)

* fix: resolve deep links by room id for channels and groups (#7111)

* Merge pull request #7570 from RocketChat/deeplink-saml-auth

feat: SAML deeplink auth

* fix: grant pull-requests write to build call sites in build-develop (#7599)

The reusable workflows build-android.yml and build-ios.yml declare
pull-requests: write on their upload jobs. GitHub validates these at
call time regardless of job conditionals, so build-develop.yml
(caller) must grant the permission or the workflow fails validation.
build-pr.yml already grants it; this mirrors that.

---------

Co-authored-by: Rohit Bansal <40559587+Rohit3523@users.noreply.github.com>
Co-authored-by: Yasmim Nagat <117310290+yasnagat@users.noreply.github.com>
Co-authored-by: Otávio Stasiak <91474186+OtavioStasiak@users.noreply.github.com>
Co-authored-by: OtavioStasiak <OtavioStasiak@users.noreply.github.com>
Co-authored-by: Yash Rajpal <58601732+yash-rajpal@users.noreply.github.com>
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