-
Notifications
You must be signed in to change notification settings - Fork 13k
fix(federation): handle "disinvite" and duplicated messages #37791
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
Looks like this PR is ready to merge! 🎉 |
🦋 Changeset detectedLatest commit: 266f381 The changes in this PR will be included in the next version bump. This PR includes changesets to release 41 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
WalkthroughThis PR bumps the federation SDK across packages, adds 403-handling when rejecting Matrix invites (removing the local subscription on forbidden responses), and adds end-to-end tests covering revoked-invitation flows. Changes
Sequence Diagram(s)sequenceDiagram
participant RC as Rocket.Chat (FederationMatrix)
participant SDK as `@rocket.chat/federation-sdk`
participant Room as Room subsystem / DB
RC->>SDK: rejectInvite(invite)
alt SDK returns success
SDK-->>RC: success
RC->>Room: (no-op / keep subscription removed by normal flow)
else SDK throws FederationRequestError (403)
SDK-->>RC: throw FederationRequestError(403)
RC->>Room: performUserRemoval(room, user)
Room-->>RC: removal confirmed
else SDK throws other error
SDK-->>RC: throw Error
RC->>RC: log error and rethrow
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes
Possibly related PRs
Suggested labels
Suggested reviewers
Poem
Pre-merge checks and finishing touches✅ Passed checks (5 passed)
✨ Finishing touches🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro Disabled knowledge base sources:
⛔ Files ignored due to path filters (1)
📒 Files selected for processing (3)
🚧 Files skipped from review as they are similar to previous changes (2)
🧰 Additional context used🧠 Learnings (4)📓 Common learnings📚 Learning: 2025-10-28T16:53:42.761ZApplied to files:
📚 Learning: 2025-11-05T21:04:35.787ZApplied to files:
📚 Learning: 2025-09-19T15:15:04.642ZApplied to files:
⏰ 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). (3)
🔇 Additional comments (1)
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. Comment |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## develop #37791 +/- ##
===========================================
- Coverage 67.80% 67.72% -0.09%
===========================================
Files 3458 3458
Lines 113955 113953 -2
Branches 20927 20926 -1
===========================================
- Hits 77271 77175 -96
- Misses 34553 34648 +95
+ Partials 2131 2130 -1
Flags with carried forward coverage won't be shown. Click here to find out more. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
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/src/FederationMatrix.ts (1)
897-936: Handle revoked invite on accept path too (currently only clears on reject).The original FB-144 repro scenario is "accept after disinvite". A 403 from the accept path currently propagates as an error without any subscription cleanup, leaving the INVITED subscription dangling. The reject path already handles this correctly by calling
performUserRemovalon 403. Apply the same logic to accept: catch the 403, remove the stale subscription, then throw an error for the user.async handleInvite(roomId: IRoom['_id'], userId: IUser['_id'], action: 'accept' | 'reject'): Promise<void> { @@ if (action === 'accept') { + try { + await federationSDK.acceptInvite(room.federation.mrid, matrixUserId); + } catch (error) { + if (error instanceof FederationRequestError && error.response?.status === 403) { + await Room.performUserRemoval(room, user); + throw new Error('Invitation was revoked'); + } + throw error; + } await Room.performAcceptRoomInvite(room, subscription, user); + return; } if (action === 'reject') { try { await federationSDK.rejectInvite(room.federation.mrid, matrixUserId); } catch (error) { - if (error instanceof FederationRequestError && error.response.status === 403) { + if (error instanceof FederationRequestError && error.response?.status === 403) { return Room.performUserRemoval(room, user); } this.logger.error(error, 'Failed to reject invite in Matrix'); throw error; } } }Also add optional chaining (
error.response?.status) for defensive access to the response object.
🧹 Nitpick comments (2)
.changeset/dull-tips-look.md (1)
1-7: Changeset looks correct; consider making the description more specific (revoked invite → stale INVITED subscription / 403).
Current wording is fine, but a slightly more explicit summary will make release notes clearer.ee/packages/federation-matrix/tests/end-to-end/room.spec.ts (1)
1660-1705: Strengthen revoked-invite assertions (and add retries for eventual consistency).
Two improvements that will make this scenario more robust and more clearly tied to FB-144:
- Poll for subscription removal (same reason as above).
- When
acceptfails, assert the error message contains something like “revoked” (once implemented), and consider asserting the stale invitation is cleared (either on accept-403 cleanup or after reject).
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Jira integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
⛔ Files ignored due to path filters (1)
yarn.lockis excluded by!**/yarn.lock,!**/*.lock
📒 Files selected for processing (6)
.changeset/dull-tips-look.md(1 hunks)apps/meteor/package.json(1 hunks)ee/packages/federation-matrix/package.json(1 hunks)ee/packages/federation-matrix/src/FederationMatrix.ts(2 hunks)ee/packages/federation-matrix/tests/end-to-end/room.spec.ts(1 hunks)packages/core-services/package.json(1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{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:
ee/packages/federation-matrix/tests/end-to-end/room.spec.tsee/packages/federation-matrix/src/FederationMatrix.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.tsextension for test files (e.g.,login.spec.ts)
Files:
ee/packages/federation-matrix/tests/end-to-end/room.spec.ts
🧠 Learnings (7)
📓 Common learnings
Learnt from: sampaiodiego
Repo: RocketChat/Rocket.Chat PR: 37532
File: ee/packages/federation-matrix/src/FederationMatrix.ts:920-927
Timestamp: 2025-12-09T20:01:07.355Z
Learning: In Rocket.Chat's federation invite handling (ee/packages/federation-matrix/src/FederationMatrix.ts), when a user rejects an invite via federationSDK.rejectInvite(), the subscription cleanup happens automatically through an event-driven flow: Matrix emits a leave event back, which is processed by handleLeave() in ee/packages/federation-matrix/src/events/member.ts, and that function calls Room.performUserRemoval() to clean up the subscription. No explicit cleanup is needed in the reject branch of handleInvite() because the leave event handler takes care of it.
<!-- </add_learning>
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37377
File: apps/meteor/ee/server/hooks/federation/index.ts:86-88
Timestamp: 2025-11-04T16:49:19.107Z
Learning: In Rocket.Chat's federation system (apps/meteor/ee/server/hooks/federation/), permission checks follow two distinct patterns: (1) User-initiated federation actions (creating rooms, adding users to federated rooms, joining from invites) should throw MeteorError to inform users they lack 'access-federation' permission. (2) Remote server-initiated federation events should silently skip/ignore when users lack permission. The beforeAddUserToRoom hook only executes for local user-initiated actions, so throwing an error there is correct. Remote federation events are handled separately by the federation Matrix package with silent skipping logic.
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37205
File: ee/packages/federation-matrix/src/FederationMatrix.ts:296-301
Timestamp: 2025-10-28T16:53:42.761Z
Learning: In the Rocket.Chat federation-matrix integration (ee/packages/federation-matrix/), the createRoom method from rocket.chat/federation-sdk will support a 4-argument signature (userId, roomName, visibility, displayName) in newer versions. Code using this 4-argument call is forward-compatible with planned library updates and should not be flagged as an error.
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37205
File: ee/packages/federation-matrix/src/FederationMatrix.ts:296-301
Timestamp: 2025-10-28T16:53:42.761Z
Learning: In the Rocket.Chat federation-matrix integration (ee/packages/federation-matrix/), the createRoom method from rocket.chat/federation-sdk will support a 4-argument signature (userId, roomName, visibility, displayName) in newer versions. Code using this 4-argument call is forward-compatible with planned library updates and should not be flagged as an error.
📚 Learning: 2025-10-28T16:53:42.761Z
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37205
File: ee/packages/federation-matrix/src/FederationMatrix.ts:296-301
Timestamp: 2025-10-28T16:53:42.761Z
Learning: In the Rocket.Chat federation-matrix integration (ee/packages/federation-matrix/), the createRoom method from rocket.chat/federation-sdk will support a 4-argument signature (userId, roomName, visibility, displayName) in newer versions. Code using this 4-argument call is forward-compatible with planned library updates and should not be flagged as an error.
Applied to files:
apps/meteor/package.jsonee/packages/federation-matrix/package.jsonee/packages/federation-matrix/tests/end-to-end/room.spec.tsee/packages/federation-matrix/src/FederationMatrix.tspackages/core-services/package.json
📚 Learning: 2025-09-19T15:15:04.642Z
Learnt from: rodrigok
Repo: RocketChat/Rocket.Chat PR: 36991
File: apps/meteor/server/services/federation/infrastructure/rocket-chat/adapters/Settings.ts:219-221
Timestamp: 2025-09-19T15:15:04.642Z
Learning: The Federation_Matrix_homeserver_domain setting in apps/meteor/server/services/federation/infrastructure/rocket-chat/adapters/Settings.ts is part of the old federation system and is being deprecated/removed, so configuration issues with this setting should not be flagged for improvement.
Applied to files:
apps/meteor/package.jsonee/packages/federation-matrix/package.jsonee/packages/federation-matrix/src/FederationMatrix.tspackages/core-services/package.json.changeset/dull-tips-look.md
📚 Learning: 2025-11-04T16:49:19.107Z
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37377
File: apps/meteor/ee/server/hooks/federation/index.ts:86-88
Timestamp: 2025-11-04T16:49:19.107Z
Learning: In Rocket.Chat's federation system (apps/meteor/ee/server/hooks/federation/), permission checks follow two distinct patterns: (1) User-initiated federation actions (creating rooms, adding users to federated rooms, joining from invites) should throw MeteorError to inform users they lack 'access-federation' permission. (2) Remote server-initiated federation events should silently skip/ignore when users lack permission. The beforeAddUserToRoom hook only executes for local user-initiated actions, so throwing an error there is correct. Remote federation events are handled separately by the federation Matrix package with silent skipping logic.
Applied to files:
apps/meteor/package.jsonee/packages/federation-matrix/src/FederationMatrix.ts.changeset/dull-tips-look.md
📚 Learning: 2025-11-05T21:04:35.787Z
Learnt from: sampaiodiego
Repo: RocketChat/Rocket.Chat PR: 37357
File: ee/packages/federation-matrix/src/setup.ts:103-120
Timestamp: 2025-11-05T21:04:35.787Z
Learning: In Rocket.Chat's federation-matrix setup (ee/packages/federation-matrix/src/setup.ts and apps/meteor/ee/server/startup/federation.ts), configureFederationMatrixSettings does not need to be called before setupFederationMatrix. The SDK's init() establishes infrastructure (database, event handlers, APIs) first, and the configuration can be applied later via settings watchers before actual federation events are processed. The config only matters when events actually occur, at which point all infrastructure is already configured.
Applied to files:
ee/packages/federation-matrix/package.jsonee/packages/federation-matrix/src/FederationMatrix.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/tests/end-to-end/room.spec.tsee/packages/federation-matrix/src/FederationMatrix.ts
📚 Learning: 2025-12-09T20:01:07.355Z
Learnt from: sampaiodiego
Repo: RocketChat/Rocket.Chat PR: 37532
File: ee/packages/federation-matrix/src/FederationMatrix.ts:920-927
Timestamp: 2025-12-09T20:01:07.355Z
Learning: In Rocket.Chat's federation invite handling (ee/packages/federation-matrix/src/FederationMatrix.ts), when a user rejects an invite via federationSDK.rejectInvite(), the subscription cleanup happens automatically through an event-driven flow: Matrix emits a leave event back, which is processed by handleLeave() in ee/packages/federation-matrix/src/events/member.ts, and that function calls Room.performUserRemoval() to clean up the subscription. No explicit cleanup is needed in the reject branch of handleInvite() because the leave event handler takes care of it.
<!-- </add_learning>
Applied to files:
.changeset/dull-tips-look.md
🧬 Code graph analysis (1)
ee/packages/federation-matrix/tests/end-to-end/room.spec.ts (3)
apps/meteor/tests/data/rooms.helper.ts (3)
rejectRoomInvite(492-508)getSubscriptions(467-479)acceptRoomInvite(439-455)ee/packages/federation-matrix/tests/helper/config.ts (1)
federationConfig(113-113)ee/packages/federation-matrix/src/events/member.ts (1)
member(238-261)
⏰ 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). (3)
- GitHub Check: 📦 Build Packages
- GitHub Check: CodeQL-Build
- GitHub Check: CodeQL-Build
🔇 Additional comments (3)
packages/core-services/package.json (1)
18-22: Version alignment is correct.
All internal packages (core-services, federation-matrix, apps/meteor) consistently pin@rocket.chat/federation-sdkto0.3.4, and yarn.lock resolves to a single version. No risk of duplicate installations orinstanceofmismatches.ee/packages/federation-matrix/package.json (1)
21-27: SDK bump to v0.3.4 is compatible with current code usage.The
@rocket.chat/federation-sdkv0.3.4 dependency is properly integrated.FederationRequestErroris successfully imported and used throughout the codebase for error handling (e.g., checkingerror instanceof FederationRequestError && error.response.status === 403). TheacceptInviteandrejectInvitemethods are called consistently without issues. No breaking changes are evident from the working code patterns across the federation-matrix package.apps/meteor/package.json (1)
101-101: federation-sdk version 0.3.4 is correctly applied across all workspace packages.Version 0.3.4 is available on npm and all related package.json files (apps/meteor, ee/packages/federation-matrix, and packages/core-services) are consistently updated. The patch-level version bump is properly coordinated across the monorepo.
| } from '@rocket.chat/core-typings'; | ||
| import type { MessageQuoteAttachment, IMessage, IRoom, IUser, IRoomNativeFederated } from '@rocket.chat/core-typings'; | ||
| import { eventIdSchema, roomIdSchema, userIdSchema, federationSDK } from '@rocket.chat/federation-sdk'; | ||
| import { eventIdSchema, roomIdSchema, userIdSchema, federationSDK, FederationRequestError } from '@rocket.chat/federation-sdk'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🌐 Web query:
@rocket.chat/federation-sdk v0.3.4 FederationRequestError export response status
💡 Result:
I don’t see the v0.3.4 source online right now. In practice, FederationRequestError objects usually expose the HTTP status in one of these places — try checking in this order:
- err.response?.status
- err.statusCode
- err.status
If that doesn’t work, log the error keys (console.log(Object.keys(err)) or console.dir(err, { depth: null })) and share the output and/or the thrown error stack and I’ll look up the SDK source (or fetch v0.3.4 on npm/GitHub) and give exact accessors.
🏁 Script executed:
# First, check the actual error handling in FederationMatrix.ts around lines 925-934
fd FederationMatrix.ts | head -5Repository: RocketChat/Rocket.Chat
Length of output: 119
🏁 Script executed:
# Search for FederationRequestError usage in the codebase
rg "FederationRequestError" --type ts --type tsx -B 2 -A 5Repository: RocketChat/Rocket.Chat
Length of output: 93
🏁 Script executed:
# Check package.json for federation-sdk version
rg "@rocket.chat/federation-sdk" package.jsonRepository: RocketChat/Rocket.Chat
Length of output: 48
🏁 Script executed:
# Find the FederationMatrix.ts file and check lines around 925-934
fd FederationMatrix.ts -x cat -n {} | sed -n '920,940p'Repository: RocketChat/Rocket.Chat
Length of output: 733
🏁 Script executed:
# Find package.json files that contain federation-sdk
fd package.json | xargs grep -l "federation-sdk"Repository: RocketChat/Rocket.Chat
Length of output: 169
🏁 Script executed:
# Search for FederationRequestError with broader approach
rg "FederationRequestError" -A 5 -B 2Repository: RocketChat/Rocket.Chat
Length of output: 1805
🏁 Script executed:
# Check the imports in FederationMatrix.ts
head -30 ee/packages/federation-matrix/src/FederationMatrix.tsRepository: RocketChat/Rocket.Chat
Length of output: 1321
🏁 Script executed:
# Check federation-sdk version in ee/packages/federation-matrix/package.json
cat ee/packages/federation-matrix/package.json | grep -A 2 "federation-sdk"Repository: RocketChat/Rocket.Chat
Length of output: 193
🏁 Script executed:
# Search for FederationRequestError class/interface definition in the codebase
rg "class FederationRequestError|interface FederationRequestError|type FederationRequestError" -A 10Repository: RocketChat/Rocket.Chat
Length of output: 48
🏁 Script executed:
# Check if there's a node_modules or type definitions for federation-sdk
fd "FederationRequestError" --type fRepository: RocketChat/Rocket.Chat
Length of output: 48
🏁 Script executed:
# Look for federation-sdk in node_modules or dist if available
find . -name "@rocket.chat" -type d 2>/dev/null | head -5Repository: RocketChat/Rocket.Chat
Length of output: 48
🏁 Script executed:
# Search for any imports or usage of error.response in the codebase to see patterns
rg "error\.response" -A 2 -B 2 | head -40Repository: RocketChat/Rocket.Chat
Length of output: 3444
🏁 Script executed:
# Check if there are other places where FederationRequestError is caught and used
rg "instanceof FederationRequestError" -B 5 -A 5Repository: RocketChat/Rocket.Chat
Length of output: 1024
Use defensive chaining for error.response.status to match codebase patterns: Line 929 accesses error.response.status directly without a null/undefined check, while similar error handling elsewhere in the codebase (webdav, webdavClientAdapter) uses optional chaining (error.response?.statusText). Add a guard (error.response?.status === 403) or validate that error.response exists before accessing status.
🤖 Prompt for AI Agents
In ee/packages/federation-matrix/src/FederationMatrix.ts around line 11 and
specifically where error.response.status is accessed (line ~929), the code
accesses error.response.status directly; change this to use defensive chaining
or a null check (e.g. error.response?.status === 403 or check that
error.response exists before reading status) to avoid runtime errors when
response is undefined, and mirror the existing pattern used elsewhere
(error.response?.statusText) so the conditional safely handles missing response
objects.
| it('should allow RC user to reject the invite and remove the subscription', async () => { | ||
| const rejectResponse = await rejectRoomInvite(rid, rc1AdminRequestConfig); | ||
| expect(rejectResponse.success).toBe(true); | ||
| }); | ||
|
|
||
| it('It should remove the subscription after rejection', async () => { | ||
| const subscriptions = await getSubscriptions(rc1AdminRequestConfig); | ||
|
|
||
| const invitedSub = subscriptions.update.find((sub) => sub.fname?.includes(channelName)); | ||
|
|
||
| expect(invitedSub).toBeFalsy(); | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Avoid flakiness: wait/poll for subscription removal instead of asserting immediately.
If subscription cleanup is driven by async Matrix membership events, this can race. Prefer polling subscriptions.get until the INVITED sub disappears (or a timeout).
it('should allow RC user to reject the invite and remove the subscription', async () => {
const rejectResponse = await rejectRoomInvite(rid, rc1AdminRequestConfig);
expect(rejectResponse.success).toBe(true);
- const subscriptions = await getSubscriptions(rc1AdminRequestConfig);
- const invitedSub = subscriptions.update.find((sub) => sub.fname?.includes(channelName));
- expect(invitedSub).toBeFalsy();
+ const deadline = Date.now() + 10_000;
+ while (true) {
+ const subscriptions = await getSubscriptions(rc1AdminRequestConfig);
+ const invitedSub = subscriptions.update.find((sub) => sub.fname?.includes(channelName));
+ if (!invitedSub) break;
+ if (Date.now() > deadline) throw new Error('Timed out waiting for invited subscription removal');
+ await new Promise((r) => setTimeout(r, 250));
+ }
});📝 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.
| it('should allow RC user to reject the invite and remove the subscription', async () => { | |
| const rejectResponse = await rejectRoomInvite(rid, rc1AdminRequestConfig); | |
| expect(rejectResponse.success).toBe(true); | |
| }); | |
| it('It should remove the subscription after rejection', async () => { | |
| const subscriptions = await getSubscriptions(rc1AdminRequestConfig); | |
| const invitedSub = subscriptions.update.find((sub) => sub.fname?.includes(channelName)); | |
| expect(invitedSub).toBeFalsy(); | |
| }); | |
| it('should allow RC user to reject the invite and remove the subscription', async () => { | |
| const rejectResponse = await rejectRoomInvite(rid, rc1AdminRequestConfig); | |
| expect(rejectResponse.success).toBe(true); | |
| const deadline = Date.now() + 10_000; | |
| while (true) { | |
| const subscriptions = await getSubscriptions(rc1AdminRequestConfig); | |
| const invitedSub = subscriptions.update.find((sub) => sub.fname?.includes(channelName)); | |
| if (!invitedSub) break; | |
| if (Date.now() > deadline) throw new Error('Timed out waiting for invited subscription removal'); | |
| await new Promise((r) => setTimeout(r, 250)); | |
| } | |
| }); |
🤖 Prompt for AI Agents
In ee/packages/federation-matrix/tests/end-to-end/room.spec.ts around lines 1650
to 1657, the test asserts immediately that the invited subscription is removed
which can be flaky due to async Matrix membership events; replace the immediate
check with a polling/wait loop that repeatedly calls getSubscriptions (e.g.,
every 100–500ms) until the invited subscription is no longer present or a
sensible timeout (e.g., 5–10s) elapses, then assert that the invited
subscription is falsy; ensure the polling rejects/fails the test on timeout to
preserve test correctness.
…at#37791) Co-authored-by: Jéssica Souza <jessica_schelly@hotmail.com>
https://rocketchat.atlassian.net/browse/FB-144
Proposed changes (including videos or screenshots)
Issue(s)
Steps to test or reproduce
Further comments
Summary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings.