Skip to content

chore: bump react-native-permissions to 5.6.0 - #33597

Merged
adnxy merged 2 commits into
mainfrom
chore/bump-permissions
Jul 24, 2026
Merged

chore: bump react-native-permissions to 5.6.0#33597
adnxy merged 2 commits into
mainfrom
chore/bump-permissions

Conversation

@adnxy

@adnxy adnxy commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Pre-upgrade dependency bump for the RN 0.85 migration (Wave 4 — verified required). 3.7.2 is out of support and incompatible with the RN 0.85 toolchain; 5.6.0 is the validated target. Landing it now on 0.83 isolates any regression and gives it soak time on main.

Description

Bumps react-native-permissions from ^3.7.2 to ^5.6.0 as part of the incremental pre-upgrade dependency work for React Native 0.85.

Changes required by the v4/v5 API:

  • PERMISSIONS.IOS.BLUETOOTH_PERIPHERAL renamed to PERMISSIONS.IOS.BLUETOOTH — updated useBluetoothPermissions.ts, its test mock, and the global app/__mocks__/react-native-permissions.ts (Android constants unchanged)
  • iOS Podfile migrated from the per-permission pod (Permission-BluetoothPeripheral) to the v4+ setup_permissions(['Bluetooth']) flow — permission handlers are now compiled into RNPermissions directly
  • NSBluetoothAlwaysUsageDescription was already present in both Info.plists (required by the Bluetooth handler) — no plist change needed

Our only usage of this library is Bluetooth permissions for Ledger hardware wallet flows (useBluetoothPermissions, LedgerBluetoothAdapter).

Verified locally: yarn lint:tsc green, both consumer test suites pass (103 tests), pod install resolves cleanly (RNPermissions 5.6.0, Permission-BluetoothPeripheral pod removed).

Changelog

CHANGELOG entry: null

Related issues

Fixes:

Manual testing steps

Feature: Bluetooth permissions for Ledger

  Scenario: user connects a Ledger device
    Given the app is freshly installed
    When user starts the Ledger pairing flow
    Then the OS Bluetooth permission prompt appears
    And granting it allows device scanning to proceed on both iOS and Android

Screenshots/Recordings

N/A — dependency version bump, no visual changes expected.

Before

N/A

After

N/A

Pre-merge author checklist

Pre-merge reviewer checklist

  • I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed).
  • I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots.

Note

Medium Risk
Touches OS permission prompts for Ledger Bluetooth on iOS and changes native iOS pod wiring; scope is narrow but device manual testing is important.

Overview
Upgrades react-native-permissions from ^3.7.2 to ^5.6.0 ahead of the RN 0.85 migration, with lockfile and iOS pod updates (RNPermissions 5.6.0).

For v4/v5 breaking changes, iOS Bluetooth permission requests now use PERMISSIONS.IOS.BLUETOOTH instead of BLUETOOTH_PERIPHERAL in useBluetoothPermissions and in Jest mocks. Android permission usage is unchanged.

On iOS, the Podfile drops the Permission-BluetoothPeripheral subpod and adopts setup_permissions(['Bluetooth']) so the Bluetooth handler is built into RNPermissions.

Reviewed by Cursor Bugbot for commit f27627c. Bugbot is set up for automated code reviews on this repo. Configure here.

@github-actions

Copy link
Copy Markdown
Contributor

CLA Signature Action: All authors have signed the CLA. You may need to manually re-run the blocking PR check if it doesn't pass in a few minutes.

@github-actions github-actions Bot added the pr-not-ready-for-e2e Skip E2E and block merging. Remove this label once the PR is ready to run the E2E tests. label Jul 21, 2026
@adnxy adnxy self-assigned this Jul 21, 2026
@adnxy adnxy added team-mobile-platform Mobile Platform team size-S and removed pr-not-ready-for-e2e Skip E2E and block merging. Remove this label once the PR is ready to run the E2E tests. labels Jul 21, 2026
@metamask-ci

metamask-ci Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

PR template — items to address before "Ready for review"

Warnings — informational, address before merging:

  • Related issues section is empty. Add Fixes: #123 / Closes: <URL> / Refs: <Jira key>, or write a short rationale after the colon.
  • Pre-merge author checklist has only 5 of the required 8 items. Every checklist row must be present and consciously checked — do not delete rows.

See docs/readme/ready-for-review.md for the full Definition of Ready for Review.

@socket-security

socket-security Bot commented Jul 21, 2026

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Updatednpm/​react-native-permissions@​3.10.1 ⏵ 5.6.0100 +110010091100

View full report

@github-actions

github-actions Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

🧪 Flaky unit test detection

Run history flaky detection

View recent run history

