Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/android-tab-test-ids.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"react-native-bottom-tabs": patch
"@bottom-tabs/react-navigation": patch
---

Expose Android tab button test IDs to UIAutomator-based E2E tools.
20 changes: 20 additions & 0 deletions apps/example/e2e/native-tabs-test-id.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
appId: bottomtabs.example
name: Navigate tabs via testIDs
---
- launchApp
- scrollUntilVisible:
element:
text: ^Native Bottom Tabs$
direction: DOWN
timeout: 15000
- tapOn:
text: ^Native Bottom Tabs$
- assertVisible: Press me
- tapOn:
id: articleTestID
- assertVisible: What is Lorem Ipsum?
- tapOn:
id: albumsTestID
- tapOn:
id: chatTestID
- assertVisible: Press me
2 changes: 2 additions & 0 deletions apps/example/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
"build:android": "npm run mkdist && react-native bundle --entry-file index.js --platform android --dev true --bundle-output dist/main.android.jsbundle --assets-dest dist && react-native build-android --extra-params \"--no-daemon --console=plain -PreactNativeArchitectures=arm64-v8a -PnewArchEnabled=true\"",
"build:ios": "npm run mkdist && react-native bundle --entry-file index.js --platform ios --dev true --bundle-output dist/main.ios.jsbundle --assets-dest dist",
"ios": "react-native run-ios",
"e2e:ios": "maestro test --platform=ios e2e",
"e2e:android": "maestro test --platform=android e2e",
"mkdist": "node -e \"require('node:fs').mkdirSync('dist', { recursive: true, mode: 0o755 })\"",
"start": "react-native start"
},
Expand Down
3 changes: 3 additions & 0 deletions apps/example/src/Examples/NativeBottomTabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ function NativeBottomTabs() {
name="Albums"
component={Albums}
options={{
tabBarButtonTestID: 'albumsTestID',
tabBarIcon: () => require('../../assets/icons/grid_dark.png'),
}}
/>
Expand All @@ -72,6 +73,7 @@ function NativeBottomTabs() {
},
}}
options={{
tabBarButtonTestID: 'contactsTestID',
tabBarIcon: () => require('../../assets/icons/person_dark.png'),
tabBarActiveTintColor: 'yellow',
preventsDefault: true,
Expand All @@ -86,6 +88,7 @@ function NativeBottomTabs() {
},
}}
options={{
tabBarButtonTestID: 'chatTestID',
tabBarIcon: () => require('../../assets/icons/chat_dark.png'),
tabBarActiveTintColor: 'white',
}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@ import android.view.ViewGroup
import android.widget.FrameLayout
import android.widget.LinearLayout
import android.widget.TextView
import androidx.core.view.AccessibilityDelegateCompat
import androidx.core.view.MenuItemCompat
import androidx.core.view.ViewCompat
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat
import androidx.core.view.forEachIndexed
import coil3.ImageLoader
import coil3.asDrawable
Expand Down Expand Up @@ -281,12 +284,8 @@ class ReactBottomNavigationView(context: Context) : LinearLayout(context) {
onTabSelected(menuItem)
}

item.testID?.let { testId ->
view.findViewById<View>(com.google.android.material.R.id.navigation_bar_item_content_container)
?.apply {
tag = testId
}
}
view.findViewById<View>(com.google.android.material.R.id.navigation_bar_item_content_container)
?.setTabTestID(item.testID)
}
}
}
Expand All @@ -301,6 +300,24 @@ class ReactBottomNavigationView(context: Context) : LinearLayout(context) {
return bottomNavigation.menu.findItem(index) ?: bottomNavigation.menu.add(0, index, 0, title)
}

private fun View.setTabTestID(testId: String?) {
tag = testId
if (testId == null) {
ViewCompat.setAccessibilityDelegate(this, null)
return
}

ViewCompat.setAccessibilityDelegate(this, object : AccessibilityDelegateCompat() {
override fun onInitializeAccessibilityNodeInfo(
host: View,
info: AccessibilityNodeInfoCompat
) {
super.onInitializeAccessibilityNodeInfo(host, info)
info.viewIdResourceName = testId
}
})
}

private fun updateIconTintMode(menuItem: MenuItem, item: TabInfo) {
MenuItemCompat.setIconTintMode(
menuItem,
Expand Down
Loading