feat: Migrate to react-native-true-sheet#6970
Conversation
|
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:
WalkthroughMigrates ActionSheet from Changes
Sequence DiagramsequenceDiagram
participant UI as Caller (Component)
participant AS as ActionSheet (wrapper)
participant Det as Detents Hook
participant TS as TrueSheet
participant CB as options.onClose / onDidDismiss
UI->>AS: showActionSheet(options)
AS->>Det: compute detents/maxHeight/scrollEnabled
Det-->>AS: detents, maxHeight, scrollEnabled
AS->>TS: present(detents, maxHeight, header, content)
TS->>TS: render sheet with detents
User->>TS: interact (tap handle / content pan)
TS->>AS: onDidDismiss()
AS->>CB: call options.onClose() (if provided)
AS->>AS: reset internal state
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. 📝 Coding Plan
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 Tip CodeRabbit can use TruffleHog to scan for secrets in your code with verification capabilities.Add a TruffleHog config file (e.g. trufflehog-config.yml, trufflehog.yml) to your project to customize detectors and scanning behavior. The tool runs only when a config file is present. |
7c04e79 to
b65245a
Compare
b65245a to
7d74120
Compare
2b5b64a to
72a2197
Compare
2233b87 to
f413d19
Compare
97914ff to
76cc834
Compare
|
@coderabbitai review |
|
iOS Build Available Rocket.Chat Experimental 4.71.0.108387 |
|
Android Build Available Rocket.Chat Experimental 4.71.0.108388 Internal App Sharing: https://play.google.com/apps/test/RQVpXLytHNc/ahAO29uNRgU8smap7h_FKwR62mmLrOcJbQlCmtKGuvGhddKUzMvPGcqsxMTltpt8tN4eKDTgQP_TeqYemQaHy6rgnx |
|
Android Build Available Rocket.Chat Experimental 4.71.0.108391 Internal App Sharing: https://play.google.com/apps/test/RQVpXLytHNc/ahAO29uNSA9JzEZnuZulrBCGIcRzcLC_QqlIdb8v9pub2sNaNUuWM4P03rpeGfzqFEc0hb92peceCybxSqXQP97k9- |
|
iOS Build Available Rocket.Chat Experimental 4.71.0.108392 |
diegolmello
left a comment
There was a problem hiding this comment.
Besides these comments, I'm missing unit/integration tests, so I built this Cursor plan to understand how we could add them.
Feel free to copy/paste to your fav AI and ask it to create the tests for you.
Just make sure to review and confirm the tests make sense.
name: ActionSheet test strategy
overview: Define a maintainable unit/integration-focused test plan for the true-sheet migration in ActionSheet, including Storybook coverage and a clear breakdown into independent work items for future AI agents.
todos:
- id: track-b-lifecycle-wrapper
content: Define and implement ActionSheet lifecycle/wrapper integration tests with fake timers and dismissal callback assertions.
status: pending - id: track-c-options-interactions
content: Add BottomSheetContent/Item/Handle interaction and accessibility tests for options behavior and disabled paths.
status: pending - id: track-d-detents-expansion
content: Expand detents hook tests to cover orientation overrides, boundary clamping, and dynamic-height branches.
status: pending - id: track-e-input-submit
content: Add integration tests for ActionSheetContentWithInputAndSubmit required-input logic and submit/cancel flows.
status: pending - id: track-a-provider-contract
content: Add Provider contract tests for show/hide refs and hook API safety.
status: pending - id: track-f-storybook-baseline
content: Create ActionSheet stories and snapshot tests for key visual/structural states.
status: pending
isProject: false
ActionSheet Test Plan (True-Sheet Migration)
Scope And Goal
Build durable test coverage for @app/containers/ActionSheet so regressions are caught early while keeping tests readable, meaningful, and maintainable.
Primary files in scope:
- app/containers/ActionSheet/ActionSheet.tsx
- app/containers/ActionSheet/Provider.tsx
- app/containers/ActionSheet/BottomSheetContent.tsx
- app/containers/ActionSheet/Item.tsx
- app/containers/ActionSheet/Handle.tsx
- app/containers/ActionSheet/useActionSheetDetents.ts
- app/containers/ActionSheet/ActionSheetContentWithInputAndSubmit/index.tsx
Supporting infra and patterns:
- jest.setup.js
- jest.config.js
- app/containers/UIKit/MultiSelect/MultiSelect.test.tsx
- app/containers/MessageComposer/MessageComposer.test.tsx
- app/containers/UIKit/UiKitModal.stories.tsx
- app/containers/UIKit/UiKitModal.test.tsx
- .rnstorybook/generateSnapshots.tsx
Should We Test true-sheet Itself?
Short answer: not directly in unit/integration Jest tests.
What makes sense:
- Test our wrapper contract with
true-sheet(props passed, imperative methods called, callbacks wired, timing behavior). - Test our business/UI logic around options, callbacks, disabled states, orientation snaps, and close lifecycle.
What does not make sense in Jest/RNTL:
- Native drag physics, animation smoothness, detent snapping transitions, backdrop tap internals, keyboard-native layout interplay.
- These depend on native runtime and should be validated by E2E/manual checks (separate track, not part of this unit/integration plan).
User Stories To Protect
- As a user, opening an ActionSheet shows the expected content and keyboard is dismissed.
- As a user, closing ActionSheet via handle/cancel/back/native dismiss reliably closes once and runs
onCloseonce. - As a user, I can select options with correct enabled/disabled behavior and visual semantics.
- As a user, the sheet size/detents are appropriate for content size and orientation.
- As a user, custom content mode behaves predictably (layout measurement, full container behavior).
- As a user, accessibility labels/roles make controls understandable.
- As a developer,
showActionSheetandhideActionSheetAPIs are stable and safe across rapid state changes.
Edge Cases To Include
- Rapid
show -> hide -> showtiming around the 200ms present timer. onClosecallback identity snapshot (latest callback should fire on dismiss).options=[]versusoptionsundefined behavior differences.- Duplicate option titles (current keyExtractor risk) documented with an assertion-level test note.
- Disabled item press emits toast event and does not call action.
portraitSnaps/landscapeSnapsoverride behavior.- Android back-handler consumes back only when visible.
- iOS
fullContainer + snapsmin-height behavior in content mode.
RNTL + Storybook Strategy
- Use RNTL integration-style tests for behavior and callback contracts.
- Use Storybook snapshot tests as broad visual-regression baseline for key ActionSheet states.
- Add targeted interaction assertions in RNTL where snapshots are insufficient (callbacks, timing, dismiss flow).
Proposed Test Workstreams (Independent Future AI Tasks)
Track A: Provider Contract Tests
Target files:
- app/containers/ActionSheet/Provider.tsx
- New test:
app/containers/ActionSheet/Provider.test.tsx
Cases:
showActionSheetRef/hideActionSheetRefdelegate to provider methods.useActionSheetreturns stable API in provider scope.- Calling show/hide without mounted sheet is safe (no throw).
Track B: ActionSheet Lifecycle And True-Sheet Wrapper Tests
Target files:
- app/containers/ActionSheet/ActionSheet.tsx
- New test:
app/containers/ActionSheet/ActionSheet.test.tsx
Cases:
showschedules present after 200ms (fake timers).hidedismisses and cancels pending present timer.onDidDismisstriggers currentonClosecallback exactly once.- Android back handling closes when visible and returns consume boolean.
- Wrapper props passed to mocked
TrueSheet:detents,dimmed,draggable,scrollable,maxHeight.
Track C: Options Rendering + Interaction Tests
Target files:
- app/containers/ActionSheet/BottomSheetContent.tsx
- app/containers/ActionSheet/Item.tsx
- app/containers/ActionSheet/Handle.tsx
- New tests:
BottomSheetContent.test.tsx,Item.test.tsx,Handle.test.tsx
Cases:
- Options list renders labels, subtitles, and accessory nodes.
- Cancel footer appears only with
hasCancel; press closes sheet. - Disabled item emits toast event and does not run
onPress. - Handle press calls
hideActionSheet. - Accessibility labels/roles/hints are present and readable.
Track D: Detents Hook Expansion
Target files:
- app/containers/ActionSheet/useActionSheetDetents.ts
- Existing test expansion: app/containers/ActionSheet/useActionSheetDetents.test.tsx
Cases:
- Orientation-specific snaps precedence (
portraitSnaps/landscapeSnaps). - Clamping/sorting/normalization around min/max detents.
- Dynamic content detent from measured height (no options mode).
- Scroll enablement threshold and stable behavior at boundaries.
Track E: Input-And-Submit Integration Tests
Target files:
- app/containers/ActionSheet/ActionSheetContentWithInputAndSubmit/index.tsx
- New test:
ActionSheetContentWithInputAndSubmit.test.tsx
Cases:
- Confirm button disabled state with required inputs.
onButtonPressandonChangeTexthandlers receive expected payload.- Cancel path hides sheet; submit path behavior remains explicit and verified.
- Async submit path and timeout-driven hide behavior are deterministic with fake timers.
Track F: Storybook Coverage For ActionSheet States
Target files:
- New story file:
app/containers/ActionSheet/ActionSheet.stories.tsx - New snapshot test:
app/containers/ActionSheet/ActionSheet.stories.test.tsx - Reuse .rnstorybook/generateSnapshots.tsx
Stories to add:
- Option list: default, destructive option, disabled option.
- Custom children mode.
hasCancelenabled state.- Compact vs long-content variants.
Suggested Test Architecture Rules (Maintainability)
- Favor user-facing assertions over implementation internals.
- Use helper builders for options payloads to reduce fixture noise.
- Keep one behavior focus per test; descriptive names with “given/when/then” wording.
- Reuse existing global mocks from
jest.setup.js; avoid introducing redundant native mocks. - Use fake timers only for timer-driven behavior; restore real timers per suite.
Execution Order
- Track B and Track C first (highest regression risk).
- Track D and Track E second (logic depth and form behavior).
- Track A and Track F last (API hardening + visual baseline).
Validation Checklist For Completion
- New/updated tests pass with
yarn test. - No brittle timer/race failures across reruns.
- Storybook snapshots are intentional and reviewed.
- Each new suite documents the user story it protects in test titles.
Behavior Map
flowchart TD
userAction[UserOrAPITrigger] --> showCall[showActionSheet]
showCall --> schedulePresent[SchedulePresent200ms]
schedulePresent --> trueSheetPresent[TrueSheetPresent]
trueSheetPresent --> sheetVisible[SheetVisible]
sheetVisible --> closePath[HandleCancelBackOrHide]
closePath --> trueSheetDismiss[TrueSheetDismiss]
trueSheetDismiss --> didDismiss[onDidDismiss]
didDismiss --> onCloseCallback[InvokeOnCloseCallback]
| Keyboard.dismiss(); | ||
| Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light); | ||
| onCloseSnapshotRef.current = options.onClose; | ||
| presentTimerRef.current = setTimeout(() => { |
There was a problem hiding this comment.
This timeout to open the action sheet is hurting the UX.
It causes the impression the app is not fast enough.
It also creates a potential race condition on onClose, since it's being changed 200ms before the action sheet is actually displayed.
diegolmello
left a comment
There was a problem hiding this comment.
Tests/stories aren't quite there.
Let's remove them and keep the rest of the code, which seems fine.
…Chat/Rocket.Chat.ReactNative into test.poc-a11y-bottom-shet
|
iOS Build Available Rocket.Chat Experimental 4.71.0.108407 |
|
Android Build Available Rocket.Chat Experimental 4.71.0.108406 Internal App Sharing: https://play.google.com/apps/test/RQVpXLytHNc/ahAO29uNRCrHsChPPjTJFDUezCdGLrhUeS36Gqdb1AY7ZDSF5CpfQHDE8i07FIV5X7829IoMOhZhuFMBpA3LbJc_B2 |
OtavioStasiak
left a comment
There was a problem hiding this comment.
LGTM! Tested on both platforms.
Proposed changes
Use react-native-true-sheet instead of the Discord bottom sheet, because react-native-true-sheet works as expected in accessibility (a11y) terms.
PS: GestureHandlerRootView defaults to
flex: 1, which causes it to expand and consume all available height inside the sheet, pushing the scrollable content area to zero. Setting flex: 0 pins the view to its intrinsic content size (only as tall as its children), so TrueSheet can correctly distribute space between the fixed header zone and the scrollable content below.Issue(s)
https://rocketchat.atlassian.net/browse/CORE-1809
How to test or reproduce
Screenshots
Types of changes
Checklist
Further comments
Summary by CodeRabbit
New Features
Improvements
Tests
Refactor