Historical failure rate is a hint, not proof — review each suggestion in context. See the flaky-test-detection skill for the full pattern reference and manual audit workflow.

Failures / runs sampled per window:

File 7d 15d 30d
app/components/hooks/useBluetoothPermissions.test.ts 0/159 0/191 0/334

AI-detected flaky patterns

app/components/hooks/useBluetoothPermissions.test.ts

  • J10 — jest.spyOn without restoreAllMocks() (medium)
    • jest.spyOn(AppState, 'addEventListener') replaces the real implementation with a spy. jest.resetAllMocks() resets call counts and return values but does NOT restore the original implementation — the spy persists for the entire Jest worker lifetime. Any test that runs after this suite (or a future test added to this file) that relies on the real AppState.addEventListener will silently receive the spy instead of the original. Adding jest.restoreAllMocks() in an afterEach ensures the original is restored after every test.
    • Suggested fix in app/components/hooks/useBluetoothPermissions.test.ts:47:
      -  beforeEach(() => {
      -    jest.resetAllMocks();
      -    jest.spyOn(AppState, 'addEventListener').mockReturnValue({
      -      remove: jest.fn(),
      -    } as unknown as ReturnType<typeof AppState.addEventListener>);
      -  });
      +  beforeEach(() => {
      +    jest.resetAllMocks();
      +    jest.spyOn(AppState, 'addEventListener').mockReturnValue({
      +      remove: jest.fn(),
      +    } as unknown as ReturnType<typeof AppState.addEventListener>);
      +  });
      +
      +  afterEach(() => {
      +    jest.restoreAllMocks();
      +  });
  • J1 — Synchronous act() wrapping an async state-updating callback (critical)
    • The AppState change handler triggered here calls requestMultiple(), which is mocked with .mockResolvedValue(...) — a Promise. The Promise resolution and any resulting hook state updates are microtasks that execute after the synchronous act() completes. React will emit 'not wrapped in act()' warnings and the assertion on call count may race against those pending updates, producing intermittent failures under load. The test function must be made async and act() must be awaited as async so all microtasks are flushed before the assertion runs.
    • Suggested fix in app/components/hooks/useBluetoothPermissions.test.ts:153:
      -  it('checks permissions when app state changes to active', () => {
      -    (Device.isAndroid as jest.Mock).mockReturnValue(true);
      -    (getSystemVersion as jest.Mock).mockReturnValue('12');
      -    (requestMultiple as jest.Mock).mockResolvedValue({
      -      [PERMISSIONS.ANDROID.BLUETOOTH_CONNECT]: RESULTS.GRANTED,
      -      [PERMISSIONS.ANDROID.BLUETOOTH_SCAN]: RESULTS.GRANTED,
      -    });
      -
      -    AppState.currentState = 'background';
      -    renderHook(() => useBluetoothPermissions());
      -    //checkPermission run once when hook is mounted
      -    expect(requestMultiple).toHaveBeenCalledTimes(1);
      -
      -    act(() => {
      -      (AppState.addEventListener as jest.Mock).mock.calls[0][1]('active');
      -    });
      -
      -    //checkPermission run again when app state changes to active
      -    expect(requestMultiple).toHaveBeenCalledTimes(2);
      -  });
      +  it('checks permissions when app state changes to active', async () => {
      +    (Device.isAndroid as jest.Mock).mockReturnValue(true);
      +    (getSystemVersion as jest.Mock).mockReturnValue('12');
      +    (requestMultiple as jest.Mock).mockResolvedValue({
      +      [PERMISSIONS.ANDROID.BLUETOOTH_CONNECT]: RESULTS.GRANTED,
      +      [PERMISSIONS.ANDROID.BLUETOOTH_SCAN]: RESULTS.GRANTED,
      +    });
      +
      +    AppState.currentState = 'background';
      +    renderHook(() => useBluetoothPermissions());
      +    //checkPermission run once when hook is mounted
      +    expect(requestMultiple).toHaveBeenCalledTimes(1);
      +
      +    await act(async () => {
      +      (AppState.addEventListener as jest.Mock).mock.calls[0][1]('active');
      +    });
      +
      +    //checkPermission run again when app state changes to active
      +    expect(requestMultiple).toHaveBeenCalledTimes(2);
      +  });
  • J1 — Synchronous act() wrapping an async state-updating callback (critical)
    • Same J1 pattern as the previous test: the AppState change handler is async (calls requestMultiple which returns a Promise via mockResolvedValue), but act() is synchronous. Any state updates from the resolved promise escape the act() boundary, causing potential 'not wrapped in act()' warnings and order-dependent assertion results. The test function must be made async and act() must be awaited as async.
    • Suggested fix in app/components/hooks/useBluetoothPermissions.test.ts:173:
      -  it('does not check permissions when app state changes to background', () => {
      -    (Device.isAndroid as jest.Mock).mockReturnValue(true);
      -    (getSystemVersion as jest.Mock).mockReturnValue('12');
      -    (requestMultiple as jest.Mock).mockResolvedValue({
      -      [PERMISSIONS.ANDROID.BLUETOOTH_CONNECT]: RESULTS.GRANTED,
      -      [PERMISSIONS.ANDROID.BLUETOOTH_SCAN]: RESULTS.GRANTED,
      -    });
      -
      -    AppState.currentState = 'background';
      -    renderHook(() => useBluetoothPermissions());
      -    //checkPermission run once when hook is mounted
      -    expect(requestMultiple).toHaveBeenCalledTimes(1);
      -
      -    act(() => {
      -      (AppState.addEventListener as jest.Mock).mock.calls[0][1]('inactive');
      -    });
      -
      -    //checkPermission does not run when app state changes to inactive
      -    expect(requestMultiple).toHaveBeenCalledTimes(1);
      -  });
      +  it('does not check permissions when app state changes to background', async () => {
      +    (Device.isAndroid as jest.Mock).mockReturnValue(true);
      +    (getSystemVersion as jest.Mock).mockReturnValue('12');
      +    (requestMultiple as jest.Mock).mockResolvedValue({
      +      [PERMISSIONS.ANDROID.BLUETOOTH_CONNECT]: RESULTS.GRANTED,
      +      [PERMISSIONS.ANDROID.BLUETOOTH_SCAN]: RESULTS.GRANTED,
      +    });
      +
      +    AppState.currentState = 'background';
      +    renderHook(() => useBluetoothPermissions());
      +    //checkPermission run once when hook is mounted
      +    expect(requestMultiple).toHaveBeenCalledTimes(1);
      +
      +    await act(async () => {
      +      (AppState.addEventListener as jest.Mock).mock.calls[0][1]('inactive');
      +    });
      +
      +    //checkPermission does not run when app state changes to inactive
      +    expect(requestMultiple).toHaveBeenCalledTimes(1);
      +  });

This check is informational only and does not block merging.

@adnxy
adnxy marked this pull request as ready for review July 21, 2026 14:14
@adnxy
adnxy requested a review from a team as a code owner July 21, 2026 14:14
@adnxy
adnxy force-pushed the chore/bump-permissions branch from b1bcd52 to 817675b Compare July 21, 2026 14:15
@github-actions github-actions Bot added the risk:low AI analysis: low risk label Jul 21, 2026
@sonarqubecloud

Copy link
Copy Markdown

@adnxy
adnxy force-pushed the chore/bump-permissions branch from 817675b to f27627c Compare July 21, 2026 15:52
@github-actions github-actions Bot added risk:high AI analysis: high risk and removed risk:low AI analysis: low risk labels Jul 21, 2026
@github-actions

Copy link
Copy Markdown
Contributor

🔍 Smart E2E Test Selection

  • Selected E2E tags: SmokeAccounts, SmokeConfirmations, SmokeNetworkAbstractions, SmokeNetworkExpansion, SmokeSwap, SmokeStake, SmokeWalletPlatform, SmokeMoney, SmokePerps, SmokeMultiChainAPI, SmokePredictions, SmokeSeedlessOnboarding, SmokeBrowser, SmokeSnaps
  • Selected Performance tags: None (no tests recommended)
  • Risk Level: high
  • AI Confidence: 100%
click to see 🤖 AI reasoning details

E2E Test Selection:
Hard rule (global-infrastructure-change): Global infrastructure changed: app/components/hooks/useBluetoothPermissions.test.ts, app/components/hooks/useBluetoothPermissions.ts. Running all tests.

Performance Test Selection:
The changes are limited to iOS Bluetooth permission API updates and a dependency upgrade for react-native-permissions. No performance-sensitive code paths (app launch, login, onboarding, asset loading, swaps, etc.) are affected. No performance test tags are warranted.

View GitHub Actions results

@adnxy
adnxy requested review from Cal-L, tommasini and weitingsun July 22, 2026 12:53
@adnxy
adnxy added this pull request to the merge queue Jul 24, 2026
Merged via the queue into main with commit 4c8c49d Jul 24, 2026
192 of 194 checks passed
@adnxy
adnxy deleted the chore/bump-permissions branch July 24, 2026 14:22
@github-actions github-actions Bot locked and limited conversation to collaborators Jul 24, 2026
@metamask-ci metamask-ci Bot added the release-8.6.0 Issue or pull request that will be included in release 8.6.0 label Jul 24, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

release-8.6.0 Issue or pull request that will be included in release 8.6.0 risk:high AI analysis: high risk size-S team-mobile-platform Mobile Platform team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants