test(voip): integration tests for CallView pipeline#7161
test(voip): integration tests for CallView pipeline#7161diegolmello merged 12 commits intofeat.voip-lib-newfrom
Conversation
… pipeline
Tests verify that pressing the Call button drives the full pipeline:
- session.startCall called at SDK boundary with correct actor/userId
- Navigation.navigate('CallView') dispatched
- useCallStore.call populated via the real setCall action
- emitter wired at both SDK-layer and store-layer
Test 5 additionally proves CallView renders its container when the store
is populated via setCall, completing the two-halves proof: press → store
update + navigation, and store update → view renders.
|
Note Reviews pausedIt 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 Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughAdds a new React Native integration test suite for NewMediaCall covering outgoing call flows (user and SIP), SDK mock signaling, navigation and store side effects, and several edge cases; also adds a VoIP integration-tests plan document describing expanded lifecycle test scenarios and hygiene requirements. Changes
Sequence Diagram(s)Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes 🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. 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 |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@app/containers/NewMediaCall/NewMediaCall.integration.test.tsx`:
- Around line 273-283: Replace the standalone Jest assertion in the beforeEach
setup with an imperative guard: instead of using
expect(createdSessions).toHaveLength(1) inside beforeEach, check the length of
createdSessions and throw an Error (or call an invariant) if it is not 1 so the
setup fails fast; update the setup block that calls
mediaSessionInstance.init('me') and the singleton-bleed guard to use something
like if (createdSessions.length !== 1) throw new Error('expected exactly one
created session') so lint rule jest/no-standalone-expect is satisfied while
preserving the same protective behavior.
- Around line 29-34: The compile-time route-name guard currently uses the `void
_routeCheck;` statement which trigers the ESLint `no-void` rule; replace that
runtime `void` usage with a lint-safe generic type-assertion helper and call it
with `_routeCheck`. Add a small helper like `function assertType<T>(_v: T): void
{}` (or reuse an existing generic noop assert) and then call
`assertType(_routeCheck)` instead of `void _routeCheck;`, keeping the existing
type alias `type AssertCallViewRoute = InsideStackParamList extends { CallView:
unknown } ? true : never;` and the const `_routeCheck: AssertCallViewRoute =
true;` unchanged so the compile-time guard remains.
🪄 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: 654570b6-009a-4cc0-8514-ed1a194a5cab
📒 Files selected for processing (1)
app/containers/NewMediaCall/NewMediaCall.integration.test.tsx
📜 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 (5)
**/*.{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/containers/NewMediaCall/NewMediaCall.integration.test.tsx
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Use ESLint with
@rocket.chat/eslint-configbase configuration including React, React Native, TypeScript, and Jest plugins
Files:
app/containers/NewMediaCall/NewMediaCall.integration.test.tsx
**/*.{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/containers/NewMediaCall/NewMediaCall.integration.test.tsx
app/containers/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Place reusable UI components in app/containers/ directory
Files:
app/containers/NewMediaCall/NewMediaCall.integration.test.tsx
**/*.{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/containers/NewMediaCall/NewMediaCall.integration.test.tsx
🧠 Learnings (3)
📓 Common learnings
Learnt from: CR
Repo: RocketChat/Rocket.Chat.ReactNative PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-07T17:49:17.538Z
Learning: Applies to app/lib/services/voip/**/*.{ts,tsx} : Implement VoIP with WebRTC peer-to-peer audio calls in app/lib/services/voip/ using Zustand stores instead of Redux, with native CallKit (iOS) and Telecom (Android) integration; keep VoIP and VideoConf separate
📚 Learning: 2026-04-07T17:49:17.538Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat.ReactNative PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-07T17:49:17.538Z
Learning: Applies to app/lib/services/voip/**/*.{ts,tsx} : Implement VoIP with WebRTC peer-to-peer audio calls in app/lib/services/voip/ using Zustand stores instead of Redux, with native CallKit (iOS) and Telecom (Android) integration; keep VoIP and VideoConf separate
Applied to files:
app/containers/NewMediaCall/NewMediaCall.integration.test.tsx
📚 Learning: 2026-03-30T15:49:30.957Z
Learnt from: Rohit3523
Repo: RocketChat/Rocket.Chat.ReactNative PR: 6875
File: app/containers/RoomItem/Actions.tsx:12-12
Timestamp: 2026-03-30T15:49:30.957Z
Learning: In RocketChat/Rocket.Chat.ReactNative, `react-native-worklets` version 0.6.1 does NOT export a built-in Jest mock (e.g., no `react-native-worklets/lib/module/mock`). The correct Jest mock approach for this version is to add a manual mock in `jest.setup.js`: `jest.mock('react-native-worklets', () => ({ scheduleOnRN: jest.fn((fn, ...args) => fn(...args)) }))`.
Applied to files:
app/containers/NewMediaCall/NewMediaCall.integration.test.tsx
🪛 ESLint
app/containers/NewMediaCall/NewMediaCall.integration.test.tsx
[error] 34-34: Expected 'undefined' and instead saw 'void'.
(no-void)
[error] 281-281: Expect must be inside of a test block
(jest/no-standalone-expect)
- Replace `void _routeCheck` (banned by no-void rule) with `(true satisfies AssertCallViewRoute)` — no binding, no unused-var - Add eslint-disable for jest/no-standalone-expect in beforeEach guard
…d setup guard - Replace `(true satisfies AssertCallViewRoute)` with a generic assertType function call: no-unused-expressions can't flag a call - Prefix type param with `_T` to silence unused-type-param TS error - Replace eslint-disable + expect in beforeEach with an imperative throw — satisfies jest/no-standalone-expect without suppressions
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (3)
app/containers/NewMediaCall/NewMediaCall.integration.test.tsx (3)
266-266: Add an explicit return type toWrapper.Line 266 relies on inferred return typing. Adding an explicit return type keeps this file aligned with the TypeScript annotation guideline.
As per coding guidelines, "Use TypeScript for type safety; add explicit type annotations to function parameters and return types".
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/containers/NewMediaCall/NewMediaCall.integration.test.tsx` at line 266, The Wrapper component currently relies on inferred return type; add an explicit return type annotation (e.g., : React.ReactElement or : JSX.Element) to its declaration to satisfy the TypeScript guideline—update the function signature for Wrapper (the component taking { children }: { children: React.ReactNode }) to specify the return type explicitly while keeping the same props and implementation.
166-175: Preferinterfaceovertypefor object-shape contracts.
MockMediaSignalingSessionis an object shape; usinginterfacehere aligns with the TypeScript guideline and keeps extension/merging options open.Suggested refactor
-type MockMediaSignalingSession = { +interface MockMediaSignalingSession { userId: string; sessionId: string; endSession: jest.Mock; on: jest.Mock; processSignal: jest.Mock; setIceGatheringTimeout: jest.Mock; startCall: jest.Mock; getCallData: jest.Mock; -}; +}As per coding guidelines, "Prefer interfaces over type aliases for defining object shapes in TypeScript".
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/containers/NewMediaCall/NewMediaCall.integration.test.tsx` around lines 166 - 175, Replace the type alias used for the mock session object with an interface to follow the project guideline: change the declaration of MockMediaSignalingSession from a `type` to an `interface`, keeping the same property names and types (userId, sessionId, endSession, on, processSignal, setIceGatheringTimeout, startCall, getCallData) so existing uses of MockMediaSignalingSession continue to work and enable future interface extension/merging.
12-13: Update stale test-number comments for clarity.References to “Test 5” are confusing in a suite with four
it(...)tests plus one compile-time assertion. Renaming those comments will reduce maintenance friction.Also applies to: 239-240, 379-380
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/containers/NewMediaCall/NewMediaCall.integration.test.tsx` around lines 12 - 13, Update the stale "Test 5" comment text in NewMediaCall.integration.test.tsx to a clearer label (e.g., "separate test" or "separate case") so it accurately reflects the suite structure; search for the exact comment string "Test 5" (and the same phrasing used around the lines noted) and replace it with the new phrasing in all occurrences so comments near the tests and the compile-time assertion are consistent.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@app/containers/NewMediaCall/NewMediaCall.integration.test.tsx`:
- Around line 31-32: The generic type parameter is reported as unused; update
the compile-time assertion so the type parameter is actually referenced. Change
the declaration of assertType to consume its type parameter (e.g. const
assertType = <T extends true>() => undefined as unknown as T;) and keep the call
assertType<InsideStackParamList extends { CallView: unknown } ? true : false>();
so the type parameter (T) is used and the ESLint
`@typescript-eslint/no-unused-vars` error is resolved while preserving the
compile-time route assertion (referencing assertType and InsideStackParamList).
---
Nitpick comments:
In `@app/containers/NewMediaCall/NewMediaCall.integration.test.tsx`:
- Line 266: The Wrapper component currently relies on inferred return type; add
an explicit return type annotation (e.g., : React.ReactElement or : JSX.Element)
to its declaration to satisfy the TypeScript guideline—update the function
signature for Wrapper (the component taking { children }: { children:
React.ReactNode }) to specify the return type explicitly while keeping the same
props and implementation.
- Around line 166-175: Replace the type alias used for the mock session object
with an interface to follow the project guideline: change the declaration of
MockMediaSignalingSession from a `type` to an `interface`, keeping the same
property names and types (userId, sessionId, endSession, on, processSignal,
setIceGatheringTimeout, startCall, getCallData) so existing uses of
MockMediaSignalingSession continue to work and enable future interface
extension/merging.
- Around line 12-13: Update the stale "Test 5" comment text in
NewMediaCall.integration.test.tsx to a clearer label (e.g., "separate test" or
"separate case") so it accurately reflects the suite structure; search for the
exact comment string "Test 5" (and the same phrasing used around the lines
noted) and replace it with the new phrasing in all occurrences so comments near
the tests and the compile-time assertion are consistent.
🪄 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: b15ddd28-80f6-4556-a48d-ed3a0643e9d8
📒 Files selected for processing (1)
app/containers/NewMediaCall/NewMediaCall.integration.test.tsx
📜 Review details
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{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/containers/NewMediaCall/NewMediaCall.integration.test.tsx
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Use ESLint with
@rocket.chat/eslint-configbase configuration including React, React Native, TypeScript, and Jest plugins
Files:
app/containers/NewMediaCall/NewMediaCall.integration.test.tsx
**/*.{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/containers/NewMediaCall/NewMediaCall.integration.test.tsx
app/containers/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Place reusable UI components in app/containers/ directory
Files:
app/containers/NewMediaCall/NewMediaCall.integration.test.tsx
**/*.{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/containers/NewMediaCall/NewMediaCall.integration.test.tsx
🧠 Learnings (4)
📓 Common learnings
Learnt from: CR
Repo: RocketChat/Rocket.Chat.ReactNative PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-07T17:49:17.538Z
Learning: Applies to app/lib/services/voip/**/*.{ts,tsx} : Implement VoIP with WebRTC peer-to-peer audio calls in app/lib/services/voip/ using Zustand stores instead of Redux, with native CallKit (iOS) and Telecom (Android) integration; keep VoIP and VideoConf separate
📚 Learning: 2026-04-07T17:49:17.538Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat.ReactNative PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-07T17:49:17.538Z
Learning: Applies to app/lib/services/voip/**/*.{ts,tsx} : Implement VoIP with WebRTC peer-to-peer audio calls in app/lib/services/voip/ using Zustand stores instead of Redux, with native CallKit (iOS) and Telecom (Android) integration; keep VoIP and VideoConf separate
Applied to files:
app/containers/NewMediaCall/NewMediaCall.integration.test.tsx
📚 Learning: 2026-03-30T15:49:30.957Z
Learnt from: Rohit3523
Repo: RocketChat/Rocket.Chat.ReactNative PR: 6875
File: app/containers/RoomItem/Actions.tsx:12-12
Timestamp: 2026-03-30T15:49:30.957Z
Learning: In RocketChat/Rocket.Chat.ReactNative, `react-native-worklets` version 0.6.1 does NOT export a built-in Jest mock (e.g., no `react-native-worklets/lib/module/mock`). The correct Jest mock approach for this version is to add a manual mock in `jest.setup.js`: `jest.mock('react-native-worklets', () => ({ scheduleOnRN: jest.fn((fn, ...args) => fn(...args)) }))`.
Applied to files:
app/containers/NewMediaCall/NewMediaCall.integration.test.tsx
📚 Learning: 2026-04-07T17:49:25.836Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat.ReactNative PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-07T17:49:25.836Z
Learning: Applies to **/*.{ts,tsx} : Use TypeScript for type safety; add explicit type annotations to function parameters and return types
Applied to files:
app/containers/NewMediaCall/NewMediaCall.integration.test.tsx
🪛 ESLint
app/containers/NewMediaCall/NewMediaCall.integration.test.tsx
[error] 31-31: '_T' is defined but never used.
(@typescript-eslint/no-unused-vars)
🔇 Additional comments (1)
app/containers/NewMediaCall/NewMediaCall.integration.test.tsx (1)
292-356: Strong integration-contract coverage here — nice work.This validates the critical chain (button press → SDK boundary call →
newCallhandling → store wiring → navigation/render) and includes meaningful negative-path assertions.Also applies to: 358-377, 382-406
Previous tests severed the button→navigation pipeline: session.startCall was
jest.fn() that did nothing, then tests manually invoked the newCall handler.
Navigation and button press were causally unrelated.
Key changes:
- MockMediaSignalingSession now has a real handler registry (on() stores
handlers; emit() dispatches to them) instead of jest.fn() that only records
- startCall(actor, userId) fires 'newCall' synchronously with a synthetic
outgoing call — simulating the SDK's response after WebRTC negotiation
- fireEvent.press alone now causes Navigation.navigate('CallView')
- Behavioral ended-handler test: fire call.emitter.emit('ended'), assert
RNCallKeep.endCall and Navigation.back (replaces fragile toHaveLength counts)
- Add hidden=true branch test: newCall must not navigate or populate store
- Add callee-role branch test: incoming calls must not navigate on newCall
- mockCallEmitter prefix required by jest.mock hoisting restriction
There was a problem hiding this comment.
🧹 Nitpick comments (1)
app/containers/NewMediaCall/NewMediaCall.integration.test.tsx (1)
166-175: Preferinterfacefor object-shape definitions in this test file.
MockMediaSignalingSession(line 166) and thebuildClientMediaCalloptions shape (lines 213–218) should be converted to interfaces. This aligns with the repository's TypeScript guideline: "Prefer interfaces over type aliases for defining object shapes in TypeScript."Suggested refactor
-type MockMediaSignalingSession = { +interface MockMediaSignalingSession { userId: string; sessionId: string; endSession: jest.Mock; on: jest.Mock; processSignal: jest.Mock; setIceGatheringTimeout: jest.Mock; startCall: jest.Mock; getCallData: jest.Mock; -}; +} + +interface BuildClientMediaCallOptions { + callId: string; + role: 'caller' | 'callee'; + hidden?: boolean; + contact?: { username?: string; sipExtension?: string }; +} -function buildClientMediaCall(options: { - callId: string; - role: 'caller' | 'callee'; - hidden?: boolean; - contact?: { username?: string; sipExtension?: string }; -}): IClientMediaCall { +function buildClientMediaCall(options: BuildClientMediaCallOptions): IClientMediaCall {🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/containers/NewMediaCall/NewMediaCall.integration.test.tsx` around lines 166 - 175, Convert the object-shape type aliases to interfaces: replace the type alias MockMediaSignalingSession with an interface declaration and likewise convert the options shape used by buildClientMediaCall (the options parameter type) into an interface; update any references to these types (e.g., in test helpers and function signatures) so they refer to the new interface names and ensure the jest.Mock properties remain typed the same.
🤖 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/containers/NewMediaCall/NewMediaCall.integration.test.tsx`:
- Around line 166-175: Convert the object-shape type aliases to interfaces:
replace the type alias MockMediaSignalingSession with an interface declaration
and likewise convert the options shape used by buildClientMediaCall (the options
parameter type) into an interface; update any references to these types (e.g.,
in test helpers and function signatures) so they refer to the new interface
names and ensure the jest.Mock properties remain typed the same.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: de6cfd6c-ddad-4ef1-b168-158ef84733ce
📒 Files selected for processing (1)
app/containers/NewMediaCall/NewMediaCall.integration.test.tsx
📜 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 (5)
**/*.{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/containers/NewMediaCall/NewMediaCall.integration.test.tsx
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Use ESLint with
@rocket.chat/eslint-configbase configuration including React, React Native, TypeScript, and Jest plugins
Files:
app/containers/NewMediaCall/NewMediaCall.integration.test.tsx
**/*.{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/containers/NewMediaCall/NewMediaCall.integration.test.tsx
app/containers/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Place reusable UI components in app/containers/ directory
Files:
app/containers/NewMediaCall/NewMediaCall.integration.test.tsx
**/*.{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/containers/NewMediaCall/NewMediaCall.integration.test.tsx
🧠 Learnings (3)
📓 Common learnings
Learnt from: CR
Repo: RocketChat/Rocket.Chat.ReactNative PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-07T17:49:17.538Z
Learning: Applies to app/lib/services/voip/**/*.{ts,tsx} : Implement VoIP with WebRTC peer-to-peer audio calls in app/lib/services/voip/ using Zustand stores instead of Redux, with native CallKit (iOS) and Telecom (Android) integration; keep VoIP and VideoConf separate
Learnt from: Rohit3523
Repo: RocketChat/Rocket.Chat.ReactNative PR: 6875
File: app/containers/RoomItem/Actions.tsx:12-12
Timestamp: 2026-03-30T15:49:30.957Z
Learning: In RocketChat/Rocket.Chat.ReactNative, `react-native-worklets` version 0.6.1 does NOT export a built-in Jest mock (e.g., no `react-native-worklets/lib/module/mock`). The correct Jest mock approach for this version is to add a manual mock in `jest.setup.js`: `jest.mock('react-native-worklets', () => ({ scheduleOnRN: jest.fn((fn, ...args) => fn(...args)) }))`.
📚 Learning: 2026-04-07T17:49:17.538Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat.ReactNative PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-07T17:49:17.538Z
Learning: Applies to app/lib/services/voip/**/*.{ts,tsx} : Implement VoIP with WebRTC peer-to-peer audio calls in app/lib/services/voip/ using Zustand stores instead of Redux, with native CallKit (iOS) and Telecom (Android) integration; keep VoIP and VideoConf separate
Applied to files:
app/containers/NewMediaCall/NewMediaCall.integration.test.tsx
📚 Learning: 2026-04-07T17:49:25.836Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat.ReactNative PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-07T17:49:25.836Z
Learning: Applies to **/*.{ts,tsx} : Use TypeScript for type safety; add explicit type annotations to function parameters and return types
Applied to files:
app/containers/NewMediaCall/NewMediaCall.integration.test.tsx
🔇 Additional comments (3)
app/containers/NewMediaCall/NewMediaCall.integration.test.tsx (3)
29-33: Nice compile-time route guard.This assertion keeps the
CallViewroute contract enforced at type-check time without tripping lint rules.
292-356: Strong integration coverage for user and SIP call paths.The tests assert the critical contract boundaries (
startCall,newCallhandling, navigation, and store binding) with clear and focused assertions.
358-406: Good negative-path and store-to-UI verification.The disabled-button case and the
setCall → CallViewrender/teardown flow make the suite resilient and complete for this pipeline slice.
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@app/containers/NewMediaCall/NewMediaCall.integration.test.tsx`:
- Around line 205-221: The test assigns this.startCall using a
mockImplementation that aliases `this` via `const self = this`, triggering
no-this-alias; replace the mockImplementation with an arrow function so `this`
is captured lexically (e.g., this.startCall =
jest.fn().mockImplementation((_actor: string, userId: string) => { ...
this.emit('newCall', { call }); ... })); keep the same created IClientMediaCall
shape (callId, localParticipant, remoteParticipants, reject, hangup, emitter
from mockCallEmitter) and return Promise.resolve() as before, but remove the
`self` alias.
- Around line 231-246: The makeIncomingCall helper has Prettier violations:
collapse the function parameter block to a single inline parameter list (e.g.,
function makeIncomingCall(options: { callId?: string; role?: 'caller' |
'callee'; hidden?: boolean; }): IClientMediaCall) and reformat the long object
literal so the remoteParticipants array places its object on its own line (e.g.,
remoteParticipants: [{ local: false, role: ..., muted: false, held: false,
contact: {} }], each object starting on its own line), and ensure surrounding
commas/spacing match Prettier conventions for IClientMediaCall,
localParticipant, remoteParticipants, reject/hangup/emitter so CI formatting
passes.
- Around line 299-309: Replace the direct property access
useCallStore.getState().call with object destructuring (assign call from
useCallStore.getState()), and remove the unnecessary outer parentheses around
the type assertion on call!.emitter so the type cast is applied directly and
then call .emit('ended') on that typed emitter; this addresses the
prefer-destructuring warning and the redundant parentheses around the type
assertion used with mockCallEmitter, RNCallKeep.endCall and Navigation.back.
🪄 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: 0e1bc9e4-38cc-46d2-b7ce-53b427e009b7
📒 Files selected for processing (1)
app/containers/NewMediaCall/NewMediaCall.integration.test.tsx
📜 Review details
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{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/containers/NewMediaCall/NewMediaCall.integration.test.tsx
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Use ESLint with
@rocket.chat/eslint-configbase configuration including React, React Native, TypeScript, and Jest plugins
Files:
app/containers/NewMediaCall/NewMediaCall.integration.test.tsx
**/*.{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/containers/NewMediaCall/NewMediaCall.integration.test.tsx
app/containers/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Place reusable UI components in app/containers/ directory
Files:
app/containers/NewMediaCall/NewMediaCall.integration.test.tsx
**/*.{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/containers/NewMediaCall/NewMediaCall.integration.test.tsx
🧠 Learnings (3)
📚 Learning: 2026-04-07T17:49:17.538Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat.ReactNative PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-07T17:49:17.538Z
Learning: Applies to app/lib/services/voip/**/*.{ts,tsx} : Implement VoIP with WebRTC peer-to-peer audio calls in app/lib/services/voip/ using Zustand stores instead of Redux, with native CallKit (iOS) and Telecom (Android) integration; keep VoIP and VideoConf separate
Applied to files:
app/containers/NewMediaCall/NewMediaCall.integration.test.tsx
📚 Learning: 2026-04-07T17:49:17.538Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat.ReactNative PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-07T17:49:17.538Z
Learning: Applies to @(app/sagas/videoConf.ts|app/lib/methods/videoConf.ts) : Manage video conferencing via Redux actions/reducers/sagas in app/sagas/videoConf.ts and app/lib/methods/videoConf.ts using server-managed Jitsi integration; do not conflate with VoIP
Applied to files:
app/containers/NewMediaCall/NewMediaCall.integration.test.tsx
📚 Learning: 2026-04-07T17:49:25.836Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat.ReactNative PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-07T17:49:25.836Z
Learning: Applies to **/*.{ts,tsx} : Use TypeScript for type safety; add explicit type annotations to function parameters and return types
Applied to files:
app/containers/NewMediaCall/NewMediaCall.integration.test.tsx
🪛 ESLint
app/containers/NewMediaCall/NewMediaCall.integration.test.tsx
[error] 207-207: Unexpected aliasing of 'this' to local variable.
(@typescript-eslint/no-this-alias)
[error] 231-235: Replace ⏎↹callId?:·string;⏎↹role?:·'caller'·|·'callee';⏎↹hidden?:·boolean;⏎ with ·callId?:·string;·role?:·'caller'·|·'callee';·hidden?:·boolean·
(prettier/prettier)
[error] 241-241: Replace {·local:·false,·role:·options.role·===·'caller'·?·'callee'·:·'caller',·muted:·false,·held:·false,·contact:·{}·} with ⏎↹↹↹{·local:·false,·role:·options.role·===·'caller'·?·'callee'·:·'caller',·muted:·false,·held:·false,·contact:·{}·}⏎↹↹
(prettier/prettier)
[error] 301-301: Use object destructuring.
(prefer-destructuring)
[error] 307-307: Replace (RNCallKeep.endCall·as·jest.Mock) with RNCallKeep.endCall·as·jest.Mock
(prettier/prettier)
🪛 GitHub Check: ESLint and Test / run-eslint-and-test
app/containers/NewMediaCall/NewMediaCall.integration.test.tsx
[failure] 307-307:
Replace (RNCallKeep.endCall·as·jest.Mock) with RNCallKeep.endCall·as·jest.Mock
[failure] 301-301:
Use object destructuring
[failure] 241-241:
Replace {·local:·false,·role:·options.role·===·'caller'·?·'callee'·:·'caller',·muted:·false,·held:·false,·contact:·{}·} with ⏎↹↹↹{·local:·false,·role:·options.role·===·'caller'·?·'callee'·:·'caller',·muted:·false,·held:·false,·contact:·{}·}⏎↹↹
[failure] 231-231:
Replace ⏎↹callId?:·string;⏎↹role?:·'caller'·|·'callee';⏎↹hidden?:·boolean;⏎ with ·callId?:·string;·role?:·'caller'·|·'callee';·hidden?:·boolean·
[failure] 207-207:
Unexpected aliasing of 'this' to local variable
🔇 Additional comments (3)
app/containers/NewMediaCall/NewMediaCall.integration.test.tsx (3)
31-32: Compile-time route guard looks correct.The type assertion pattern now uses
_Tas the parameter type, satisfying the@typescript-eslint/no-unused-varsrule while maintaining the compile-time check thatCallViewexists inInsideStackParamList.
256-275: Test setup and teardown are well-structured.The
beforeEachproperly resets all state (mocks, stores, singleton) and uses an imperative guard for the singleton-bleed check. TheafterEachcorrectly restores the console spy.
311-412: Remaining test cases are well-designed.The tests comprehensively cover:
- SIP peer outgoing calls
- Disabled button when no peer selected
- Hidden call filtering
- Callee role handling (incoming calls)
- CallView render/unmount contract
Good test isolation and clear documentation of the integration strategy.
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
docs/plans/voip-integration-tests-phase-2.md (1)
91-91: Clean up inline code-span spacing for markdown lint hygiene.Line formatting around inline code at this point appears to trigger
MD038. Not blocking, but worth adjusting to keep docs lint-clean.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/plans/voip-integration-tests-phase-2.md` at line 91, Fix the MD038 lint issue by removing any leading/trailing spaces inside inline code spans and ensuring punctuation is placed outside backticks; specifically update the inline code spans like `emitDDPMediaSignal(signal)` and `capturedStreamHandler({ fields: { eventName: `${userId}/media-signal`, args: [signal] } })` so the backticks wrap the exact code with no internal extra spaces and no stray spaces before/after the backtick delimiters.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@docs/plans/voip-integration-tests-phase-2.md`:
- Line 297: The document contains incorrect cross-reference numbers "step 7.7"
and "step 7.11" that don't match Section 7's 1–11 sequence; update those
references to the correct step numbers (change "step 7.7" to "step 7" and "step
7.11" to "step 11" or whatever the intended targets are), ensure the wording and
any internal links point to the correct entries in Section 7, and run a quick
scan of the file for any other misnumbered "step 7.*" references to correct them
consistently.
- Line 7: The grep example in the document is written with pipes which the shell
treats as separate commands; change the example to use grep's extended regex
mode (egrep or grep -E) and pass the alternation pattern as a single, quoted
argument containing testMatch|testRegex|integration\.test|NewMediaCall so the
pipe characters are interpreted as alternation rather than shell pipes; update
both occurrences of the command in the doc (the line containing the grep example
and the similar occurrence around lines ~63).
---
Nitpick comments:
In `@docs/plans/voip-integration-tests-phase-2.md`:
- Line 91: Fix the MD038 lint issue by removing any leading/trailing spaces
inside inline code spans and ensuring punctuation is placed outside backticks;
specifically update the inline code spans like `emitDDPMediaSignal(signal)` and
`capturedStreamHandler({ fields: { eventName: `${userId}/media-signal`, args:
[signal] } })` so the backticks wrap the exact code with no internal extra
spaces and no stray spaces before/after the backtick delimiters.
🪄 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: 1dbb850e-1ec6-4a6d-af60-3fefea5dfcae
📒 Files selected for processing (1)
docs/plans/voip-integration-tests-phase-2.md
📜 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
🧠 Learnings (3)
📓 Common learnings
Learnt from: CR
Repo: RocketChat/Rocket.Chat.ReactNative PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-07T17:49:17.538Z
Learning: Applies to app/lib/services/voip/**/*.{ts,tsx} : Implement VoIP with WebRTC peer-to-peer audio calls in app/lib/services/voip/ using Zustand stores instead of Redux, with native CallKit (iOS) and Telecom (Android) integration; keep VoIP and VideoConf separate
📚 Learning: 2026-04-07T17:49:17.538Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat.ReactNative PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-07T17:49:17.538Z
Learning: Applies to app/lib/services/voip/**/*.{ts,tsx} : Implement VoIP with WebRTC peer-to-peer audio calls in app/lib/services/voip/ using Zustand stores instead of Redux, with native CallKit (iOS) and Telecom (Android) integration; keep VoIP and VideoConf separate
Applied to files:
docs/plans/voip-integration-tests-phase-2.md
📚 Learning: 2026-04-07T17:49:17.538Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat.ReactNative PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-07T17:49:17.538Z
Learning: Applies to @(app/sagas/videoConf.ts|app/lib/methods/videoConf.ts) : Manage video conferencing via Redux actions/reducers/sagas in app/sagas/videoConf.ts and app/lib/methods/videoConf.ts using server-managed Jitsi integration; do not conflate with VoIP
Applied to files:
docs/plans/voip-integration-tests-phase-2.md
🪛 LanguageTool
docs/plans/voip-integration-tests-phase-2.md
[uncategorized] ~7-~7: The official name of this software platform is spelled with a capital “H”.
Context: ... across jest.config*, package.json, .github/**/*.{yml,yaml} returns no matches...
(GITHUB)
🪛 markdownlint-cli2 (0.22.0)
docs/plans/voip-integration-tests-phase-2.md
[warning] 91-91: Spaces inside code span elements
(MD038, no-space-in-code)
This reverts commit 19f3ef5.
…cle.integration.test.tsx Filename now reflects genre (call lifecycle across MediaSessionInstance + useCallStore), not just the press component. CI-glob audit: no config references the old name; Jest default testMatch picks up the renamed file.
Adds 9 tests covering the call-lifecycle handlers previously untested:
- answerCall (A1/A2/A3): DDP accepted signal drives real answerCall;
not-found branch clears native id; idempotent when call already bound.
- endCall (B1/B2/B3): UI useCallStore.endCall + MediaSessionInstance.endCall
for both ringing and active states, asserting RNCallKeep cleanup and
store reset.
- In-call controls (C1/C2/C3): toggleMute / toggleHold flip store state;
trackStateChange emission syncs isMuted/remoteHeld/controlsVisible.
Infrastructure changes:
- Mock react-native-incall-manager so setCall/reset do not log errors.
- Capture sdk.onStreamData handler in mockSdkState so tests can drive
DDP signals through the real MediaSessionInstance listener.
- Add makeSyntheticCall + emitDDPMediaSignal inline helpers.
- Replace the blanket console.error spy with a narrow allowlist spy that
throws on unexpected errors/warns. Known noise is documented inline.
- Wrap emitter/setCall/setState mutations in act() wherever missing.
startCall rejection path deferred to Phase 3: production code does not
catch the SDK's startCall promise, so the test needs the fix first.
- Wrap afterEach reset() in act() to prevent leaked Zustand set() - Strip redundant inner act() from flushMicrotasks helper - Restore jest.fn() on getUniqueId/getUniqueIdSync for spy capability - Rename F1 → E1 to fix test numbering after D-series addition - Add C4: toggleSpeaker async path via InCallManager - Tighten A2: assert console.warn for expected call-not-found branch
Add missing await for toggleSpeaker() calls inside act() to satisfy ESLint require-await rule.
Add getVersion and getBuildNumber to react-native-device-info mock to fix test suite initialization failure in CI.
Proposed changes
Integration tests for the VoIP call lifecycle across real
MediaSessionInstance,useCallStore,NewMediaCall, andCallView— with@rocket.chat/media-signalingmocked at the SDK boundary.Scenarios covered
Outgoing calls (press → CallView)
startCall → newCall → setCall + Navigation.navigatestartCall(sip, number) → newCall → setCall + Navigation.navigateIncoming call handling
answerCallwith native pre-accept: DDP accepted signal drives navigationanswerCallwhen call not found: RNCallKeep cleanup, no navigationHang up (endCall)
useCallStore.endCall: RNCallKeep cleanup + store resetMediaSessionInstance.endCallduringactivestate: full RNCallKeep cleanupMediaSessionInstance.endCallduringringingstate: reject branch cleanupIn-call controls
toggleMute: flips storeisMutedtoggleHold: flips storeisOnHoldtrackStateChangeemission: syncsisMuted/remoteHeld/controlsVisiblefrom call stateButton wiring (CallView → store → SDK)
participant.setMuted+ store flipparticipant.setHeld+ store flipcall.hangup+ RNCallKeep.endCall + store clearedCall state transitions
ringing → active: setscallStartTime+ RNCallKeepsetCurrentCallActiveIssues
https://rocketchat.atlassian.net/browse/VMUX-77
How to test or reproduce
Types of changes
Checklist
Summary by CodeRabbit