Skip to content

refactor: simplify native tab bridge#2

Merged
DjDeveloperr merged 7 commits into
mainfrom
codex/simplify-native-apis
May 27, 2026
Merged

refactor: simplify native tab bridge#2
DjDeveloperr merged 7 commits into
mainfrom
codex/simplify-native-apis

Conversation

@DjDeveloperr
Copy link
Copy Markdown
Owner

@DjDeveloperr DjDeveloperr commented May 27, 2026

Summary

  • simplify the native tab controller bridge by replacing custom ObjC target/delegate plumbing with ctx.delegate() and ctx.targetAction()
  • add a SimDeck E2E test that launches the simulator app, verifies Wallet/PDF/Scanner tab behavior, and rapid-switches tabs
  • extend macOS CI to build the simulator app, start Metro, install the app through SimDeck, and run the E2E test

Validation

  • npm test
  • npm run build:ios:ci
  • SIMDECK_UDID=7321BC96-CD84-42E8-B183-3F8D40B0A482 npm run test:e2e

Summary by CodeRabbit

  • Tests

    • Added end-to-end tests validating native tab flows (Wallet, PDF, Scanner), app launch/install behavior, simulator boot selection, and repeated tab responsiveness on iOS.
  • Refactor

    • Simplified native tab controller and accessory handling for more immediate selection updates, cleaner delegate wiring, and reduced cleanup complexity.
  • Chores

    • Integrated E2E execution into iOS CI, added npm scripts for E2E/CI/demo/web runs, and included tooling support for simulator orchestration.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 27, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds SimDeck-driven iOS E2E test and CI wiring; refactors utils/native-tabs to use UIKit view context (ctx) for delegate and accessory wiring, removing the ObjC retainer/target bridge.

Changes

E2E Testing and Native Tabs

Layer / File(s) Summary
E2E Test Infrastructure: CI Workflow and Package Scripts
.github/workflows/ci.yml, package.json
iOS CI step renamed to include E2E; new Run SimDeck E2E step starts Metro, polls the Expo iOS bundle URL, resolves NativeScriptRN.app in DerivedData, selects/boots an iPhone simulator via simctl, and runs npm run test:e2e. package.json adds test:e2e, build:ios:ci, pass:build, web, private: true, and optionalDependencies.simdeck.
E2E Test Implementation: SimDeck Tab Verification
e2e/native-tabs.simdeck.test.mjs
Adds SimDeck Node test that connects to SimDeck, selects/boots an iPhone simulator, optionally installs app from E2E_APP_PATH, launches bundle ID, waits for initial native UI, selects/asserts Wallet/PDF/Scanner tabs (regex for Scanner), cycles tab taps to verify responsiveness, and ensures simdeck.close() in finally. Helpers for selectTab, tapTab, selectBootedIphone, isIphone, and localPath included.
UIKit Context Types and Imports
utils/native-tabs.ts
Adds defineUIViewController and UIKitViewContext imports; introduces NativeTabBarContext; simplifies TabBarControllerWithState and AccessoryButtonWithState state fields; removes ObjC bridge (nativeRetainers and target class).
Accessory Button Context Wiring
utils/native-tabs.ts
configureTabBarController accepts optional ctx?: NativeTabBarContext. configureBottomAccessory rewritten to require ctx when creating an accessory, wiring press via ctx.targetAction, checking ctx.props.accessory and disabled state, and forwarding onPress via promise with logError on rejection.
Tab Controller Delegate and Selection Refactoring
utils/native-tabs.ts
NativeTabBarController.createController now takes ctx; delegate wiring uses ctx.delegate(...); selection updates nativeSelectedIndex and immediately emits onSelect via ctx.emit, removing pending/timer propagation; disposal clears delegate and accessory/selection state without timer/retainer cleanup.
Navigation Container Updates and Export Cleanup
utils/native-tabs.ts
Removes exported NativeNavigationStack; updates NativeNavigationContainer.update to call configureNavigationTitle instead of configureNavigationStack.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐰 Metro hums beneath the tree,
SimDeck taps — the tests run free,
Tabs hop Wallet, PDF, and Scan,
ctx wires buttons hand in hand,
Hop, verify, and sip carrot tea!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title 'refactor: simplify native tab bridge' accurately reflects the main change: refactoring the native tab controller bridge to use simplified ctx.delegate() and ctx.targetAction() instead of custom ObjC plumbing, as shown in the utils/native-tabs.ts changes.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/simplify-native-apis

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
utils/native-tabs.ts (1)

114-129: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Sync controlled selectedIndex updates after the first render.

After nativeSelectedIndex is initialized, this branch stops applying later in-range props.selectedIndex changes, so JS-driven tab switches no longer propagate to UITabBarController. That's a controlled-state regression.

Proposed fix
   if (props.items.length > 0) {
     const selectedIndex = clampSelectedIndex(
       props.selectedIndex,
       props.items.length,
     );
-    const needsNativeSelection =
-      didRebuildItems ||
-      controller.nativeSelectedIndex === undefined ||
-      controller.nativeSelectedIndex >= props.items.length;
+    const needsNativeSelection =
+      didRebuildItems || controller.nativeSelectedIndex !== selectedIndex;
 
     if (needsNativeSelection && controller.selectedIndex !== selectedIndex) {
       controller.selectedIndex = selectedIndex;
     }
     if (needsNativeSelection) {
       controller.nativeSelectedIndex = selectedIndex;
     }
   }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@utils/native-tabs.ts` around lines 114 - 129, The branch currently only
updates controller.selectedIndex when needsNativeSelection is true, which
prevents later in-range props.selectedIndex changes from propagating; change the
logic so that after computing selectedIndex (via clampSelectedIndex), you always
sync controller.selectedIndex when it differs from selectedIndex (regardless of
needsNativeSelection) and only set controller.nativeSelectedIndex when the
existing native selection truly needs initialization or repair (i.e., keep the
existing needsNativeSelection check for assigning
controller.nativeSelectedIndex); update the block around
clampSelectedIndex/needsNativeSelection to first compare and assign
controller.selectedIndex if different, then conditionally assign
controller.nativeSelectedIndex when needsNativeSelection.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@utils/native-tabs.ts`:
- Around line 114-129: The branch currently only updates
controller.selectedIndex when needsNativeSelection is true, which prevents later
in-range props.selectedIndex changes from propagating; change the logic so that
after computing selectedIndex (via clampSelectedIndex), you always sync
controller.selectedIndex when it differs from selectedIndex (regardless of
needsNativeSelection) and only set controller.nativeSelectedIndex when the
existing native selection truly needs initialization or repair (i.e., keep the
existing needsNativeSelection check for assigning
controller.nativeSelectedIndex); update the block around
clampSelectedIndex/needsNativeSelection to first compare and assign
controller.selectedIndex if different, then conditionally assign
controller.nativeSelectedIndex when needsNativeSelection.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 90d4eac9-40e0-41bf-828d-b84d7ce5a26f

📥 Commits

Reviewing files that changed from the base of the PR and between 9996335 and 7abaff1.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (4)
  • .github/workflows/ci.yml
  • e2e/native-tabs.simdeck.test.mjs
  • package.json
  • utils/native-tabs.ts

@DjDeveloperr DjDeveloperr merged commit 2ecd47a into main May 27, 2026
3 checks passed
@DjDeveloperr DjDeveloperr deleted the codex/simplify-native-apis branch May 27, 2026 20:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant