diff --git a/.maestro/helpers/assert-room-title.yaml b/.maestro/helpers/assert-room-title.yaml
new file mode 100644
index 00000000000..183c4e2556a
--- /dev/null
+++ b/.maestro/helpers/assert-room-title.yaml
@@ -0,0 +1,23 @@
+appId: ${APP_ID}
+name: Assert room title
+tags:
+ - 'util'
+
+---
+- runFlow:
+ when:
+ platform: Android
+ commands:
+ - extendedWaitUntil:
+ visible:
+ id: 'room-view-title-${ROOM}'
+ timeout: 60000
+
+- runFlow:
+ when:
+ platform: iOS
+ commands:
+ - extendedWaitUntil:
+ visible:
+ text: '${ROOM}'
+ timeout: 60000
diff --git a/.maestro/helpers/clear-search-field.yaml b/.maestro/helpers/clear-search-field.yaml
new file mode 100644
index 00000000000..3ee551c0df0
--- /dev/null
+++ b/.maestro/helpers/clear-search-field.yaml
@@ -0,0 +1,18 @@
+appId: ${APP_ID}
+name: Clear search field
+tags:
+ - 'util'
+---
+- runFlow:
+ when:
+ platform: iOS
+ commands:
+ - tapOn:
+ id: 'magnifyingglass'
+ - eraseText
+- runFlow:
+ when:
+ platform: android
+ commands:
+ - tapOn:
+ id: clear-text-input
diff --git a/.maestro/helpers/close-search.yaml b/.maestro/helpers/close-search.yaml
new file mode 100644
index 00000000000..db6560964fd
--- /dev/null
+++ b/.maestro/helpers/close-search.yaml
@@ -0,0 +1,13 @@
+appId: ${APP_ID}
+name: Close search
+tags:
+ - 'util'
+---
+- runFlow:
+ when:
+ platform: iOS
+ visible:
+ text: 'Close'
+ commands:
+ - tapOn:
+ text: 'Close'
diff --git a/.maestro/helpers/go-back.yaml b/.maestro/helpers/go-back.yaml
index 667f678c475..81fd69def37 100644
--- a/.maestro/helpers/go-back.yaml
+++ b/.maestro/helpers/go-back.yaml
@@ -6,16 +6,15 @@ tags:
---
- runFlow:
when:
- visible:
- id: 'custom-header-back'
+ platform: Android
commands:
- tapOn:
- id: 'custom-header-back'
+ id: '(custom-)?header-back'
- runFlow:
when:
- visible:
- id: 'header-back'
+ platform: iOS
commands:
- tapOn:
- id: 'header-back'
+ text: 'Back(, .*)?'
+ retryTapIfNoChange: true
diff --git a/.maestro/helpers/logout.yaml b/.maestro/helpers/logout.yaml
index 70ddc19cfb7..b19b9eba4ee 100644
--- a/.maestro/helpers/logout.yaml
+++ b/.maestro/helpers/logout.yaml
@@ -14,12 +14,22 @@ tags:
- runFlow:
when:
+ platform: Android
visible:
id: 'rooms-list-view-sidebar'
commands:
- tapOn:
id: 'rooms-list-view-sidebar'
+- runFlow:
+ when:
+ platform: iOS
+ visible:
+ text: 'Menu'
+ commands:
+ - tapOn:
+ text: 'Menu'
+
- runFlow:
when:
platform: Android
diff --git a/.maestro/helpers/navigate-to-recent-room.yaml b/.maestro/helpers/navigate-to-recent-room.yaml
index fdfc1057707..5da07125d33 100644
--- a/.maestro/helpers/navigate-to-recent-room.yaml
+++ b/.maestro/helpers/navigate-to-recent-room.yaml
@@ -8,19 +8,23 @@ tags:
visible:
id: 'rooms-list-view'
timeout: 60000
-- tapOn:
- id: 'rooms-list-view-search'
-- extendedWaitUntil:
- visible:
- id: 'rooms-list-view-search-input'
- timeout: 60000
+- runFlow:
+ when:
+ platform: android
+ commands:
+ - tapOn:
+ id: 'rooms-list-view-search'
+ - extendedWaitUntil:
+ visible:
+ id: 'rooms-list-view-search-input'
+ timeout: 60000
- extendedWaitUntil:
visible:
id: 'rooms-list-view-item-${ROOM}'
timeout: 60000
- tapOn:
id: 'rooms-list-view-item-${ROOM}'
-- extendedWaitUntil:
- visible:
- id: 'room-view-title-${ROOM}'
- timeout: 60000
+- runFlow:
+ file: 'assert-room-title.yaml'
+ env:
+ ROOM: ${ROOM}
diff --git a/.maestro/helpers/navigate-to-room-action.yaml b/.maestro/helpers/navigate-to-room-action.yaml
index 08a0dfeb718..f9367ee7fd3 100644
--- a/.maestro/helpers/navigate-to-room-action.yaml
+++ b/.maestro/helpers/navigate-to-room-action.yaml
@@ -18,13 +18,5 @@ tags:
visible:
id: 'room-view'
timeout: 60000
-- assertVisible:
- id: 'room-header'
- index: 0
-- tapOn:
- id: 'room-header'
- index: 0
-- extendedWaitUntil:
- visible:
- id: 'room-actions-view'
- timeout: 60000
+
+- runFlow: './open-room-actions.yaml'
diff --git a/.maestro/helpers/navigate-to-room.yaml b/.maestro/helpers/navigate-to-room.yaml
index e8eba0728b0..af619b5da61 100644
--- a/.maestro/helpers/navigate-to-room.yaml
+++ b/.maestro/helpers/navigate-to-room.yaml
@@ -4,6 +4,7 @@ tags:
- 'util'
---
+- runFlow: './pop-to-rooms-list.yaml'
- waitForAnimationToEnd
- scrollUntilVisible:
element:
@@ -11,7 +12,7 @@ tags:
- waitForAnimationToEnd
- tapOn:
id: 'rooms-list-view-item-${ROOM}'
-- extendedWaitUntil:
- visible:
- id: 'room-view-title-${ROOM}'
- timeout: 60000
+- runFlow:
+ file: 'assert-room-title.yaml'
+ env:
+ ROOM: ${ROOM}
diff --git a/.maestro/helpers/open-room-actions.yaml b/.maestro/helpers/open-room-actions.yaml
new file mode 100644
index 00000000000..e351514fbfc
--- /dev/null
+++ b/.maestro/helpers/open-room-actions.yaml
@@ -0,0 +1,18 @@
+appId: ${APP_ID}
+name: Open room actions
+tags:
+ - 'util'
+
+---
+- extendedWaitUntil:
+ visible:
+ id: 'room-header'
+ timeout: 60000
+- tapOn:
+ id: 'room-header'
+ index: 0
+ retryTapIfNoChange: true
+- extendedWaitUntil:
+ visible:
+ id: 'room-actions-view'
+ timeout: 60000
diff --git a/.maestro/helpers/open-servers-list.yaml b/.maestro/helpers/open-servers-list.yaml
new file mode 100644
index 00000000000..d0fbb379500
--- /dev/null
+++ b/.maestro/helpers/open-servers-list.yaml
@@ -0,0 +1,12 @@
+appId: ${APP_ID}
+name: Open servers list
+tags:
+ - 'util'
+
+---
+- extendedWaitUntil:
+ visible:
+ id: 'rooms-list-header-servers-list-button'
+ timeout: 60000
+- tapOn:
+ id: 'rooms-list-header-servers-list-button'
diff --git a/.maestro/helpers/pop-to-rooms-list.yaml b/.maestro/helpers/pop-to-rooms-list.yaml
new file mode 100644
index 00000000000..1e8fb0abeb0
--- /dev/null
+++ b/.maestro/helpers/pop-to-rooms-list.yaml
@@ -0,0 +1,30 @@
+appId: ${APP_ID}
+name: Pop to rooms list
+tags:
+ - 'util'
+
+---
+- repeat:
+ times: 4
+ while:
+ notVisible:
+ id: 'rooms-list-view'
+ commands:
+ - runFlow:
+ when:
+ platform: Android
+ visible:
+ id: '(custom-)?header-back'
+ commands:
+ - tapOn:
+ id: '(custom-)?header-back'
+ - runFlow:
+ when:
+ platform: iOS
+ visible:
+ text: 'Back(, .*)?'
+ commands:
+ - tapOn:
+ text: 'Back(, .*)?'
+ - waitForAnimationToEnd:
+ timeout: 5000
diff --git a/.maestro/helpers/search-room.yaml b/.maestro/helpers/search-room.yaml
index 6314ba6f9af..17dfdc0668f 100644
--- a/.maestro/helpers/search-room.yaml
+++ b/.maestro/helpers/search-room.yaml
@@ -3,18 +3,31 @@ name: Search room
tags:
- 'util'
---
+- runFlow: './pop-to-rooms-list.yaml'
- extendedWaitUntil:
visible:
id: 'rooms-list-view'
timeout: 60000
- waitForAnimationToEnd:
timeout: 5000
-- tapOn:
- id: 'rooms-list-view-search'
-- tapOn:
- id: 'rooms-list-view-search-input'
-- inputText:
- text: ${ROOM}
+- runFlow:
+ when:
+ platform: iOS
+ commands:
+ - tapOn:
+ id: 'magnifyingglass'
+ - inputText:
+ text: ${ROOM}
+- runFlow:
+ when:
+ platform: android
+ commands:
+ - tapOn:
+ id: 'rooms-list-view-search'
+ - tapOn:
+ id: 'rooms-list-view-search-input'
+ - inputText:
+ text: ${ROOM}
- extendedWaitUntil:
visible:
id: 'rooms-list-view-item-${ROOM}'
diff --git a/.maestro/helpers/select-header-filter.yaml b/.maestro/helpers/select-header-filter.yaml
new file mode 100644
index 00000000000..7a577c1cd3d
--- /dev/null
+++ b/.maestro/helpers/select-header-filter.yaml
@@ -0,0 +1,37 @@
+appId: ${APP_ID}
+name: Select header filter
+tags:
+ - 'util'
+---
+- runFlow:
+ when:
+ platform: iOS
+ commands:
+ - extendedWaitUntil:
+ visible:
+ text: 'Filter'
+ timeout: 60000
+ - tapOn:
+ text: 'Filter'
+ - extendedWaitUntil:
+ visible:
+ text: ${IOS_OPTION}
+ timeout: 60000
+ - tapOn:
+ text: ${IOS_OPTION}
+- runFlow:
+ when:
+ platform: android
+ commands:
+ - extendedWaitUntil:
+ visible:
+ id: ${ANDROID_FILTER_ID}
+ timeout: 60000
+ - tapOn:
+ id: ${ANDROID_FILTER_ID}
+ - extendedWaitUntil:
+ visible:
+ id: ${ANDROID_OPTION_ID}
+ timeout: 60000
+ - tapOn:
+ id: ${ANDROID_OPTION_ID}
diff --git a/.maestro/helpers/tap-header-item.yaml b/.maestro/helpers/tap-header-item.yaml
new file mode 100644
index 00000000000..963ba9f797c
--- /dev/null
+++ b/.maestro/helpers/tap-header-item.yaml
@@ -0,0 +1,21 @@
+appId: ${APP_ID}
+name: Tap header item
+tags:
+ - 'util'
+
+---
+# iOS native header items (unstable_headerLeftItems/RightItems) carry no accessibilityIdentifier,
+# only a label. Android keeps the JS-rendered header, matched by testID as before.
+- runFlow:
+ when:
+ platform: Android
+ commands:
+ - tapOn:
+ id: ${ANDROID_ID}
+
+- runFlow:
+ when:
+ platform: iOS
+ commands:
+ - tapOn:
+ text: ${IOS_LABEL}
diff --git a/.maestro/helpers/tap-search-field.yaml b/.maestro/helpers/tap-search-field.yaml
new file mode 100644
index 00000000000..a2f14c3f691
--- /dev/null
+++ b/.maestro/helpers/tap-search-field.yaml
@@ -0,0 +1,33 @@
+appId: ${APP_ID}
+name: Tap search field
+tags:
+ - 'util'
+---
+- runFlow:
+ when:
+ platform: iOS
+ commands:
+ - runFlow:
+ when:
+ notVisible:
+ id: 'magnifyingglass'
+ commands:
+ - swipe:
+ start: 50%, 30%
+ end: 50%, 60%
+ - extendedWaitUntil:
+ visible:
+ id: 'magnifyingglass'
+ timeout: 60000
+ - tapOn:
+ id: 'magnifyingglass'
+- runFlow:
+ when:
+ platform: android
+ commands:
+ - extendedWaitUntil:
+ visible:
+ id: ${SEARCH_ID}
+ timeout: 60000
+ - tapOn:
+ id: ${SEARCH_ID}
diff --git a/.maestro/helpers/wait-header-item.yaml b/.maestro/helpers/wait-header-item.yaml
new file mode 100644
index 00000000000..7046e125b3c
--- /dev/null
+++ b/.maestro/helpers/wait-header-item.yaml
@@ -0,0 +1,23 @@
+appId: ${APP_ID}
+name: Wait for header item
+tags:
+ - 'util'
+
+---
+- runFlow:
+ when:
+ platform: Android
+ commands:
+ - extendedWaitUntil:
+ visible:
+ id: ${ANDROID_ID}
+ timeout: 60000
+
+- runFlow:
+ when:
+ platform: iOS
+ commands:
+ - extendedWaitUntil:
+ visible:
+ text: ${IOS_LABEL}
+ timeout: 60000
diff --git a/.maestro/tests/accessibilityAndAppearance/ToastsAndDialogs.yml b/.maestro/tests/accessibilityAndAppearance/ToastsAndDialogs.yml
index a2bf50b79a6..17c2280bfdc 100644
--- a/.maestro/tests/accessibilityAndAppearance/ToastsAndDialogs.yml
+++ b/.maestro/tests/accessibilityAndAppearance/ToastsAndDialogs.yml
@@ -18,11 +18,27 @@ tags:
# Show alerts as Toasts
- tapOn: 'Menu'
- tapOn: 'Accessibility & appearance'
-- tapOn: '.*Show alerts as.*'
-- assertVisible: 'Toasts. Dismissed automatically. Checked'
-- assertVisible: 'Dialogs. Require manual dismissal. Unchecked'
-- tapOn:
- id: 'action-sheet-handle'
+- runFlow:
+ when:
+ platform: iOS
+ commands:
+ - tapOn: 'Toasts'
+ - assertVisible:
+ text: 'Toasts'
+ selected: true
+ - assertVisible:
+ text: 'Dialogs'
+ selected: false
+ - tapOn: 'Toasts'
+- runFlow:
+ when:
+ platform: Android
+ commands:
+ - tapOn: '.*Show alerts as.*'
+ - assertVisible: 'Toasts. Dismissed automatically. Checked'
+ - assertVisible: 'Dialogs. Require manual dismissal. Unchecked'
+ - tapOn:
+ id: 'action-sheet-handle'
- waitForAnimationToEnd:
timeout: 5000
- tapOn: 'Menu'
@@ -37,9 +53,23 @@ tags:
# Show alerts as Dialogs
- tapOn: 'Accessibility & appearance'
-- tapOn: '.*Show alerts as.*'
-- assertVisible: 'Toasts. Dismissed automatically. Checked'
-- tapOn: 'Dialogs. Require manual dismissal. Unchecked'
+- runFlow:
+ when:
+ platform: iOS
+ commands:
+ - tapOn: 'Toasts'
+ - assertVisible:
+ text: 'Toasts'
+ selected: true
+ - tapOn: 'Dialogs'
+ - assertVisible: 'Dialogs'
+- runFlow:
+ when:
+ platform: Android
+ commands:
+ - tapOn: '.*Show alerts as.*'
+ - assertVisible: 'Toasts. Dismissed automatically. Checked'
+ - tapOn: 'Dialogs. Require manual dismissal. Unchecked'
- tapOn: 'Menu'
- tapOn: 'Edit status'
- tapOn:
diff --git a/.maestro/tests/assorted/accessibility-and-appearance.yaml b/.maestro/tests/assorted/accessibility-and-appearance.yaml
index 04a79a29fcd..dec998f84f7 100644
--- a/.maestro/tests/assorted/accessibility-and-appearance.yaml
+++ b/.maestro/tests/assorted/accessibility-and-appearance.yaml
@@ -95,8 +95,7 @@ tags:
timeout: 60000
# should disable mentions with @ symbol
-- tapOn:
- id: header-back
+- runFlow: '../../helpers/go-back.yaml'
- runFlow:
file: './utils/go-to-accessibility-appearance.yaml'
@@ -134,8 +133,7 @@ tags:
timeout: 60000
# should enable rooms with # symbol
-- tapOn:
- id: header-back
+- runFlow: '../../helpers/go-back.yaml'
- runFlow:
file: './utils/go-to-accessibility-appearance.yaml'
@@ -169,8 +167,7 @@ tags:
timeout: 60000
# should disable mentions with # symbol
-- tapOn:
- id: header-back
+- runFlow: '../../helpers/go-back.yaml'
- runFlow:
file: './utils/go-to-accessibility-appearance.yaml'
diff --git a/.maestro/tests/assorted/admin-panel.yaml b/.maestro/tests/assorted/admin-panel.yaml
index e783063497f..7380dfca90a 100644
--- a/.maestro/tests/assorted/admin-panel.yaml
+++ b/.maestro/tests/assorted/admin-panel.yaml
@@ -19,8 +19,11 @@ tags:
visible:
id: 'rooms-list-view'
timeout: 60000
-- tapOn:
- id: 'rooms-list-view-sidebar'
+- runFlow:
+ file: '../../helpers/tap-header-item.yaml'
+ env:
+ ANDROID_ID: 'rooms-list-view-sidebar'
+ IOS_LABEL: 'Menu'
- extendedWaitUntil:
visible:
id: 'sidebar-view'
diff --git a/.maestro/tests/assorted/broadcast.yaml b/.maestro/tests/assorted/broadcast.yaml
index 254c6b78b1b..7afd49459b2 100644
--- a/.maestro/tests/assorted/broadcast.yaml
+++ b/.maestro/tests/assorted/broadcast.yaml
@@ -19,12 +19,11 @@ tags:
PASSWORD: ${output.user.password}
# should create broadcast room
-- extendedWaitUntil:
- visible:
- id: 'rooms-list-view-create-channel'
- timeout: 60000
-- tapOn:
- id: 'rooms-list-view-create-channel'
+- runFlow:
+ file: '../../helpers/tap-header-item.yaml'
+ env:
+ ANDROID_ID: 'rooms-list-view-create-channel'
+ IOS_LABEL: 'Create new channel, team, direct message or discussion'
- extendedWaitUntil:
visible:
id: 'new-message-view'
@@ -39,8 +38,10 @@ tags:
visible:
id: 'select-users-view'
timeout: 60000
-- tapOn:
- id: 'select-users-view-search'
+- runFlow:
+ file: '../../helpers/tap-search-field.yaml'
+ env:
+ SEARCH_ID: 'select-users-view-search'
- inputText: ${output.otherUser.username}
- extendedWaitUntil:
visible:
@@ -52,10 +53,17 @@ tags:
visible:
id: 'selected-user-${output.otherUser.username}'
timeout: 60000
-- assertVisible:
- id: 'selected-users-view-submit'
-- tapOn:
- id: 'selected-users-view-submit'
+- runFlow: '../../helpers/close-search.yaml'
+- runFlow:
+ file: '../../helpers/wait-header-item.yaml'
+ env:
+ ANDROID_ID: 'selected-users-view-submit'
+ IOS_LABEL: 'Next'
+- runFlow:
+ file: '../../helpers/tap-header-item.yaml'
+ env:
+ ANDROID_ID: 'selected-users-view-submit'
+ IOS_LABEL: 'Next'
- extendedWaitUntil:
visible:
id: 'create-channel-view'
@@ -76,15 +84,11 @@ tags:
timeout: 60000
- tapOn:
id: 'create-channel-submit'
-- extendedWaitUntil:
- visible:
- id: 'room-view-title-${output.room}'
-- tapOn:
- id: 'room-header'
-- extendedWaitUntil:
- visible:
- id: 'room-actions-view'
- timeout: 60000
+- runFlow:
+ file: '../../helpers/assert-room-title.yaml'
+ env:
+ ROOM: ${output.room}
+- runFlow: '../../helpers/open-room-actions.yaml'
- tapOn:
id: 'room-actions-info'
- extendedWaitUntil:
@@ -117,10 +121,10 @@ tags:
file: '../../helpers/search-and-navigate-room.yaml'
env:
ROOM: ${output.room}
-- extendedWaitUntil:
- visible:
- id: 'room-view-title-${output.room}'
- timeout: 60000
+- runFlow:
+ file: '../../helpers/assert-room-title.yaml'
+ env:
+ ROOM: ${output.room}
# should not have message composer
- assertNotVisible:
@@ -139,10 +143,10 @@ tags:
id: 'message-broadcast-reply'
- tapOn:
id: 'message-broadcast-reply'
-- extendedWaitUntil:
- visible:
- id: 'room-view-title-${output.user.username}'
- timeout: 60000
+- runFlow:
+ file: '../../helpers/assert-room-title.yaml'
+ env:
+ ROOM: ${output.user.username}
# should reply broadcasted message
- assertVisible:
@@ -165,6 +169,7 @@ tags:
timeout: 60000
- tapOn:
text: 'Jump to message'
-- extendedWaitUntil:
- visible:
- id: 'room-view-title-${output.room}'
+- runFlow:
+ file: '../../helpers/assert-room-title.yaml'
+ env:
+ ROOM: ${output.room}
diff --git a/.maestro/tests/assorted/change-avatar.yaml b/.maestro/tests/assorted/change-avatar.yaml
index 72285dfc884..087c693591e 100644
--- a/.maestro/tests/assorted/change-avatar.yaml
+++ b/.maestro/tests/assorted/change-avatar.yaml
@@ -16,12 +16,11 @@ tags:
env:
USERNAME: ${output.user.username}
PASSWORD: ${output.user.password}
-- extendedWaitUntil:
- visible:
- id: 'rooms-list-view-sidebar'
- timeout: 60000
-- tapOn:
- id: 'rooms-list-view-sidebar'
+- runFlow:
+ file: '../../helpers/tap-header-item.yaml'
+ env:
+ ANDROID_ID: 'rooms-list-view-sidebar'
+ IOS_LABEL: 'Menu'
- extendedWaitUntil:
visible:
id: 'sidebar-view'
@@ -56,8 +55,7 @@ tags:
id: 'reset-avatar-suggestion'
# should appear the discard alert when click the back icon
-- tapOn:
- id: 'header-back'
+- runFlow: '../../helpers/go-back.yaml'
- extendedWaitUntil:
visible:
text: '.*Discard changes?.*'
@@ -68,8 +66,7 @@ tags:
timeout: 60000
- tapOn:
text: '.*Cancel.*'
-- tapOn:
- id: 'header-back'
+- runFlow: '../../helpers/go-back.yaml'
- extendedWaitUntil:
visible:
text: '.*Discard changes?.*'
diff --git a/.maestro/tests/assorted/changeserver.yaml b/.maestro/tests/assorted/changeserver.yaml
index 897eabe427d..6ae06a0747b 100644
--- a/.maestro/tests/assorted/changeserver.yaml
+++ b/.maestro/tests/assorted/changeserver.yaml
@@ -18,12 +18,7 @@ tags:
PASSWORD: ${output.user.password}
# should open the servers list, have the server add button and create workspace button
-- extendedWaitUntil:
- visible:
- id: 'rooms-list-header-servers-list-button'
- timeout: 60000
-- tapOn:
- id: 'rooms-list-header-servers-list-button'
+- runFlow: '../../helpers/open-servers-list.yaml'
- extendedWaitUntil:
visible:
id: 'rooms-list-header-servers-list'
@@ -57,12 +52,7 @@ tags:
timeout: 60000
# should add server and create new user
-- extendedWaitUntil:
- visible:
- id: 'rooms-list-header-servers-list-button'
- timeout: 60000
-- tapOn:
- id: 'rooms-list-header-servers-list-button'
+- runFlow: '../../helpers/open-servers-list.yaml'
- extendedWaitUntil:
visible:
id: 'rooms-list-header-servers-list'
@@ -107,14 +97,9 @@ tags:
server: ${output.data.alternateServer}
# should change back to main server
-- extendedWaitUntil:
- visible:
- id: 'rooms-list-header-servers-list-button'
- timeout: 60000
- waitForAnimationToEnd:
timeout: 5000
-- tapOn:
- id: 'rooms-list-header-servers-list-button'
+- runFlow: '../../helpers/open-servers-list.yaml'
- extendedWaitUntil:
visible:
id: 'rooms-list-header-servers-list'
@@ -154,12 +139,7 @@ tags:
server: ${output.data.server}
# should test swipe to delete on alternate server
-- extendedWaitUntil:
- visible:
- id: 'rooms-list-header-servers-list-button'
- timeout: 60000
-- tapOn:
- id: 'rooms-list-header-servers-list-button'
+- runFlow: '../../helpers/open-servers-list.yaml'
- extendedWaitUntil:
visible:
id: 'server-item-${output.data.alternateServer}'
@@ -198,12 +178,7 @@ tags:
# verify alternate server is deleted
- waitForAnimationToEnd:
timeout: 500
-- extendedWaitUntil:
- visible:
- id: 'rooms-list-header-servers-list-button'
- timeout: 60000
-- tapOn:
- id: 'rooms-list-header-servers-list-button'
+- runFlow: '../../helpers/open-servers-list.yaml'
- extendedWaitUntil:
notVisible:
id: 'server-item-${output.data.alternateServer}'
diff --git a/.maestro/tests/assorted/channel-deeplink.yaml b/.maestro/tests/assorted/channel-deeplink.yaml
index 6edcc747621..5f1d4ea0110 100644
--- a/.maestro/tests/assorted/channel-deeplink.yaml
+++ b/.maestro/tests/assorted/channel-deeplink.yaml
@@ -24,10 +24,10 @@ tags:
file: '../../helpers/open-deeplink.yaml'
env:
link: ${output.utils.getDeepLink('room', output.data.server, 'path=group/', output.group.name)}
-- extendedWaitUntil:
- visible:
- id: 'room-view-title-${output.group.name}'
- timeout: 60000
+- runFlow:
+ file: '../../helpers/assert-room-title.yaml'
+ env:
+ ROOM: ${output.group.name}
# open group using id
- killApp
@@ -35,10 +35,10 @@ tags:
file: '../../helpers/open-deeplink.yaml'
env:
link: ${output.utils.getDeepLink('room', output.data.server, 'path=group/', output.group._id)}
-- extendedWaitUntil:
- visible:
- id: 'room-view-title-${output.group.name}'
- timeout: 60000
+- runFlow:
+ file: '../../helpers/assert-room-title.yaml'
+ env:
+ ROOM: ${output.group.name}
# open channel using name
- killApp
@@ -46,10 +46,10 @@ tags:
file: '../../helpers/open-deeplink.yaml'
env:
link: ${output.utils.getDeepLink('room', output.data.server, 'path=channel/', output.channel.name)}
-- extendedWaitUntil:
- visible:
- id: 'room-view-title-${output.channel.name}'
- timeout: 60000
+- runFlow:
+ file: '../../helpers/assert-room-title.yaml'
+ env:
+ ROOM: ${output.channel.name}
# open channel using id
- killApp
@@ -57,7 +57,7 @@ tags:
file: '../../helpers/open-deeplink.yaml'
env:
link: ${output.utils.getDeepLink('room', output.data.server, 'path=channel/', output.channel._id)}
-- extendedWaitUntil:
- visible:
- id: 'room-view-title-${output.channel.name}'
- timeout: 60000
+- runFlow:
+ file: '../../helpers/assert-room-title.yaml'
+ env:
+ ROOM: ${output.channel.name}
diff --git a/.maestro/tests/assorted/deeplink.yaml b/.maestro/tests/assorted/deeplink.yaml
index 50cd775b78e..eef191bd36e 100644
--- a/.maestro/tests/assorted/deeplink.yaml
+++ b/.maestro/tests/assorted/deeplink.yaml
@@ -37,10 +37,10 @@ tags:
file: '../../helpers/open-deeplink.yaml'
env:
link: ${output.utils.getDeepLink('auth', output.data.server, 'userId=', output.login.userId, '&token=', output.login.authToken, '&path=group/', output.room.name)}
-- extendedWaitUntil:
- visible:
- id: 'room-view-title-${output.room.name}'
- timeout: 60000
+- runFlow:
+ file: '../../helpers/assert-room-title.yaml'
+ env:
+ ROOM: ${output.room.name}
- runFlow: '../../helpers/go-back.yaml'
- extendedWaitUntil:
visible:
@@ -70,10 +70,10 @@ tags:
file: '../../helpers/open-deeplink.yaml'
env:
link: ${output.utils.getDeepLink('auth', output.data.server, 'userId=', output.login.userId, '&token=', output.login.authToken, '&path=group/', output.room.name)}
-- extendedWaitUntil:
- visible:
- id: 'room-view-title-${output.room.name}'
- timeout: 60000
+- runFlow:
+ file: '../../helpers/assert-room-title.yaml'
+ env:
+ ROOM: ${output.room.name}
- runFlow: '../../helpers/go-back.yaml'
- extendedWaitUntil:
visible:
@@ -94,10 +94,10 @@ tags:
file: '../../helpers/open-deeplink.yaml'
env:
link: ${output.utils.getDeepLink('room', output.data.server, 'path=group/', output.room.name)}
-- extendedWaitUntil:
- visible:
- id: 'room-view-title-${output.room.name}'
- timeout: 60000
+- runFlow:
+ file: '../../helpers/assert-room-title.yaml'
+ env:
+ ROOM: ${output.room.name}
# should navigate to the thread using path
- stopApp: ${APP_ID}
@@ -105,10 +105,10 @@ tags:
file: '../../helpers/open-deeplink.yaml'
env:
link: ${output.utils.getDeepLink('room', output.data.server, 'path=group/', output.room.name, '/thread/', output.result.message._id)}
-- extendedWaitUntil:
- visible:
- id: 'room-view-title-${output.threadMessage}'
- timeout: 60000
+- runFlow:
+ file: '../../helpers/assert-room-title.yaml'
+ env:
+ ROOM: ${output.threadMessage}
# should navigate to the room using rid
- stopApp: ${APP_ID}
@@ -116,10 +116,10 @@ tags:
file: '../../helpers/open-deeplink.yaml'
env:
link: ${output.utils.getDeepLink('room', output.data.server, 'rid=', output.room._id)}
-- extendedWaitUntil:
- visible:
- id: 'room-view-title-${output.room.name}'
- timeout: 60000
+- runFlow:
+ file: '../../helpers/assert-room-title.yaml'
+ env:
+ ROOM: ${output.room.name}
- runFlow: '../../helpers/go-back.yaml'
- extendedWaitUntil:
visible:
@@ -132,10 +132,10 @@ tags:
file: '../../helpers/open-deeplink.yaml'
env:
link: ${output.utils.getDeepLink('room', output.data.server, 'path=group/', output.room.name)}
-- extendedWaitUntil:
- visible:
- id: 'room-view-title-${output.room.name}'
- timeout: 60000
+- runFlow:
+ file: '../../helpers/assert-room-title.yaml'
+ env:
+ ROOM: ${output.room.name}
# should simulate a tap on a push notification and navigate to the room
# we are skipping this because we can't send push on iOS simulator and for android we have similar test
@@ -146,12 +146,7 @@ tags:
visible:
id: 'rooms-list-view'
timeout: 60000
-- extendedWaitUntil:
- visible:
- id: 'rooms-list-header-servers-list-button'
- timeout: 60000
-- tapOn:
- id: 'rooms-list-header-servers-list-button'
+- runFlow: '../../helpers/open-servers-list.yaml'
- extendedWaitUntil:
visible:
id: 'server-item-${output.data.alternateServer}'
@@ -167,10 +162,10 @@ tags:
file: '../../helpers/open-deeplink.yaml'
env:
link: ${output.utils.getDeepLink('room', output.data.server, 'path=group/', output.room.name)}
-- extendedWaitUntil:
- visible:
- id: 'room-view-title-${output.room.name}'
- timeout: 60000
+- runFlow:
+ file: '../../helpers/assert-room-title.yaml'
+ env:
+ ROOM: ${output.room.name}
# should add a not existing server and fallback to the previous one
- stopApp: ${APP_ID}
@@ -227,12 +222,7 @@ tags:
visible:
id: 'rooms-list-view'
timeout: 60000
-- extendedWaitUntil:
- visible:
- id: 'rooms-list-header-servers-list-button'
- timeout: 60000
-- tapOn:
- id: 'rooms-list-header-servers-list-button'
+- runFlow: '../../helpers/open-servers-list.yaml'
- extendedWaitUntil:
visible:
id: 'server-item-${output.data.alternateServer}'
@@ -343,8 +333,18 @@ tags:
visible:
id: 'new-server-view'
timeout: 60000
-- assertNotVisible:
- id: 'room-view-title-${output.room.name}'
+- runFlow:
+ when:
+ platform: android
+ commands:
+ - assertNotVisible:
+ id: 'room-view-title-${output.room.name}'
+- runFlow:
+ when:
+ platform: ios
+ commands:
+ - assertNotVisible:
+ text: '${output.room.name}'
# should show a security confirmation prompt on deep link login and sign in when confirmed
- runFlow:
@@ -376,10 +376,10 @@ tags:
commands:
- tapOn:
text: 'Login'
-- extendedWaitUntil:
- visible:
- id: 'room-view-title-${output.room.name}'
- timeout: 60000
+- runFlow:
+ file: '../../helpers/assert-room-title.yaml'
+ env:
+ ROOM: ${output.room.name}
- runFlow: '../../helpers/go-back.yaml'
- extendedWaitUntil:
visible:
diff --git a/.maestro/tests/assorted/delete-server.yaml b/.maestro/tests/assorted/delete-server.yaml
index 7e63bee1ea9..f48a289776d 100644
--- a/.maestro/tests/assorted/delete-server.yaml
+++ b/.maestro/tests/assorted/delete-server.yaml
@@ -22,12 +22,7 @@ tags:
server: ${output.data.server}
# should add server
-- extendedWaitUntil:
- visible:
- id: 'rooms-list-header-servers-list-button'
- timeout: 60000
-- tapOn:
- id: 'rooms-list-header-servers-list-button'
+- runFlow: '../../helpers/open-servers-list.yaml'
- extendedWaitUntil:
visible:
id: 'rooms-list-header-server-add'
@@ -67,12 +62,7 @@ tags:
server: ${output.data.alternateServer}
# should delete server
-- extendedWaitUntil:
- visible:
- id: 'rooms-list-header-servers-list-button'
- timeout: 60000
-- tapOn:
- id: 'rooms-list-header-servers-list-button'
+- runFlow: '../../helpers/open-servers-list.yaml'
- extendedWaitUntil:
visible:
id: 'server-item-${output.data.server}'
@@ -109,12 +99,7 @@ tags:
retryTapIfNoChange: true
- waitForAnimationToEnd:
timeout: 300
-- extendedWaitUntil:
- visible:
- id: 'rooms-list-header-servers-list-button'
- timeout: 60000
-- tapOn:
- id: 'rooms-list-header-servers-list-button'
+- runFlow: '../../helpers/open-servers-list.yaml'
- extendedWaitUntil:
visible:
id: 'rooms-list-header-servers-list'
diff --git a/.maestro/tests/assorted/display-perf.yaml b/.maestro/tests/assorted/display-perf.yaml
index 54927e65a37..bbdaf0b54d7 100644
--- a/.maestro/tests/assorted/display-perf.yaml
+++ b/.maestro/tests/assorted/display-perf.yaml
@@ -30,18 +30,44 @@ tags:
label: 'Should have room item'
# should have create channel button
-- extendedWaitUntil:
- visible:
- id: 'rooms-list-view-create-channel'
- timeout: 60000
- label: 'Should have create channel button'
+- runFlow:
+ when:
+ platform: Android
+ commands:
+ - extendedWaitUntil:
+ visible:
+ id: 'rooms-list-view-create-channel'
+ timeout: 60000
+ label: 'Should have create channel button'
+- runFlow:
+ when:
+ platform: iOS
+ commands:
+ - extendedWaitUntil:
+ visible:
+ text: 'Create new channel, team, direct message or discussion'
+ timeout: 60000
+ label: 'Should have create channel button'
# should have sidebar button
-- extendedWaitUntil:
- visible:
- id: 'rooms-list-view-sidebar'
- timeout: 60000
- label: 'Should have sidebar button'
+- runFlow:
+ when:
+ platform: Android
+ commands:
+ - extendedWaitUntil:
+ visible:
+ id: 'rooms-list-view-sidebar'
+ timeout: 60000
+ label: 'Should have sidebar button'
+- runFlow:
+ when:
+ platform: iOS
+ commands:
+ - extendedWaitUntil:
+ visible:
+ text: 'Menu'
+ timeout: 60000
+ label: 'Should have sidebar button'
# should go to Display Preferences
- runFlow:
diff --git a/.maestro/tests/assorted/i18n.yaml b/.maestro/tests/assorted/i18n.yaml
index b4be402f7b2..928eed1f68a 100644
--- a/.maestro/tests/assorted/i18n.yaml
+++ b/.maestro/tests/assorted/i18n.yaml
@@ -25,8 +25,11 @@ tags:
visible:
id: 'rooms-list-view'
timeout: 60000
-- tapOn:
- id: 'rooms-list-view-sidebar'
+- runFlow:
+ file: '../../helpers/tap-header-item.yaml'
+ env:
+ ANDROID_ID: 'rooms-list-view-sidebar'
+ IOS_LABEL: 'Menu'
- extendedWaitUntil:
visible:
id: 'sidebar-view'
@@ -54,8 +57,11 @@ tags:
visible:
id: 'rooms-list-view'
timeout: 60000
-- tapOn:
- id: 'rooms-list-view-sidebar'
+- runFlow:
+ file: '../../helpers/tap-header-item.yaml'
+ env:
+ ANDROID_ID: 'rooms-list-view-sidebar'
+ IOS_LABEL: 'Menu'
- extendedWaitUntil:
visible:
id: 'sidebar-view'
diff --git a/.maestro/tests/assorted/in-app-notification.yaml b/.maestro/tests/assorted/in-app-notification.yaml
index 7b60d11506f..aa0a6cfe914 100644
--- a/.maestro/tests/assorted/in-app-notification.yaml
+++ b/.maestro/tests/assorted/in-app-notification.yaml
@@ -28,10 +28,10 @@ tags:
timeout: 60000
- tapOn:
id: 'in-app-notification-Message in DM'
-- extendedWaitUntil:
- visible:
- id: 'room-view-title-${output.sender.username}'
- timeout: 60000
+- runFlow:
+ file: '../../helpers/assert-room-title.yaml'
+ env:
+ ROOM: ${output.sender.username}
- runFlow: '../../helpers/go-back.yaml'
# receive in another room
@@ -46,10 +46,10 @@ tags:
timeout: 60000
- tapOn:
id: 'in-app-notification-Another msg'
-- extendedWaitUntil:
- visible:
- id: 'room-view-title-${output.sender.username}'
- timeout: 60000
+- runFlow:
+ file: '../../helpers/assert-room-title.yaml'
+ env:
+ ROOM: ${output.sender.username}
# should tap back and go back to RoomsListView
- runFlow: '../../helpers/go-back.yaml'
diff --git a/.maestro/tests/assorted/join-from-directory.yaml b/.maestro/tests/assorted/join-from-directory.yaml
index 748345c4f5d..c9673976a5b 100644
--- a/.maestro/tests/assorted/join-from-directory.yaml
+++ b/.maestro/tests/assorted/join-from-directory.yaml
@@ -22,26 +22,23 @@ tags:
PASSWORD: ${output.user.password}
# should tap directory
-- extendedWaitUntil:
- visible:
- id: 'rooms-list-view-directory'
- timeout: 60000
- waitForAnimationToEnd:
timeout: 10000
-- tapOn:
- id: 'rooms-list-view-directory'
+- runFlow:
+ file: '../../helpers/tap-header-item.yaml'
+ env:
+ ANDROID_ID: 'rooms-list-view-directory'
+ IOS_LABEL: 'Directory'
- extendedWaitUntil:
visible:
id: 'directory-view'
timeout: 60000
# should search public channel and navigate
-- extendedWaitUntil:
- visible:
- id: 'directory-view-search'
- timeout: 60000
-- tapOn:
- id: 'directory-view-search'
+- runFlow:
+ file: '../../helpers/tap-search-field.yaml'
+ env:
+ SEARCH_ID: 'directory-view-search'
- inputText: join-from-directory
- extendedWaitUntil:
visible:
@@ -53,56 +50,60 @@ tags:
visible:
id: 'room-view'
timeout: 60000
-- extendedWaitUntil:
- visible:
- id: 'room-view-title-join-from-directory'
- timeout: 60000
+- runFlow:
+ file: '../../helpers/assert-room-title.yaml'
+ env:
+ ROOM: 'join-from-directory'
# should navigate to thread messages view and load messages
-- extendedWaitUntil:
- visible:
- id: 'room-view-header-threads'
- timeout: 60000
-- tapOn:
- id: 'room-view-header-threads'
+- runFlow:
+ file: '../../helpers/tap-header-item.yaml'
+ env:
+ ANDROID_ID: 'room-view-header-threads'
+ IOS_LABEL: 'Threads'
- extendedWaitUntil:
visible:
id: 'thread-messages-view-${output.thread}'
timeout: 60000
-- tapOn:
- id: 'custom-header-back'
-- extendedWaitUntil:
- visible:
- id: 'room-view-header-threads'
- timeout: 60000
+- runFlow: '../../helpers/go-back.yaml'
+- runFlow:
+ when:
+ platform: android
+ commands:
+ - extendedWaitUntil:
+ visible:
+ id: 'room-view-header-threads'
+ timeout: 60000
+- runFlow:
+ when:
+ platform: iOS
+ commands:
+ - extendedWaitUntil:
+ visible:
+ text: 'Threads'
+ timeout: 60000
# should search user and navigate
-- tapOn:
- id: 'header-back'
-- extendedWaitUntil:
- visible:
- id: 'rooms-list-view-directory'
- timeout: 60000
-- tapOn:
- id: 'rooms-list-view-directory'
+- runFlow: '../../helpers/go-back.yaml'
+- runFlow:
+ file: '../../helpers/tap-header-item.yaml'
+ env:
+ ANDROID_ID: 'rooms-list-view-directory'
+ IOS_LABEL: 'Directory'
- extendedWaitUntil:
visible:
id: 'directory-view'
timeout: 60000
-- extendedWaitUntil:
- visible:
- id: 'directory-view-filter'
- timeout: 60000
-- tapOn:
- id: 'directory-view-filter'
-- extendedWaitUntil:
- visible:
- id: 'directory-switch-users'
- timeout: 60000
-- tapOn:
- id: 'directory-switch-users'
-- tapOn:
- id: 'directory-view-search'
+- runFlow:
+ file: '../../helpers/select-header-filter.yaml'
+ env:
+ ANDROID_FILTER_ID: 'directory-view-filter'
+ ANDROID_OPTION_ID: 'directory-switch-users'
+ IOS_OPTION: 'Users'
+- runFlow:
+ file: '../../helpers/tap-search-field.yaml'
+ env:
+ SEARCH_ID: 'directory-view-search'
- inputText: ${output.otherUser.username}
- runFlow:
when:
@@ -119,38 +120,32 @@ tags:
visible:
id: 'room-view'
timeout: 60000
-- extendedWaitUntil:
- visible:
- id: 'room-view-title-${output.otherUser.username}'
- timeout: 60000
+- runFlow:
+ file: '../../helpers/assert-room-title.yaml'
+ env:
+ ROOM: ${output.otherUser.username}
# should search team and navigate
-- tapOn:
- id: 'header-back'
-- extendedWaitUntil:
- visible:
- id: 'rooms-list-view-directory'
- timeout: 60000
-- tapOn:
- id: 'rooms-list-view-directory'
+- runFlow: '../../helpers/go-back.yaml'
+- runFlow:
+ file: '../../helpers/tap-header-item.yaml'
+ env:
+ ANDROID_ID: 'rooms-list-view-directory'
+ IOS_LABEL: 'Directory'
- extendedWaitUntil:
visible:
id: 'directory-view'
timeout: 60000
-- extendedWaitUntil:
- visible:
- id: 'directory-view-filter'
- timeout: 60000
-- tapOn:
- id: 'directory-view-filter'
-- extendedWaitUntil:
- visible:
- id: 'directory-switch-teams'
- timeout: 60000
-- tapOn:
- id: 'directory-switch-teams'
-- tapOn:
- id: 'directory-view-search'
+- runFlow:
+ file: '../../helpers/select-header-filter.yaml'
+ env:
+ ANDROID_FILTER_ID: 'directory-view-filter'
+ ANDROID_OPTION_ID: 'directory-switch-teams'
+ IOS_OPTION: 'Teams'
+- runFlow:
+ file: '../../helpers/tap-search-field.yaml'
+ env:
+ SEARCH_ID: 'directory-view-search'
- inputText: ${output.team}
- extendedWaitUntil:
visible:
@@ -162,7 +157,7 @@ tags:
visible:
id: 'room-view'
timeout: 60000
-- extendedWaitUntil:
- visible:
- id: 'room-view-title-${output.team}'
- timeout: 60000
+- runFlow:
+ file: '../../helpers/assert-room-title.yaml'
+ env:
+ ROOM: ${output.team}
diff --git a/.maestro/tests/assorted/join-public-room.yaml b/.maestro/tests/assorted/join-public-room.yaml
index c7f82ad1bd9..c6210a77381 100644
--- a/.maestro/tests/assorted/join-public-room.yaml
+++ b/.maestro/tests/assorted/join-public-room.yaml
@@ -25,8 +25,18 @@ tags:
id: room-view
# should have actions button
-- assertVisible:
- id: room-header
+- runFlow:
+ when:
+ platform: android
+ commands:
+ - assertVisible:
+ id: room-header
+- runFlow:
+ when:
+ platform: iOS
+ commands:
+ - assertVisible:
+ text: 'More'
# should have join
- assertVisible:
diff --git a/.maestro/tests/assorted/profile.yaml b/.maestro/tests/assorted/profile.yaml
index 257cc297509..e973fcfe20a 100644
--- a/.maestro/tests/assorted/profile.yaml
+++ b/.maestro/tests/assorted/profile.yaml
@@ -14,12 +14,11 @@ tags:
env:
USERNAME: ${output.user.username}
PASSWORD: ${output.user.password}
-- extendedWaitUntil:
- visible:
- id: 'rooms-list-view-sidebar'
- timeout: 60000
-- tapOn:
- id: 'rooms-list-view-sidebar'
+- runFlow:
+ file: '../../helpers/tap-header-item.yaml'
+ env:
+ ANDROID_ID: 'rooms-list-view-sidebar'
+ IOS_LABEL: 'Menu'
- extendedWaitUntil:
visible:
id: 'sidebar-view'
diff --git a/.maestro/tests/assorted/screen-lock.yaml b/.maestro/tests/assorted/screen-lock.yaml
index 4ea169bfcb4..7fb93da90df 100644
--- a/.maestro/tests/assorted/screen-lock.yaml
+++ b/.maestro/tests/assorted/screen-lock.yaml
@@ -20,8 +20,11 @@ tags:
visible:
id: 'rooms-list-view'
timeout: 60000
-- tapOn:
- id: 'rooms-list-view-sidebar'
+- runFlow:
+ file: '../../helpers/tap-header-item.yaml'
+ env:
+ ANDROID_ID: 'rooms-list-view-sidebar'
+ IOS_LABEL: 'Menu'
- extendedWaitUntil:
visible:
id: 'sidebar-settings'
@@ -122,8 +125,11 @@ tags:
visible:
id: 'rooms-list-view'
timeout: 60000
-- tapOn:
- id: 'rooms-list-view-sidebar'
+- runFlow:
+ file: '../../helpers/tap-header-item.yaml'
+ env:
+ ANDROID_ID: 'rooms-list-view-sidebar'
+ IOS_LABEL: 'Menu'
- extendedWaitUntil:
visible:
id: 'sidebar-settings'
diff --git a/.maestro/tests/assorted/setting.yaml b/.maestro/tests/assorted/setting.yaml
index 9186da79f1e..3d4a08d2143 100644
--- a/.maestro/tests/assorted/setting.yaml
+++ b/.maestro/tests/assorted/setting.yaml
@@ -20,8 +20,11 @@ tags:
visible:
id: 'rooms-list-view'
timeout: 60000
-- tapOn:
- id: 'rooms-list-view-sidebar'
+- runFlow:
+ file: '../../helpers/tap-header-item.yaml'
+ env:
+ ANDROID_ID: 'rooms-list-view-sidebar'
+ IOS_LABEL: 'Menu'
- extendedWaitUntil:
visible:
id: 'sidebar-view'
@@ -177,10 +180,11 @@ tags:
timeout: 60000
# should navigate to legalview
-- assertVisible:
- id: 'rooms-list-view-sidebar'
-- tapOn:
- id: 'rooms-list-view-sidebar'
+- runFlow:
+ file: '../../helpers/tap-header-item.yaml'
+ env:
+ ANDROID_ID: 'rooms-list-view-sidebar'
+ IOS_LABEL: 'Menu'
- extendedWaitUntil:
visible:
id: 'sidebar-view'
diff --git a/.maestro/tests/assorted/status.yaml b/.maestro/tests/assorted/status.yaml
index 88e5f418369..63ef6bcc4fc 100644
--- a/.maestro/tests/assorted/status.yaml
+++ b/.maestro/tests/assorted/status.yaml
@@ -14,12 +14,11 @@ tags:
env:
USERNAME: ${output.user.username}
PASSWORD: ${output.user.password}
-- extendedWaitUntil:
- visible:
- id: 'rooms-list-view-sidebar'
- timeout: 60000
-- tapOn:
- id: 'rooms-list-view-sidebar'
+- runFlow:
+ file: '../../helpers/tap-header-item.yaml'
+ env:
+ ANDROID_ID: 'rooms-list-view-sidebar'
+ IOS_LABEL: 'Menu'
- extendedWaitUntil:
visible:
id: 'sidebar-view'
diff --git a/.maestro/tests/assorted/user-preferences.yaml b/.maestro/tests/assorted/user-preferences.yaml
index 80e026160c5..5e6baa77684 100644
--- a/.maestro/tests/assorted/user-preferences.yaml
+++ b/.maestro/tests/assorted/user-preferences.yaml
@@ -89,8 +89,7 @@ tags:
id: push-troubleshoot-view-push-gateway-connection
- assertVisible:
id: push-troubleshoot-view-notification-delay
-- tapOn:
- id: custom-header-back
+- runFlow: '../../helpers/go-back.yaml'
# should have alert in Email
- assertVisible:
@@ -105,8 +104,7 @@ tags:
id: notification-preferences-emailNotificationMode-nothing
- tapOn:
id: action-sheet-handle
-- tapOn:
- id: custom-header-back
+- runFlow: '../../helpers/go-back.yaml'
# ASCII should not be converted to emoji (Android only)
- runFlow:
@@ -114,8 +112,7 @@ tags:
when:
platform: Android
commands:
- - tapOn:
- id: 'custom-header-back'
+ - runFlow: '../../helpers/go-back.yaml'
- extendedWaitUntil:
visible:
id: 'profile-view'
@@ -162,8 +159,7 @@ tags:
when:
platform: Android
commands:
- - tapOn:
- id: 'header-back'
+ - runFlow: '../../helpers/go-back.yaml'
- runFlow:
file: './utils/go-to-user-preference.yaml'
- extendedWaitUntil:
@@ -172,8 +168,7 @@ tags:
timeout: 60000
- tapOn:
id: 'preferences-view-convert-ascii-to-emoji'
- - tapOn:
- id: 'custom-header-back'
+ - runFlow: '../../helpers/go-back.yaml'
- extendedWaitUntil:
visible:
id: 'profile-view'
diff --git a/.maestro/tests/assorted/utils/check-server.yaml b/.maestro/tests/assorted/utils/check-server.yaml
index 7e180616e21..486c3e14d43 100644
--- a/.maestro/tests/assorted/utils/check-server.yaml
+++ b/.maestro/tests/assorted/utils/check-server.yaml
@@ -4,12 +4,11 @@ tags:
- 'util'
---
-- extendedWaitUntil:
- visible:
- id: 'rooms-list-view-sidebar'
- timeout: 60000
-- tapOn:
- id: 'rooms-list-view-sidebar'
+- runFlow:
+ file: '../../../helpers/tap-header-item.yaml'
+ env:
+ ANDROID_ID: 'rooms-list-view-sidebar'
+ IOS_LABEL: 'Menu'
- extendedWaitUntil:
visible:
id: 'sidebar-view'
diff --git a/.maestro/tests/assorted/utils/go-to-accessibility-appearance.yaml b/.maestro/tests/assorted/utils/go-to-accessibility-appearance.yaml
index f54a4946e4c..42b2309f656 100644
--- a/.maestro/tests/assorted/utils/go-to-accessibility-appearance.yaml
+++ b/.maestro/tests/assorted/utils/go-to-accessibility-appearance.yaml
@@ -4,12 +4,11 @@ tags:
- 'util'
---
-- extendedWaitUntil:
- visible:
- id: 'rooms-list-view-sidebar'
- timeout: 60000
-- tapOn:
- id: 'rooms-list-view-sidebar'
+- runFlow:
+ file: '../../../helpers/tap-header-item.yaml'
+ env:
+ ANDROID_ID: 'rooms-list-view-sidebar'
+ IOS_LABEL: 'Menu'
- extendedWaitUntil:
visible:
id: 'sidebar-accessibility'
diff --git a/.maestro/tests/assorted/utils/go-to-display-pref.yaml b/.maestro/tests/assorted/utils/go-to-display-pref.yaml
index 4acea68390c..110ae664ff4 100644
--- a/.maestro/tests/assorted/utils/go-to-display-pref.yaml
+++ b/.maestro/tests/assorted/utils/go-to-display-pref.yaml
@@ -4,12 +4,11 @@ tags:
- 'util'
---
-- extendedWaitUntil:
- visible:
- id: 'rooms-list-view-sidebar'
- timeout: 60000
-- tapOn:
- id: 'rooms-list-view-sidebar'
+- runFlow:
+ file: '../../../helpers/tap-header-item.yaml'
+ env:
+ ANDROID_ID: 'rooms-list-view-sidebar'
+ IOS_LABEL: 'Menu'
- extendedWaitUntil:
visible:
id: 'sidebar-accessibility'
diff --git a/.maestro/tests/assorted/utils/go-to-room-list.yaml b/.maestro/tests/assorted/utils/go-to-room-list.yaml
index 6734380e054..5dc8737c39e 100644
--- a/.maestro/tests/assorted/utils/go-to-room-list.yaml
+++ b/.maestro/tests/assorted/utils/go-to-room-list.yaml
@@ -4,12 +4,9 @@ tags:
- 'util'
---
-- extendedWaitUntil:
- visible:
- id: 'custom-header-back'
- timeout: 60000
-- tapOn:
- id: 'custom-header-back'
+- waitForAnimationToEnd:
+ timeout: 10000
+- runFlow: '../../../helpers/go-back.yaml'
- extendedWaitUntil:
visible:
id: 'accessibility-view-drawer'
diff --git a/.maestro/tests/assorted/utils/go-to-user-preference.yaml b/.maestro/tests/assorted/utils/go-to-user-preference.yaml
index 3a735db6b03..18ac81e4df5 100644
--- a/.maestro/tests/assorted/utils/go-to-user-preference.yaml
+++ b/.maestro/tests/assorted/utils/go-to-user-preference.yaml
@@ -4,12 +4,11 @@ tags:
- 'util'
---
-- extendedWaitUntil:
- visible:
- id: 'rooms-list-view-sidebar'
- timeout: 60000
-- tapOn:
- id: 'rooms-list-view-sidebar'
+- runFlow:
+ file: '../../../helpers/tap-header-item.yaml'
+ env:
+ ANDROID_ID: 'rooms-list-view-sidebar'
+ IOS_LABEL: 'Menu'
- extendedWaitUntil:
visible:
id: 'sidebar-profile'
diff --git a/.maestro/tests/assorted/utils/nav-to-language.yaml b/.maestro/tests/assorted/utils/nav-to-language.yaml
index e92b341fad1..1cfd88f8d61 100644
--- a/.maestro/tests/assorted/utils/nav-to-language.yaml
+++ b/.maestro/tests/assorted/utils/nav-to-language.yaml
@@ -8,12 +8,11 @@ tags:
visible:
id: 'rooms-list-view'
timeout: 60000
-- extendedWaitUntil:
- visible:
- id: 'rooms-list-view-sidebar'
- timeout: 60000
-- tapOn:
- id: 'rooms-list-view-sidebar'
+- runFlow:
+ file: '../../../helpers/tap-header-item.yaml'
+ env:
+ ANDROID_ID: 'rooms-list-view-sidebar'
+ IOS_LABEL: 'Menu'
- extendedWaitUntil:
visible:
id: 'sidebar-view'
diff --git a/.maestro/tests/e2ee/flows/create-e2ee-room.yaml b/.maestro/tests/e2ee/flows/create-e2ee-room.yaml
index 02219c31d1d..7d698cc833a 100644
--- a/.maestro/tests/e2ee/flows/create-e2ee-room.yaml
+++ b/.maestro/tests/e2ee/flows/create-e2ee-room.yaml
@@ -4,12 +4,11 @@ tags:
- 'flow'
---
- launchApp
-- extendedWaitUntil:
- visible:
- id: 'rooms-list-view-create-channel'
- timeout: 60000
-- tapOn:
- id: 'rooms-list-view-create-channel'
+- runFlow:
+ file: '../../../helpers/tap-header-item.yaml'
+ env:
+ ANDROID_ID: 'rooms-list-view-create-channel'
+ IOS_LABEL: 'Create new channel, team, direct message or discussion'
- extendedWaitUntil:
visible:
id: 'new-message-view'
@@ -23,8 +22,10 @@ tags:
visible:
id: 'select-users-view'
timeout: 60000
-- tapOn:
- id: 'select-users-view-search'
+- runFlow:
+ file: '../../../helpers/tap-search-field.yaml'
+ env:
+ SEARCH_ID: 'select-users-view-search'
- inputText: ${USER_TO_ADD}
- extendedWaitUntil:
visible:
@@ -35,8 +36,11 @@ tags:
- extendedWaitUntil:
visible:
id: 'selected-user-${USER_TO_ADD}'
-- tapOn:
- id: 'selected-users-view-submit'
+- runFlow:
+ file: '../../../helpers/tap-header-item.yaml'
+ env:
+ ANDROID_ID: 'selected-users-view-submit'
+ IOS_LABEL: 'Next'
- extendedWaitUntil:
visible:
id: 'create-channel-name'
@@ -53,7 +57,7 @@ tags:
id: 'create-channel-encrypted'
- tapOn:
id: 'create-channel-submit'
-- extendedWaitUntil:
- visible:
- id: 'room-view-title-${ROOM}'
- timeout: 60000
+- runFlow:
+ file: '../../../helpers/assert-room-title.yaml'
+ env:
+ ROOM: ${ROOM}
diff --git a/.maestro/tests/e2ee/flows/reset-keys-and-send.yaml b/.maestro/tests/e2ee/flows/reset-keys-and-send.yaml
index f607b8d3957..9a2ab1da641 100644
--- a/.maestro/tests/e2ee/flows/reset-keys-and-send.yaml
+++ b/.maestro/tests/e2ee/flows/reset-keys-and-send.yaml
@@ -39,12 +39,33 @@ env:
visible:
text: '.*The encryption keys for the room need to be updated, another room member needs to be online for this to happen.*'
timeout: 60000
-- extendedWaitUntil:
- visible:
- id: 'room-view-header-encryption'
- timeout: 60000
-- tapOn:
- id: 'room-view-header-encryption'
+- runFlow:
+ when:
+ platform: android
+ commands:
+ - extendedWaitUntil:
+ visible:
+ id: 'room-view-header-encryption'
+ timeout: 60000
+ - tapOn:
+ id: 'room-view-header-encryption'
+- runFlow:
+ when:
+ platform: iOS
+ commands:
+ - runFlow:
+ when:
+ notVisible:
+ text: 'Encrypted'
+ commands:
+ - tapOn:
+ text: 'More'
+ - extendedWaitUntil:
+ visible:
+ text: 'Encrypted'
+ timeout: 60000
+ - tapOn:
+ text: 'Encrypted'
- extendedWaitUntil:
visible:
id: 'e2ee-toggle-room-view'
@@ -69,10 +90,10 @@ env:
file: '../../../helpers/navigate-to-room.yaml'
env:
ROOM: ${ROOM}
-- extendedWaitUntil:
- visible:
- id: 'room-view-title-${ROOM}'
- timeout: 60000
+- runFlow:
+ file: '../../../helpers/assert-room-title.yaml'
+ env:
+ ROOM: ${ROOM}
- runFlow:
file: '../../../helpers/send-message.yaml'
env:
diff --git a/.maestro/tests/e2ee/utils/navigate-to-e2ee-security.yaml b/.maestro/tests/e2ee/utils/navigate-to-e2ee-security.yaml
index 00c21e89233..e37a6e5bd0e 100644
--- a/.maestro/tests/e2ee/utils/navigate-to-e2ee-security.yaml
+++ b/.maestro/tests/e2ee/utils/navigate-to-e2ee-security.yaml
@@ -18,13 +18,11 @@ tags:
visible: 'Enter E2EE password'
commands:
- assertVisible: Enter E2EE password
-- extendedWaitUntil:
- visible:
- id: rooms-list-view-sidebar
- enabled: true
- timeout: 60000
-- tapOn:
- id: rooms-list-view-sidebar
+- runFlow:
+ file: '../../../helpers/tap-header-item.yaml'
+ env:
+ ANDROID_ID: 'rooms-list-view-sidebar'
+ IOS_LABEL: 'Menu'
- extendedWaitUntil:
visible:
id: sidebar-view
diff --git a/.maestro/tests/keyboardNavigation/keyboard-navigation-components.yaml b/.maestro/tests/keyboardNavigation/keyboard-navigation-components.yaml
index da7b8376cad..341680e0429 100644
--- a/.maestro/tests/keyboardNavigation/keyboard-navigation-components.yaml
+++ b/.maestro/tests/keyboardNavigation/keyboard-navigation-components.yaml
@@ -72,8 +72,7 @@ tags:
- pressKey: enter
# open Toasts and Dialogs action sheet and navigate through options
-- tapOn:
- id: 'custom-header-back'
+- runFlow: '../../helpers/go-back.yaml'
- extendedWaitUntil:
visible:
id: 'accessibility-view-list'
diff --git a/.maestro/tests/onboarding/roomslist.yaml b/.maestro/tests/onboarding/roomslist.yaml
index ca236a66b74..2421a01478b 100644
--- a/.maestro/tests/onboarding/roomslist.yaml
+++ b/.maestro/tests/onboarding/roomslist.yaml
@@ -19,10 +19,22 @@ tags:
id: 'rooms-list-view'
- assertVisible:
id: 'rooms-list-view-item-general'
-- assertVisible:
- id: 'rooms-list-view-create-channel'
-- assertVisible:
- id: 'rooms-list-view-sidebar'
+- runFlow:
+ when:
+ platform: android
+ commands:
+ - assertVisible:
+ id: 'rooms-list-view-create-channel'
+ - assertVisible:
+ id: 'rooms-list-view-sidebar'
+- runFlow:
+ when:
+ platform: iOS
+ commands:
+ - assertVisible:
+ text: 'Create new channel, team, direct message or discussion'
+ - assertVisible:
+ text: 'Menu'
- runFlow:
file: ../../helpers/search-room.yaml
env:
diff --git a/.maestro/tests/room/create-dm-group.yaml b/.maestro/tests/room/create-dm-group.yaml
index 12750ea7d0d..d00f676051b 100644
--- a/.maestro/tests/room/create-dm-group.yaml
+++ b/.maestro/tests/room/create-dm-group.yaml
@@ -18,12 +18,11 @@ tags:
env:
USERNAME: ${output.user.username}
PASSWORD: ${output.user.password}
-- extendedWaitUntil:
- visible:
- id: 'rooms-list-view-create-channel'
- timeout: 60000
-- tapOn:
- id: 'rooms-list-view-create-channel'
+- runFlow:
+ file: '../../helpers/tap-header-item.yaml'
+ env:
+ ANDROID_ID: 'rooms-list-view-create-channel'
+ IOS_LABEL: 'Create new channel, team, direct message or discussion'
# should have new message screen
- extendedWaitUntil:
@@ -46,12 +45,10 @@ tags:
id: 'new-message-view-create-direct-message'
# should add users
-- extendedWaitUntil:
- visible:
- id: 'select-users-view-search'
- timeout: 60000
-- tapOn:
- id: 'select-users-view-search'
+- runFlow:
+ file: '../../helpers/tap-search-field.yaml'
+ env:
+ SEARCH_ID: 'select-users-view-search'
- inputText: 'rocket.cat'
- extendedWaitUntil:
visible:
@@ -59,8 +56,10 @@ tags:
timeout: 60000
- tapOn:
id: 'select-users-view-item-rocket.cat'
-- tapOn:
- id: 'select-users-view-search'
+- runFlow:
+ file: '../../helpers/tap-search-field.yaml'
+ env:
+ SEARCH_ID: 'select-users-view-search'
- eraseText
- inputText: ${output.otherUser.username}
- extendedWaitUntil:
@@ -69,15 +68,19 @@ tags:
timeout: 60000
- tapOn:
id: 'select-users-view-item-${output.otherUser.username}'
-- extendedWaitUntil:
- visible:
- id: 'selected-users-view-submit'
- timeout: 60000
-- tapOn:
- id: 'selected-users-view-submit'
+- runFlow:
+ file: '../../helpers/wait-header-item.yaml'
+ env:
+ ANDROID_ID: 'selected-users-view-submit'
+ IOS_LABEL: 'Create'
+- runFlow:
+ file: '../../helpers/tap-header-item.yaml'
+ env:
+ ANDROID_ID: 'selected-users-view-submit'
+ IOS_LABEL: 'Create'
# check Group DM exist
-- extendedWaitUntil:
- visible:
- id: 'room-view-title-rocket.cat, ${output.otherUser.username}'
- timeout: 60000
+- runFlow:
+ file: '../../helpers/assert-room-title.yaml'
+ env:
+ ROOM: 'rocket.cat, ${output.otherUser.username}'
diff --git a/.maestro/tests/room/create-room.yaml b/.maestro/tests/room/create-room.yaml
index d7dc2f2df39..ce322467953 100644
--- a/.maestro/tests/room/create-room.yaml
+++ b/.maestro/tests/room/create-room.yaml
@@ -15,12 +15,11 @@ tags:
USERNAME: ${output.user.username}
PASSWORD: ${output.user.password}
-- extendedWaitUntil:
- visible:
- id: 'rooms-list-view-create-channel'
- timeout: 60000
-- tapOn:
- id: 'rooms-list-view-create-channel'
+- runFlow:
+ file: '../../helpers/tap-header-item.yaml'
+ env:
+ ANDROID_ID: 'rooms-list-view-create-channel'
+ IOS_LABEL: 'Create new channel, team, direct message or discussion'
# should have new message screen
- extendedWaitUntil:
@@ -45,8 +44,11 @@ tags:
visible:
id: 'rooms-list-view'
timeout: 60000
-- tapOn:
- id: 'rooms-list-view-create-channel'
+- runFlow:
+ file: '../../helpers/tap-header-item.yaml'
+ env:
+ ANDROID_ID: 'rooms-list-view-create-channel'
+ IOS_LABEL: 'Create new channel, team, direct message or discussion'
- extendedWaitUntil:
visible:
id: 'new-message-view'
@@ -70,10 +72,10 @@ tags:
visible:
id: 'room-view'
timeout: 60000
-- extendedWaitUntil:
- visible:
- id: 'room-view-title-rocket.cat'
- timeout: 60000
+- runFlow:
+ file: '../../helpers/assert-room-title.yaml'
+ env:
+ ROOM: 'rocket.cat'
- runFlow: '../../helpers/go-back.yaml'
- extendedWaitUntil:
visible:
@@ -81,12 +83,11 @@ tags:
timeout: 60000
# should navigate to select users
-- extendedWaitUntil:
- visible:
- id: 'rooms-list-view-create-channel'
- timeout: 60000
-- tapOn:
- id: 'rooms-list-view-create-channel'
+- runFlow:
+ file: '../../helpers/tap-header-item.yaml'
+ env:
+ ANDROID_ID: 'rooms-list-view-create-channel'
+ IOS_LABEL: 'Create new channel, team, direct message or discussion'
- extendedWaitUntil:
visible:
id: 'new-message-view'
@@ -103,12 +104,10 @@ tags:
timeout: 60000
# should search users
-- extendedWaitUntil:
- visible:
- id: 'select-users-view-search'
- timeout: 60000
-- tapOn:
- id: 'select-users-view-search'
+- runFlow:
+ file: '../../helpers/tap-search-field.yaml'
+ env:
+ SEARCH_ID: 'select-users-view-search'
- inputText: 'rocket.cat'
- extendedWaitUntil:
visible:
@@ -138,12 +137,16 @@ tags:
timeout: 60000
# should navigate to create channel view
-- extendedWaitUntil:
- visible:
- id: 'selected-users-view-submit'
- timeout: 60000
-- tapOn:
- id: 'selected-users-view-submit'
+- runFlow:
+ file: '../../helpers/wait-header-item.yaml'
+ env:
+ ANDROID_ID: 'selected-users-view-submit'
+ IOS_LABEL: 'Next'
+- runFlow:
+ file: '../../helpers/tap-header-item.yaml'
+ env:
+ ANDROID_ID: 'selected-users-view-submit'
+ IOS_LABEL: 'Next'
- extendedWaitUntil:
visible:
id: 'create-channel-view'
@@ -203,10 +206,10 @@ tags:
visible:
id: 'room-view'
timeout: 60000
-- extendedWaitUntil:
- visible:
- id: ${'room-view-title-' + output.publicRoomName}
- timeout: 60000
+- runFlow:
+ file: '../../helpers/assert-room-title.yaml'
+ env:
+ ROOM: ${output.publicRoomName}
- runFlow: '../../helpers/go-back.yaml'
- extendedWaitUntil:
visible:
@@ -223,12 +226,11 @@ tags:
visible:
id: 'rooms-list-view'
timeout: 60000
-- extendedWaitUntil:
- visible:
- id: 'rooms-list-view-create-channel'
- timeout: 60000
-- tapOn:
- id: 'rooms-list-view-create-channel'
+- runFlow:
+ file: '../../helpers/tap-header-item.yaml'
+ env:
+ ANDROID_ID: 'rooms-list-view-create-channel'
+ IOS_LABEL: 'Create new channel, team, direct message or discussion'
- extendedWaitUntil:
visible:
id: 'new-message-view'
@@ -249,8 +251,11 @@ tags:
visible:
id: 'selected-user-rocket.cat'
timeout: 60000
-- tapOn:
- id: 'selected-users-view-submit'
+- runFlow:
+ file: '../../helpers/tap-header-item.yaml'
+ env:
+ ANDROID_ID: 'selected-users-view-submit'
+ IOS_LABEL: 'Next'
- extendedWaitUntil:
visible:
id: 'create-channel-view'
@@ -269,10 +274,10 @@ tags:
visible:
id: 'room-view'
timeout: 60000
-- extendedWaitUntil:
- visible:
- id: ${'room-view-title-' + output.privateRoomName}
- timeout: 60000
+- runFlow:
+ file: '../../helpers/assert-room-title.yaml'
+ env:
+ ROOM: ${output.privateRoomName}
- runFlow: '../../helpers/go-back.yaml'
- extendedWaitUntil:
visible:
@@ -289,12 +294,11 @@ tags:
visible:
id: 'rooms-list-view'
timeout: 60000
-- extendedWaitUntil:
- visible:
- id: 'rooms-list-view-create-channel'
- timeout: 60000
-- tapOn:
- id: 'rooms-list-view-create-channel'
+- runFlow:
+ file: '../../helpers/tap-header-item.yaml'
+ env:
+ ANDROID_ID: 'rooms-list-view-create-channel'
+ IOS_LABEL: 'Create new channel, team, direct message or discussion'
- extendedWaitUntil:
visible:
id: 'new-message-view'
@@ -309,8 +313,11 @@ tags:
visible:
id: 'select-users-view'
timeout: 60000
-- tapOn:
- id: 'selected-users-view-submit'
+- runFlow:
+ file: '../../helpers/tap-header-item.yaml'
+ env:
+ ANDROID_ID: 'selected-users-view-submit'
+ IOS_LABEL: 'Skip'
- extendedWaitUntil:
visible:
id: 'create-channel-view'
@@ -333,10 +340,10 @@ tags:
visible:
id: 'room-view'
timeout: 60000
-- extendedWaitUntil:
- visible:
- id: ${'room-view-title-' + output.emptyRoomName}
- timeout: 60000
+- runFlow:
+ file: '../../helpers/assert-room-title.yaml'
+ env:
+ ROOM: ${output.emptyRoomName}
- runFlow: '../../helpers/go-back.yaml'
- extendedWaitUntil:
visible:
diff --git a/.maestro/tests/room/discussion.yaml b/.maestro/tests/room/discussion.yaml
index 3fc7f536218..da4a072996f 100644
--- a/.maestro/tests/room/discussion.yaml
+++ b/.maestro/tests/room/discussion.yaml
@@ -25,10 +25,11 @@ tags:
visible:
id: 'rooms-list-view'
timeout: 60000
-- assertVisible:
- id: 'rooms-list-view-create-channel'
-- tapOn:
- id: 'rooms-list-view-create-channel'
+- runFlow:
+ file: '../../helpers/tap-header-item.yaml'
+ env:
+ ANDROID_ID: 'rooms-list-view-create-channel'
+ IOS_LABEL: 'Create new channel, team, direct message or discussion'
- extendedWaitUntil:
visible:
id: 'new-message-view'
@@ -44,12 +45,10 @@ tags:
id: 'select-users-view'
timeout: 60000
# Select users in SelectedUsersView
-- extendedWaitUntil:
- visible:
- id: 'select-users-view-search'
- timeout: 60000
-- tapOn:
- id: 'select-users-view-search'
+- runFlow:
+ file: '../../helpers/tap-search-field.yaml'
+ env:
+ SEARCH_ID: 'select-users-view-search'
- inputText: ${output.selectUser}
- extendedWaitUntil:
visible:
@@ -61,8 +60,11 @@ tags:
visible:
id: 'selected-user-${output.selectUser}'
timeout: 60000
-- tapOn:
- id: 'selected-users-view-submit'
+- runFlow:
+ file: '../../helpers/tap-header-item.yaml'
+ env:
+ ANDROID_ID: 'selected-users-view-submit'
+ IOS_LABEL: 'Next'
- extendedWaitUntil:
visible:
id: 'create-discussion-view'
@@ -89,18 +91,17 @@ tags:
visible:
id: 'room-view'
timeout: 60000
-- extendedWaitUntil:
- visible:
- id: 'room-view-title-${output.discussionFromNewMessage}'
- timeout: 60000
+- runFlow:
+ file: '../../helpers/assert-room-title.yaml'
+ env:
+ ROOM: ${output.discussionFromNewMessage}
- runFlow: '../../helpers/hide-keyboard.yaml'
- runFlow:
when:
visible:
id: 'room-view'
commands:
- - tapOn:
- id: 'header-back'
+ - runFlow: '../../helpers/go-back.yaml'
- extendedWaitUntil:
visible:
id: 'rooms-list-view-item-${output.discussionFromNewMessage}'
@@ -142,10 +143,10 @@ tags:
visible:
id: 'room-view'
timeout: 60000
-- extendedWaitUntil:
- visible:
- id: 'room-view-title-${output.discussionFromMessageComposer}'
- timeout: 60000
+- runFlow:
+ file: '../../helpers/assert-room-title.yaml'
+ env:
+ ROOM: ${output.discussionFromMessageComposer}
# Create Discussion from action sheet
- extendedWaitUntil:
@@ -183,21 +184,13 @@ tags:
visible:
id: 'room-view'
timeout: 60000
-- extendedWaitUntil:
- visible:
- id: 'room-view-title-message'
- timeout: 60000
+- runFlow:
+ file: '../../helpers/assert-room-title.yaml'
+ env:
+ ROOM: 'message'
# Check RoomActionsView render
-- assertVisible:
- id: room-header
-- tapOn:
- id: room-header
- retryTapIfNoChange: true
-- extendedWaitUntil:
- visible:
- id: 'room-actions-view'
- timeout: 60000
+- runFlow: '../../helpers/open-room-actions.yaml'
# should have room actions screen
- assertVisible:
@@ -259,20 +252,17 @@ tags:
id: room-info-view-edit-button
# should go back to main room
-- tapOn:
- id: custom-header-back
+- runFlow: '../../helpers/go-back.yaml'
- extendedWaitUntil:
visible:
id: 'room-actions-view'
timeout: 60000
-- tapOn:
- id: custom-header-back
+- runFlow: '../../helpers/go-back.yaml'
- extendedWaitUntil:
visible:
id: 'room-view-messages'
timeout: 60000
-- tapOn:
- id: header-back
+- runFlow: '../../helpers/go-back.yaml'
- extendedWaitUntil:
visible:
id: 'rooms-list-view'
@@ -283,12 +273,7 @@ tags:
ROOM: ${output.room.name}
# should navigate to DiscussionsView
-- extendedWaitUntil:
- visible:
- id: 'room-header'
- timeout: 60000
-- tapOn:
- id: 'room-header'
+- runFlow: '../../helpers/open-room-actions.yaml'
- extendedWaitUntil:
visible:
id: 'room-actions-discussions'
@@ -307,7 +292,7 @@ tags:
timeout: 60000
- tapOn:
id: 'discussions-view-${output.discussionFromNewMessage}'
-- extendedWaitUntil:
- visible:
- id: 'room-view-title-${output.discussionFromNewMessage}'
- timeout: 60000
+- runFlow:
+ file: '../../helpers/assert-room-title.yaml'
+ env:
+ ROOM: ${output.discussionFromNewMessage}
diff --git a/.maestro/tests/room/ignoreuser.yaml b/.maestro/tests/room/ignoreuser.yaml
index f2ea05b2a37..90fe1d4b380 100644
--- a/.maestro/tests/room/ignoreuser.yaml
+++ b/.maestro/tests/room/ignoreuser.yaml
@@ -224,10 +224,10 @@ tags:
timeout: 60000
- tapOn:
id: 'report-user-view-submit'
-- extendedWaitUntil:
- visible:
- id: 'room-view-title-${output.otherUser.username}'
- timeout: 60000
+- runFlow:
+ file: '../../helpers/assert-room-title.yaml'
+ env:
+ ROOM: ${output.otherUser.username}
# should go to user info view from a channel
- runFlow: '../../helpers/go-back.yaml'
@@ -281,7 +281,7 @@ tags:
timeout: 60000
- tapOn:
id: 'report-user-view-submit'
-- extendedWaitUntil:
- visible:
- id: 'room-view-title-${output.room.name}'
- timeout: 60000
+- runFlow:
+ file: '../../helpers/assert-room-title.yaml'
+ env:
+ ROOM: ${output.room.name}
diff --git a/.maestro/tests/room/jump-to-message.yaml b/.maestro/tests/room/jump-to-message.yaml
index e6cfb9dcd03..4c966f24015 100644
--- a/.maestro/tests/room/jump-to-message.yaml
+++ b/.maestro/tests/room/jump-to-message.yaml
@@ -85,12 +85,24 @@ tags:
file: '../../helpers/search-and-navigate-room.yaml'
env:
ROOM: 'jumping'
-- extendedWaitUntil:
- visible:
- id: 'room-view-search'
- timeout: 60000
-- tapOn:
- id: 'room-view-search'
+- runFlow:
+ when:
+ platform: iOS
+ commands:
+ - tapOn:
+ text: 'More'
+ - tapOn:
+ text: 'Search messages'
+- runFlow:
+ when:
+ platform: android
+ commands:
+ - extendedWaitUntil:
+ visible:
+ id: 'room-view-search'
+ timeout: 60000
+ - tapOn:
+ id: 'room-view-search'
- extendedWaitUntil:
visible:
id: 'search-messages-view'
@@ -183,8 +195,7 @@ tags:
visible:
id: 'message-content-202'
timeout: 60000
-- tapOn:
- id: header-back
+- runFlow: '../../helpers/go-back.yaml'
# should navigate to a thread from another room
- runFlow:
@@ -208,14 +219,13 @@ tags:
file: './utils/expect-thread-messages.yaml'
env:
message: Go to jumping-thread's thread
-- tapOn:
- id: header-back
+- runFlow: '../../helpers/go-back.yaml'
# should tap on thread message from main room
-- extendedWaitUntil:
- visible:
- id: 'room-view-title-jumping-thread'
- timeout: 60000
+- runFlow:
+ file: '../../helpers/assert-room-title.yaml'
+ env:
+ ROOM: 'jumping-thread'
- extendedWaitUntil:
visible:
text: '.*thread message sent to main room.*'
@@ -227,14 +237,13 @@ tags:
file: './utils/expect-thread-messages.yaml'
env:
message: 'thread message sent to main room'
-- tapOn:
- id: header-back
+- runFlow: '../../helpers/go-back.yaml'
# should tap on quote
-- extendedWaitUntil:
- visible:
- id: 'room-view-title-jumping-thread'
- timeout: 60000
+- runFlow:
+ file: '../../helpers/assert-room-title.yaml'
+ env:
+ ROOM: 'jumping-thread'
- extendedWaitUntil:
visible:
id: '.*reply-.*-quoted.*'
@@ -252,16 +261,27 @@ tags:
file: './utils/expect-thread-messages.yaml'
env:
message: 'quoted'
-- tapOn:
- id: 'header-back'
+- runFlow: '../../helpers/go-back.yaml'
# should jump from search message
-- extendedWaitUntil:
- visible:
- id: 'room-view-title-jumping-thread'
- timeout: 60000
-- tapOn:
- id: 'room-view-search'
+- runFlow:
+ file: '../../helpers/assert-room-title.yaml'
+ env:
+ ROOM: 'jumping-thread'
+- runFlow:
+ when:
+ platform: iOS
+ commands:
+ - tapOn:
+ text: 'More'
+ - tapOn:
+ text: 'Search messages'
+- runFlow:
+ when:
+ platform: android
+ commands:
+ - tapOn:
+ id: 'room-view-search'
- extendedWaitUntil:
visible:
id: 'search-messages-view'
diff --git a/.maestro/tests/room/message-markdown-click.yaml b/.maestro/tests/room/message-markdown-click.yaml
index f0a746f2648..c6ea511cd20 100644
--- a/.maestro/tests/room/message-markdown-click.yaml
+++ b/.maestro/tests/room/message-markdown-click.yaml
@@ -57,14 +57,13 @@ tags:
text: '.*detox-public.*'
# Go back to room
-- tapOn:
- id: custom-header-back
+- runFlow: '../../helpers/go-back.yaml'
# Wait for room view to be visible again
-- extendedWaitUntil:
- visible:
- id: 'room-view-title-maestro-message-clickable-test'
- timeout: 60000
+- runFlow:
+ file: '../../helpers/assert-room-title.yaml'
+ env:
+ ROOM: maestro-message-clickable-test
# Tap on the URL link to open alert
- runFlow:
@@ -137,61 +136,58 @@ tags:
text: '.*e2e_admin.*'
# Go back to room
-- tapOn:
- id: custom-header-back
+- runFlow: '../../helpers/go-back.yaml'
# Wait for room view to be visible again
-- extendedWaitUntil:
- visible:
- id: 'room-view-title-maestro-message-clickable-test'
- timeout: 60000
+- runFlow:
+ file: '../../helpers/assert-room-title.yaml'
+ env:
+ ROOM: maestro-message-clickable-test
# Tap on message with thread to open thread room
- tapOn:
text: '.*Message with thread*.'
# Verify thread room view is opened with the correct id
-- extendedWaitUntil:
- visible:
- id: 'room-view-title-message with thread'
- timeout: 60000
+- runFlow:
+ file: '../../helpers/assert-room-title.yaml'
+ env:
+ ROOM: message with thread
# Go back to main room
-- tapOn:
- id: header-back
+- runFlow: '../../helpers/go-back.yaml'
# Wait for room view to be visible again
-- extendedWaitUntil:
- visible:
- id: 'room-view-title-maestro-message-clickable-test'
- timeout: 60000
+- runFlow:
+ file: '../../helpers/assert-room-title.yaml'
+ env:
+ ROOM: maestro-message-clickable-test
# Tap on "View thread" button
- tapOn:
id: 'message-thread-button-message with thread'
# Verify thread room view is opened
-- extendedWaitUntil:
- visible:
- id: 'room-view-title-message with thread'
- timeout: 60000
+- runFlow:
+ file: '../../helpers/assert-room-title.yaml'
+ env:
+ ROOM: message with thread
# Go back to main room
-- tapOn:
- id: header-back
+- runFlow: '../../helpers/go-back.yaml'
# Wait for room view to be visible again
-- extendedWaitUntil:
- visible:
- id: 'room-view-title-maestro-message-clickable-test'
- timeout: 60000
+- runFlow:
+ file: '../../helpers/assert-room-title.yaml'
+ env:
+ ROOM: maestro-message-clickable-test
# Now tap on a message within the thread
- tapOn:
text: '.*a message in thread*.'
# Verify thread room view remains (clicking message in thread stays in thread)
-- extendedWaitUntil:
- visible:
- id: 'room-view-title-message with thread'
- timeout: 60000
+- runFlow:
+ file: '../../helpers/assert-room-title.yaml'
+ env:
+ ROOM: message with thread
diff --git a/.maestro/tests/room/room-actions.yaml b/.maestro/tests/room/room-actions.yaml
index 52a1d7332a9..cb0110a1a34 100644
--- a/.maestro/tests/room/room-actions.yaml
+++ b/.maestro/tests/room/room-actions.yaml
@@ -93,14 +93,12 @@ tags:
visible:
id: 'mentioned-messages-view'
timeout: 60000
-- tapOn:
- id: custom-header-back
+- runFlow: '../../helpers/go-back.yaml'
- extendedWaitUntil:
visible:
id: 'room-actions-view'
timeout: 60000
-- tapOn:
- id: custom-header-back
+- runFlow: '../../helpers/go-back.yaml'
# should star and show in starred message
- runFlow:
@@ -131,12 +129,7 @@ tags:
notVisible:
text: '.*Message Starred.*'
timeout: 60000
-- tapOn:
- id: 'room-header'
-- extendedWaitUntil:
- visible:
- id: 'room-actions-view'
- timeout: 60000
+- runFlow: '../../helpers/open-room-actions.yaml'
- tapOn:
id: 'room-actions-starred'
retryTapIfNoChange: true
@@ -149,14 +142,12 @@ tags:
id: 'message-content-messageToStar'
timeout: 60000
# should unstar
-- tapOn:
- id: custom-header-back
+- runFlow: '../../helpers/go-back.yaml'
- extendedWaitUntil:
visible:
id: 'room-actions-view'
timeout: 60000
-- tapOn:
- id: custom-header-back
+- runFlow: '../../helpers/go-back.yaml'
- extendedWaitUntil:
visible:
id: message-content-messageToStar
@@ -181,12 +172,7 @@ tags:
notVisible:
text: '.*Message Unstarred.*'
timeout: 60000
-- tapOn:
- id: 'room-header'
-- extendedWaitUntil:
- visible:
- id: 'room-actions-view'
- timeout: 60000
+- runFlow: '../../helpers/open-room-actions.yaml'
- tapOn:
id: 'room-actions-starred'
retryTapIfNoChange: true
@@ -198,14 +184,12 @@ tags:
notVisible:
id: 'message-content-messageToStar'
timeout: 60000
-- tapOn:
- id: custom-header-back
+- runFlow: '../../helpers/go-back.yaml'
- extendedWaitUntil:
visible:
id: 'room-actions-view'
timeout: 60000
-- tapOn:
- id: custom-header-back
+- runFlow: '../../helpers/go-back.yaml'
# should pin a message and show in pinned
- runFlow:
@@ -236,12 +220,7 @@ tags:
visible:
text: '.*Pinned a message:.*'
timeout: 60000
-- tapOn:
- id: 'room-header'
-- extendedWaitUntil:
- visible:
- id: 'room-actions-view'
- timeout: 60000
+- runFlow: '../../helpers/open-room-actions.yaml'
- tapOn: Pinned
- extendedWaitUntil:
visible:
@@ -261,8 +240,7 @@ tags:
notVisible:
id: 'message-content-messageToPin'
timeout: 60000
-- tapOn:
- id: 'custom-header-back'
+- runFlow: '../../helpers/go-back.yaml'
- extendedWaitUntil:
visible:
id: 'room-actions-view'
@@ -324,8 +302,7 @@ tags:
id: 'notification-preference-view-email-alert'
timeout: 60000
-- tapOn:
- id: custom-header-back
+- runFlow: '../../helpers/go-back.yaml'
- extendedWaitUntil:
visible:
id: 'room-actions-view'
@@ -387,12 +364,10 @@ tags:
visible:
id: 'selected-user-rocket.cat'
timeout: 60000
-- extendedWaitUntil:
- visible:
- id: 'select-users-view-search'
- timeout: 60000
-- tapOn:
- id: select-users-view-search
+- runFlow:
+ file: '../../helpers/tap-search-field.yaml'
+ env:
+ SEARCH_ID: 'select-users-view-search'
- inputText: ${output.otherUser.username}
- extendedWaitUntil:
visible:
@@ -404,10 +379,12 @@ tags:
visible:
id: 'selected-user-${output.otherUser.username}'
timeout: 60000
-- tapOn:
- id: selected-users-view-submit
-- tapOn:
- id: custom-header-back
+- runFlow:
+ file: '../../helpers/tap-header-item.yaml'
+ env:
+ ANDROID_ID: 'selected-users-view-submit'
+ IOS_LABEL: 'Next'
+- runFlow: '../../helpers/go-back.yaml'
- extendedWaitUntil:
visible:
text: '.*3 members.*'
@@ -420,18 +397,12 @@ tags:
visible:
id: 'room-members-view'
timeout: 60000
-- extendedWaitUntil:
- visible:
- id: 'room-members-view-filter'
- timeout: 60000
-- tapOn:
- id: 'room-members-view-filter'
-- extendedWaitUntil:
- visible:
- id: 'room-members-view-toggle-status-all'
- timeout: 60000
-- tapOn:
- id: 'room-members-view-toggle-status-all'
+- runFlow:
+ file: '../../helpers/select-header-filter.yaml'
+ env:
+ ANDROID_FILTER_ID: 'room-members-view-filter'
+ ANDROID_OPTION_ID: 'room-members-view-toggle-status-all'
+ IOS_OPTION: 'All'
- extendedWaitUntil:
notVisible:
id: 'room-members-view-toggle-status-all'
@@ -440,8 +411,7 @@ tags:
visible:
id: 'room-members-view-item-${output.otherUser.username}'
timeout: 60000
-- tapOn:
- id: 'custom-header-back'
+- runFlow: '../../helpers/go-back.yaml'
# should filter user
- tapOn:
@@ -450,12 +420,10 @@ tags:
visible:
id: 'room-members-view'
timeout: 60000
-- extendedWaitUntil:
- visible:
- id: 'room-members-view-search'
- timeout: 60000
-- tapOn:
- id: room-members-view-search
+- runFlow:
+ file: '../../helpers/tap-search-field.yaml'
+ env:
+ SEARCH_ID: 'room-members-view-search'
- inputText: 'rocket'
- tapOn:
id: room-members-view
@@ -467,8 +435,7 @@ tags:
notVisible:
id: 'room-members-view-item-${output.otherUser.username}'
timeout: 60000
-- tapOn:
- id: clear-text-input
+- runFlow: '../../helpers/clear-search-field.yaml'
- extendedWaitUntil:
visible:
id: 'room-members-view-item-rocket.cat'
@@ -697,14 +664,12 @@ tags:
visible:
text: 'User has been ignored'
timeout: 60000
-- tapOn:
- id: custom-header-back
+- runFlow: '../../helpers/go-back.yaml'
- extendedWaitUntil:
visible:
id: 'room-actions-view'
timeout: 60000
-- tapOn:
- id: custom-header-back
+- runFlow: '../../helpers/go-back.yaml'
- extendedWaitUntil:
visible:
text: '.*Message ignored. Tap to display it.*'
@@ -717,12 +682,7 @@ tags:
timeout: 60000
# should navigate to direct message
-- tapOn:
- id: 'room-header'
-- extendedWaitUntil:
- visible:
- id: 'room-actions-view'
- timeout: 60000
+- runFlow: '../../helpers/open-room-actions.yaml'
- tapOn:
id: 'room-actions-members'
- extendedWaitUntil:
@@ -745,10 +705,10 @@ tags:
visible:
id: 'room-view'
timeout: 60000
-- extendedWaitUntil:
- visible:
- id: 'room-view-title-${output.otherUser.username}'
- timeout: 60000
+- runFlow:
+ file: '../../helpers/assert-room-title.yaml'
+ env:
+ ROOM: ${output.otherUser.username}
- tapOn: Back
- extendedWaitUntil:
visible:
diff --git a/.maestro/tests/room/room-info.yaml b/.maestro/tests/room/room-info.yaml
index 7859a2a7fa1..0078cc1f46f 100644
--- a/.maestro/tests/room/room-info.yaml
+++ b/.maestro/tests/room/room-info.yaml
@@ -141,8 +141,7 @@ tags:
timeout: 60000
# should reset form
-- tapOn:
- id: custom-header-back
+- runFlow: '../../helpers/go-back.yaml'
- tapOn:
id: room-info-view-edit-button
- extendedWaitUntil:
@@ -278,8 +277,7 @@ tags:
id: 'room-info-edit-view-react-when-ro'
# should change room name
-- tapOn:
- id: custom-header-back
+- runFlow: '../../helpers/go-back.yaml'
- tapOn:
id: room-info-view-edit-button
- evalScript: ${output.newroomname = output.room.name + 'new'}
@@ -305,8 +303,7 @@ tags:
visible:
text: '.*Settings succesfully changed.*'
timeout: 60000
-- tapOn:
- id: custom-header-back
+- runFlow: '../../helpers/go-back.yaml'
- extendedWaitUntil:
visible:
id: 'room-info-view'
@@ -367,8 +364,7 @@ tags:
visible:
text: '.*Settings succesfully changed.*'
timeout: 60000
-- tapOn:
- id: custom-header-back
+- runFlow: '../../helpers/go-back.yaml'
- extendedWaitUntil:
visible:
id: 'room-info-view'
diff --git a/.maestro/tests/room/room.yaml b/.maestro/tests/room/room.yaml
index a719d7f004c..092470c6269 100644
--- a/.maestro/tests/room/room.yaml
+++ b/.maestro/tests/room/room.yaml
@@ -483,10 +483,10 @@ tags:
timeout: 60000
- tapOn:
id: message-actions-reply-in-dm
-- extendedWaitUntil:
- visible:
- id: room-view-title-${output.replyUser.username}
- timeout: 60000
+- runFlow:
+ file: '../../helpers/assert-room-title.yaml'
+ env:
+ ROOM: ${output.replyUser.username}
- extendedWaitUntil:
visible:
id: message-composer-input
diff --git a/.maestro/tests/room/search-member.yaml b/.maestro/tests/room/search-member.yaml
index 40c7e07a35f..9fe42658adc 100644
--- a/.maestro/tests/room/search-member.yaml
+++ b/.maestro/tests/room/search-member.yaml
@@ -20,22 +20,15 @@ tags:
file: '../../helpers/navigate-to-room.yaml'
env:
ROOM: 'general'
-- tapOn:
- id: room-header
-- extendedWaitUntil:
- visible:
- id: 'room-actions-view'
- timeout: 60000
+- runFlow: '../../helpers/open-room-actions.yaml'
- tapOn:
id: 'room-actions-members'
-- extendedWaitUntil:
- visible:
- id: 'room-members-view-search'
- timeout: 60000
# should search in all users
-- tapOn:
- id: room-members-view-search
+- runFlow:
+ file: '../../helpers/tap-search-field.yaml'
+ env:
+ SEARCH_ID: 'room-members-view-search'
- inputText: rohit.bansal
- extendedWaitUntil:
visible:
@@ -43,40 +36,37 @@ tags:
timeout: 60000
# use online status and it should use the text filter
-- tapOn:
- id: room-members-view-filter
-- extendedWaitUntil:
- visible:
- id: 'room-members-view-toggle-status-online'
- timeout: 60000
-- tapOn:
- id: room-members-view-toggle-status-online
+- runFlow:
+ file: '../../helpers/select-header-filter.yaml'
+ env:
+ ANDROID_FILTER_ID: 'room-members-view-filter'
+ ANDROID_OPTION_ID: 'room-members-view-toggle-status-online'
+ IOS_OPTION: 'Online'
- extendedWaitUntil:
visible:
text: 'No members found'
timeout: 60000
# use all status again and it should use text filter
-- tapOn:
- id: room-members-view-filter
-- extendedWaitUntil:
- visible:
- id: 'room-members-view-toggle-status-all'
- timeout: 60000
-- tapOn:
- id: room-members-view-toggle-status-all
+- runFlow:
+ file: '../../helpers/select-header-filter.yaml'
+ env:
+ ANDROID_FILTER_ID: 'room-members-view-filter'
+ ANDROID_OPTION_ID: 'room-members-view-toggle-status-all'
+ IOS_OPTION: 'All'
- extendedWaitUntil:
visible:
id: 'room-members-view-item-rohit.bansal'
timeout: 60000
-- tapOn:
- id: clear-text-input
+- runFlow: '../../helpers/clear-search-field.yaml'
- evalScript: ${output.secondUser = output.utils.createUser()}
# should search for new user in all list
-- tapOn:
- id: room-members-view-search
+- runFlow:
+ file: '../../helpers/tap-search-field.yaml'
+ env:
+ SEARCH_ID: 'room-members-view-search'
- inputText: ${output.secondUser.username}
- extendedWaitUntil:
visible:
@@ -84,8 +74,10 @@ tags:
timeout: 60000
# Verify "No members found" message appears correctly when search returns no results
-- tapOn:
- id: room-members-view-search
+- runFlow:
+ file: '../../helpers/tap-search-field.yaml'
+ env:
+ SEARCH_ID: 'room-members-view-search'
- inputText: nonexistentuser12345
- extendedWaitUntil:
visible:
diff --git a/.maestro/tests/room/servers-list-small-screen.yaml b/.maestro/tests/room/servers-list-small-screen.yaml
index 685822b104b..ed2c7216818 100644
--- a/.maestro/tests/room/servers-list-small-screen.yaml
+++ b/.maestro/tests/room/servers-list-small-screen.yaml
@@ -20,12 +20,7 @@ tags:
# should fully render the Workspaces action sheet on small screens
# (regression for small-screen ServersList — the Add Server button was cut off on iPhone SE)
-- extendedWaitUntil:
- visible:
- id: 'rooms-list-header-servers-list-button'
- timeout: 60000
-- tapOn:
- id: 'rooms-list-header-servers-list-button'
+- runFlow: '../../helpers/open-servers-list.yaml'
- waitForAnimationToEnd
- extendedWaitUntil:
visible:
diff --git a/.maestro/tests/room/share-message.yaml b/.maestro/tests/room/share-message.yaml
index 461818f2f37..0448192fe26 100644
--- a/.maestro/tests/room/share-message.yaml
+++ b/.maestro/tests/room/share-message.yaml
@@ -89,10 +89,10 @@ tags:
timeout: 60000
- tapOn:
id: 'forward-message-view-send'
-- extendedWaitUntil:
- visible:
- id: 'room-view-title-${output.room.name}'
- timeout: 60000
+- runFlow:
+ file: '../../helpers/assert-room-title.yaml'
+ env:
+ ROOM: ${output.room.name}
# should go to otherUser DM and verify if exist both messages
- runFlow: '../../helpers/go-back.yaml'
diff --git a/.maestro/tests/room/threads.yaml b/.maestro/tests/room/threads.yaml
index f45f17151b4..181e690beda 100644
--- a/.maestro/tests/room/threads.yaml
+++ b/.maestro/tests/room/threads.yaml
@@ -23,22 +23,46 @@ tags:
ROOM: ${output.room.name}
# should have room screen
-- extendedWaitUntil:
- visible:
- id: 'room-view-title-${output.room.name}'
- timeout: 60000
+- runFlow:
+ file: '../../helpers/assert-room-title.yaml'
+ env:
+ ROOM: ${output.room.name}
# should have actions button
-- extendedWaitUntil:
- visible:
- id: 'room-header'
- timeout: 60000
+- runFlow:
+ when:
+ platform: android
+ commands:
+ - extendedWaitUntil:
+ visible:
+ id: 'room-header'
+ timeout: 60000
+- runFlow:
+ when:
+ platform: iOS
+ commands:
+ - extendedWaitUntil:
+ visible:
+ text: 'More'
+ timeout: 60000
# should have threads button
-- extendedWaitUntil:
- visible:
- id: 'room-view-header-threads'
- timeout: 60000
+- runFlow:
+ when:
+ platform: android
+ commands:
+ - extendedWaitUntil:
+ visible:
+ id: 'room-view-header-threads'
+ timeout: 60000
+- runFlow:
+ when:
+ platform: iOS
+ commands:
+ - extendedWaitUntil:
+ visible:
+ text: 'Threads'
+ timeout: 60000
# should create thread
- runFlow:
@@ -61,10 +85,10 @@ tags:
timeout: 60000
- tapOn:
text: 'Reply in thread'
-- extendedWaitUntil:
- visible:
- id: 'room-view-title-thread'
- timeout: 60000
+- runFlow:
+ file: '../../helpers/assert-room-title.yaml'
+ env:
+ ROOM: 'thread'
- extendedWaitUntil:
visible:
id: 'message-composer-input-thread'
@@ -78,41 +102,50 @@ tags:
visible:
id: 'message-content-replied'
timeout: 60000
-- tapOn:
- id: 'header-back'
+- runFlow: '../../helpers/go-back.yaml'
# should navigate to thread from button
-- extendedWaitUntil:
- visible:
- id: 'room-view-title-${output.room.name}'
- timeout: 60000
+- runFlow:
+ file: '../../helpers/assert-room-title.yaml'
+ env:
+ ROOM: ${output.room.name}
- extendedWaitUntil:
visible:
id: 'message-thread-button-thread'
timeout: 60000
- tapOn:
id: 'message-thread-button-thread'
-- extendedWaitUntil:
- visible:
- id: 'room-view-title-thread'
- timeout: 60000
+- runFlow:
+ file: '../../helpers/assert-room-title.yaml'
+ env:
+ ROOM: 'thread'
# should toggle follow thread
-- extendedWaitUntil:
- visible:
- id: 'room-view-header-unfollow'
- timeout: 60000
-- tapOn:
- id: 'room-view-header-unfollow'
-- extendedWaitUntil:
- visible:
- id: 'room-view-header-follow'
- timeout: 60000
-- tapOn:
- id: 'room-view-header-follow'
-- extendedWaitUntil:
- visible:
- id: 'room-view-header-unfollow'
- timeout: 60000
+- runFlow:
+ file: '../../helpers/tap-header-item.yaml'
+ env:
+ ANDROID_ID: 'room-view-header-unfollow'
+ IOS_LABEL: 'Unfollow thread'
+- runFlow:
+ file: '../../helpers/tap-header-item.yaml'
+ env:
+ ANDROID_ID: 'room-view-header-follow'
+ IOS_LABEL: 'Follow thread'
+- runFlow:
+ when:
+ platform: android
+ commands:
+ - extendedWaitUntil:
+ visible:
+ id: 'room-view-header-unfollow'
+ timeout: 60000
+- runFlow:
+ when:
+ platform: iOS
+ commands:
+ - extendedWaitUntil:
+ visible:
+ text: 'Unfollow thread'
+ timeout: 60000
# should send message in thread only
- runFlow:
@@ -120,16 +153,27 @@ tags:
env:
message: threadonly
isThread: 'true'
-- tapOn:
- id: 'header-back'
-- extendedWaitUntil:
- notVisible:
- id: 'room-view-title-thread'
- timeout: 5000
-- extendedWaitUntil:
- visible:
- id: 'room-view-title-${output.room.name}'
- timeout: 5000
+- runFlow: '../../helpers/go-back.yaml'
+- runFlow:
+ when:
+ platform: android
+ commands:
+ - extendedWaitUntil:
+ notVisible:
+ id: 'room-view-title-thread'
+ timeout: 5000
+- runFlow:
+ when:
+ platform: iOS
+ commands:
+ - extendedWaitUntil:
+ notVisible:
+ text: 'thread'
+ timeout: 5000
+- runFlow:
+ file: '../../helpers/assert-room-title.yaml'
+ env:
+ ROOM: ${output.room.name}
- extendedWaitUntil:
notVisible:
id: 'message-content-threadonly'
@@ -142,10 +186,10 @@ tags:
timeout: 60000
- tapOn:
id: 'message-thread-button-thread'
-- extendedWaitUntil:
- visible:
- id: 'room-view-title-thread'
- timeout: 60000
+- runFlow:
+ file: '../../helpers/assert-room-title.yaml'
+ env:
+ ROOM: 'thread'
- tapOn:
id: 'message-composer-input-thread'
- inputText: 'sendToChannel'
@@ -153,16 +197,27 @@ tags:
id: send-to-channel-unchecked
- tapOn:
id: message-composer-send
-- tapOn:
- id: header-back
-- extendedWaitUntil:
- notVisible:
- id: 'room-view-title-thread'
- timeout: 5000
-- extendedWaitUntil:
- visible:
- id: 'room-view-title-${output.room.name}'
- timeout: 5000
+- runFlow: '../../helpers/go-back.yaml'
+- runFlow:
+ when:
+ platform: android
+ commands:
+ - extendedWaitUntil:
+ notVisible:
+ id: 'room-view-title-thread'
+ timeout: 5000
+- runFlow:
+ when:
+ platform: iOS
+ commands:
+ - extendedWaitUntil:
+ notVisible:
+ text: 'thread'
+ timeout: 5000
+- runFlow:
+ file: '../../helpers/assert-room-title.yaml'
+ env:
+ ROOM: ${output.room.name}
- extendedWaitUntil:
visible:
text: '.*sendToChannel.*'
@@ -186,36 +241,45 @@ tags:
id: 'message-composer-send-to-channel'
- tapOn:
id: 'message-composer-send'
-- tapOn:
- id: 'header-back'
-- extendedWaitUntil:
- notVisible:
- id: 'room-view-title-thread'
- timeout: 60000
-- extendedWaitUntil:
- visible:
- id: 'room-view-title-${output.room.name}'
- timeout: 60000
+- runFlow: '../../helpers/go-back.yaml'
+- runFlow:
+ when:
+ platform: android
+ commands:
+ - extendedWaitUntil:
+ notVisible:
+ id: 'room-view-title-thread'
+ timeout: 60000
+- runFlow:
+ when:
+ platform: iOS
+ commands:
+ - extendedWaitUntil:
+ notVisible:
+ text: 'thread'
+ timeout: 60000
+- runFlow:
+ file: '../../helpers/assert-room-title.yaml'
+ env:
+ ROOM: ${output.room.name}
- extendedWaitUntil:
visible:
id: 'message-content-navthreadname'
timeout: 60000
- tapOn:
id: 'message-content-navthreadname'
-- extendedWaitUntil:
- visible:
- id: 'room-view-title-thread'
- timeout: 60000
-- tapOn:
- id: 'header-back'
+- runFlow:
+ file: '../../helpers/assert-room-title.yaml'
+ env:
+ ROOM: 'thread'
+- runFlow: '../../helpers/go-back.yaml'
# should navigate to thread from threads view
-- extendedWaitUntil:
- visible:
- id: 'room-view-header-threads'
- timeout: 60000
-- tapOn:
- id: 'room-view-header-threads'
+- runFlow:
+ file: '../../helpers/tap-header-item.yaml'
+ env:
+ ANDROID_ID: 'room-view-header-threads'
+ IOS_LABEL: 'Threads'
- extendedWaitUntil:
visible:
id: 'thread-messages-view'
@@ -226,12 +290,11 @@ tags:
timeout: 60000
- tapOn:
id: 'thread-messages-view-thread'
-- extendedWaitUntil:
- visible:
- id: 'room-view-title-thread'
- timeout: 60000
-- tapOn:
- id: 'header-back'
+- runFlow:
+ file: '../../helpers/assert-room-title.yaml'
+ env:
+ ROOM: 'thread'
+- runFlow: '../../helpers/go-back.yaml'
- extendedWaitUntil:
visible:
id: 'room-view-messages'
@@ -244,15 +307,14 @@ tags:
timeout: 60000
- tapOn:
id: 'message-thread-button-thread'
-- extendedWaitUntil:
- visible:
- id: 'room-view-title-thread'
- timeout: 60000
+- runFlow:
+ file: '../../helpers/assert-room-title.yaml'
+ env:
+ ROOM: 'thread'
- tapOn:
id: 'message-composer-input-thread'
- inputText: 'draftthread'
-- tapOn:
- id: 'header-back'
+- runFlow: '../../helpers/go-back.yaml'
- extendedWaitUntil:
visible:
@@ -260,10 +322,10 @@ tags:
timeout: 60000
- tapOn:
id: 'message-thread-button-thread'
-- extendedWaitUntil:
- visible:
- id: 'room-view-title-thread'
- timeout: 60000
+- runFlow:
+ file: '../../helpers/assert-room-title.yaml'
+ env:
+ ROOM: 'thread'
- extendedWaitUntil:
visible:
text: '.*draftthread.*'
@@ -271,8 +333,7 @@ tags:
- tapOn:
id: 'message-composer-input-thread'
- eraseText
-- tapOn:
- id: 'header-back'
+- runFlow: '../../helpers/go-back.yaml'
- extendedWaitUntil:
visible:
@@ -280,10 +341,10 @@ tags:
timeout: 60000
- tapOn:
id: 'message-thread-button-thread'
-- extendedWaitUntil:
- visible:
- id: 'room-view-title-thread'
- timeout: 60000
+- runFlow:
+ file: '../../helpers/assert-room-title.yaml'
+ env:
+ ROOM: 'thread'
- extendedWaitUntil:
notVisible:
text: '.*draftthread.*'
@@ -292,16 +353,27 @@ tags:
visible:
text: '.*Add thread reply.*'
timeout: 60000
-- tapOn:
- id: 'header-back'
-- extendedWaitUntil:
- notVisible:
- id: 'room-view-title-thread'
- timeout: 60000
-- extendedWaitUntil:
- visible:
- id: 'room-view-title-${output.room.name}'
- timeout: 60000
+- runFlow: '../../helpers/go-back.yaml'
+- runFlow:
+ when:
+ platform: android
+ commands:
+ - extendedWaitUntil:
+ notVisible:
+ id: 'room-view-title-thread'
+ timeout: 60000
+- runFlow:
+ when:
+ platform: iOS
+ commands:
+ - extendedWaitUntil:
+ notVisible:
+ text: 'thread'
+ timeout: 60000
+- runFlow:
+ file: '../../helpers/assert-room-title.yaml'
+ env:
+ ROOM: ${output.room.name}
# should create thread delete the message and the thread show the correct number of messages
- runFlow:
@@ -324,10 +396,10 @@ tags:
timeout: 60000
- tapOn:
text: 'Reply in thread'
-- extendedWaitUntil:
- visible:
- id: 'room-view-title-thread-message-count'
- timeout: 60000
+- runFlow:
+ file: '../../helpers/assert-room-title.yaml'
+ env:
+ ROOM: 'thread-message-count'
- extendedWaitUntil:
visible:
id: 'message-composer-input-thread'
@@ -374,12 +446,11 @@ tags:
text: '.*You will not be able to recover this message.*'
timeout: 60000
- tapOn: 'DELETE'
-- tapOn:
- id: 'header-back'
-- extendedWaitUntil:
- visible:
- id: 'room-view-title-${output.room.name}'
- timeout: 60000
+- runFlow: '../../helpers/go-back.yaml'
+- runFlow:
+ file: '../../helpers/assert-room-title.yaml'
+ env:
+ ROOM: ${output.room.name}
- extendedWaitUntil:
visible:
id: 'thread-count-0'
diff --git a/.maestro/tests/room/unread-badge.yaml b/.maestro/tests/room/unread-badge.yaml
index c52cfff178b..f0054edfa1b 100644
--- a/.maestro/tests/room/unread-badge.yaml
+++ b/.maestro/tests/room/unread-badge.yaml
@@ -34,9 +34,7 @@ tags:
timeout: 60000
- tapOn:
id: 'rooms-list-view-item-${output.otherUser.username}'
-- tapOn:
- id: header-back
- retryTapIfNoChange: true
+- runFlow: '../../helpers/go-back.yaml'
- waitForAnimationToEnd:
timeout: 5000
- extendedWaitUntil:
@@ -62,9 +60,7 @@ tags:
timeout: 60000
- tapOn:
id: 'rooms-list-view-item-${output.otherUser.username}'
-- tapOn:
- id: header-back
- retryTapIfNoChange: true
+- runFlow: '../../helpers/go-back.yaml'
- waitForAnimationToEnd:
timeout: 5000
- extendedWaitUntil:
@@ -91,9 +87,7 @@ tags:
timeout: 60000
- tapOn:
id: 'rooms-list-view-item-${output.otherUser.username}'
-- tapOn:
- id: header-back
- retryTapIfNoChange: true
+- runFlow: '../../helpers/go-back.yaml'
- waitForAnimationToEnd:
timeout: 5000
- extendedWaitUntil:
@@ -120,9 +114,7 @@ tags:
timeout: 60000
- tapOn:
id: 'rooms-list-view-item-${output.otherUser.username}'
-- tapOn:
- id: header-back
- retryTapIfNoChange: true
+- runFlow: '../../helpers/go-back.yaml'
- waitForAnimationToEnd:
timeout: 5000
- extendedWaitUntil:
diff --git a/.maestro/tests/room/utils/clear-cache.yaml b/.maestro/tests/room/utils/clear-cache.yaml
index bf087ac3e01..d54f70f408a 100644
--- a/.maestro/tests/room/utils/clear-cache.yaml
+++ b/.maestro/tests/room/utils/clear-cache.yaml
@@ -8,14 +8,16 @@ tags:
visible:
id: 'room-view'
timeout: 60000
-- tapOn:
- id: 'header-back'
+- runFlow: '../../../helpers/go-back.yaml'
- extendedWaitUntil:
visible:
id: 'rooms-list-view'
timeout: 60000
-- tapOn:
- id: 'rooms-list-view-sidebar'
+- runFlow:
+ file: '../../../helpers/tap-header-item.yaml'
+ env:
+ ANDROID_ID: 'rooms-list-view-sidebar'
+ IOS_LABEL: 'Menu'
- waitForAnimationToEnd:
timeout: 60000
- extendedWaitUntil:
diff --git a/.maestro/tests/room/utils/expect-thread-messages.yaml b/.maestro/tests/room/utils/expect-thread-messages.yaml
index 5f3fbc3ae44..ec204c19e36 100644
--- a/.maestro/tests/room/utils/expect-thread-messages.yaml
+++ b/.maestro/tests/room/utils/expect-thread-messages.yaml
@@ -4,10 +4,10 @@ tags:
- 'util'
---
-- extendedWaitUntil:
- visible:
- id: 'room-view-title-thread 1'
- timeout: 60000
+- runFlow:
+ file: '../../../helpers/assert-room-title.yaml'
+ env:
+ ROOM: 'thread 1'
- extendedWaitUntil:
visible:
id: '.*message-content-${message}.*'
diff --git a/.maestro/tests/room/utils/navigate-to-info-view.yaml b/.maestro/tests/room/utils/navigate-to-info-view.yaml
index c2b33f0a718..71308b4d3dd 100644
--- a/.maestro/tests/room/utils/navigate-to-info-view.yaml
+++ b/.maestro/tests/room/utils/navigate-to-info-view.yaml
@@ -4,16 +4,7 @@ tags:
- 'util'
---
-- extendedWaitUntil:
- visible:
- id: room-header
- timeout: 60000
-- tapOn:
- id: room-header
-- extendedWaitUntil:
- visible:
- id: room-actions-view
- timeout: 60000
+- runFlow: '../../../helpers/open-room-actions.yaml'
- assertVisible:
id: room-actions-info
- tapOn:
diff --git a/.maestro/tests/room/utils/navigate-to-room-info.yaml b/.maestro/tests/room/utils/navigate-to-room-info.yaml
index b440852dcbe..4c419f0c9d2 100644
--- a/.maestro/tests/room/utils/navigate-to-room-info.yaml
+++ b/.maestro/tests/room/utils/navigate-to-room-info.yaml
@@ -8,16 +8,7 @@ tags:
file: '../../../helpers/search-and-navigate-room.yaml'
env:
ROOM: ${ROOM}
-- extendedWaitUntil:
- visible:
- id: 'room-header'
- timeout: 60000
-- tapOn:
- id: 'room-header'
-- extendedWaitUntil:
- visible:
- id: 'room-actions-view'
- timeout: 60000
+- runFlow: '../../../helpers/open-room-actions.yaml'
- extendedWaitUntil:
visible:
id: 'room-actions-info'
diff --git a/.maestro/tests/teams/convert-team.yaml b/.maestro/tests/teams/convert-team.yaml
index 9820ad29154..0442b800a1b 100644
--- a/.maestro/tests/teams/convert-team.yaml
+++ b/.maestro/tests/teams/convert-team.yaml
@@ -42,10 +42,10 @@ tags:
text: 'Convert'
- tapOn:
text: 'Convert'
-- extendedWaitUntil:
- visible:
- id: 'room-view-title-${output.publicChannelToBeConverted}'
- timeout: 60000
+- runFlow:
+ file: '../../helpers/assert-room-title.yaml'
+ env:
+ ROOM: ${output.publicChannelToBeConverted}
- runFlow: '../../helpers/go-back.yaml'
- extendedWaitUntil:
visible:
@@ -74,10 +74,10 @@ tags:
text: 'Convert'
- tapOn:
text: 'Convert'
-- extendedWaitUntil:
- visible:
- id: 'room-view-title-${output.toBeConverted}'
- timeout: 60000
+- runFlow:
+ file: '../../helpers/assert-room-title.yaml'
+ env:
+ ROOM: ${output.toBeConverted}
- runFlow: '../../helpers/go-back.yaml'
- extendedWaitUntil:
visible:
@@ -124,12 +124,7 @@ tags:
text: 'Yes, move it!'
- tapOn:
text: 'Yes, move it!'
-- extendedWaitUntil:
- visible:
- id: 'room-header'
- timeout: 60000
-- tapOn:
- id: 'room-header'
+- runFlow: '../../helpers/open-room-actions.yaml'
- extendedWaitUntil:
visible:
id: 'room-actions-teams'
@@ -178,10 +173,10 @@ tags:
visible:
id: 'room-view'
timeout: 60000
-- extendedWaitUntil:
- visible:
- id: 'room-view-title-${output.toBeConverted}'
- timeout: 60000
+- runFlow:
+ file: '../../helpers/assert-room-title.yaml'
+ env:
+ ROOM: ${output.toBeConverted}
- runFlow: '../../helpers/go-back.yaml'
- extendedWaitUntil:
visible:
diff --git a/.maestro/tests/teams/create-team.yaml b/.maestro/tests/teams/create-team.yaml
index a587cd06daf..1567dfdbab0 100644
--- a/.maestro/tests/teams/create-team.yaml
+++ b/.maestro/tests/teams/create-team.yaml
@@ -17,18 +17,22 @@ tags:
USERNAME: ${output.user.username}
PASSWORD: ${output.user.password}
-- assertVisible:
- id: 'rooms-list-view-create-channel'
-- tapOn:
- id: 'rooms-list-view-create-channel'
+- runFlow:
+ file: '../../helpers/tap-header-item.yaml'
+ env:
+ ANDROID_ID: 'rooms-list-view-create-channel'
+ IOS_LABEL: 'Create new channel, team, direct message or discussion'
- assertVisible:
id: 'new-message-view-create-team'
- tapOn:
id: 'new-message-view-create-team'
- assertVisible:
id: 'select-users-view'
-- tapOn:
- id: 'selected-users-view-submit'
+- runFlow:
+ file: '../../helpers/tap-header-item.yaml'
+ env:
+ ANDROID_ID: 'selected-users-view-submit'
+ IOS_LABEL: 'Skip'
- assertVisible:
id: 'create-channel-view'
- tapOn:
@@ -39,10 +43,11 @@ tags:
id: 'create-channel-submit'
- assertVisible:
id: 'room-view-messages'
-- assertVisible:
- id: 'room-view-title-${output.teamname}'
-- tapOn:
- id: 'room-header'
+- runFlow:
+ file: '../../helpers/assert-room-title.yaml'
+ env:
+ ROOM: ${output.teamname}
+- runFlow: '../../helpers/open-room-actions.yaml'
- assertVisible:
id: 'room-actions-info'
- tapOn:
diff --git a/.maestro/tests/teams/team.yaml b/.maestro/tests/teams/team.yaml
index 91274b1131c..650b443a944 100644
--- a/.maestro/tests/teams/team.yaml
+++ b/.maestro/tests/teams/team.yaml
@@ -25,18 +25,39 @@ tags:
ROOM: ${output.team}
# Team Header
-- assertVisible:
- id: room-header
-- assertVisible:
- id: room-view-header-call
-- assertVisible:
- id: room-view-header-threads
-- assertVisible:
- id: room-view-search
+- runFlow:
+ when:
+ platform: android
+ commands:
+ - assertVisible:
+ id: room-header
+ - assertVisible:
+ id: room-view-search
+ - assertVisible:
+ id: room-view-header-call
+ - assertVisible:
+ id: room-view-header-threads
+- runFlow:
+ when:
+ platform: iOS
+ commands:
+ - assertVisible:
+ text: '.*Call.*'
+ - assertVisible:
+ text: 'Threads'
+ - tapOn:
+ text: 'More'
+ - extendedWaitUntil:
+ visible:
+ id: 'action-sheet'
+ timeout: 60000
+ - assertVisible:
+ text: 'Search messages'
+ - tapOn:
+ id: 'action-sheet-handle'
# Team Action Usage
-- tapOn:
- id: room-header
+- runFlow: '../../helpers/open-room-actions.yaml'
- tapOn:
id: room-actions-teams
- extendedWaitUntil:
@@ -46,19 +67,48 @@ tags:
label: Should navigate to team channels view
# Team Channels Header
-- assertVisible:
- id: room-header
- label: Should have actions button
-- assertVisible:
- id: team-channels-view-create
- label: Should have team channels button
-- assertVisible:
- id: team-channels-view-search
- label: Should have search button
+- runFlow:
+ when:
+ platform: android
+ commands:
+ - assertVisible:
+ id: room-header
+ label: Should have actions button
+- runFlow:
+ when:
+ platform: android
+ commands:
+ - assertVisible:
+ id: team-channels-view-create
+ label: Should have team channels button
+- runFlow:
+ when:
+ platform: iOS
+ commands:
+ - assertVisible:
+ text: 'Add channel to team'
+ label: Should have team channels button
+- runFlow:
+ when:
+ platform: iOS
+ commands:
+ - assertVisible:
+ id: magnifyingglass
+ label: Should have system search bar
+- runFlow:
+ when:
+ platform: android
+ commands:
+ - assertVisible:
+ id: team-channels-view-search
+ label: Should have search button
# Team Channels Header Usage
-- tapOn:
- id: team-channels-view-create
+- runFlow:
+ file: '../../helpers/tap-header-item.yaml'
+ env:
+ ANDROID_ID: 'team-channels-view-create'
+ IOS_LABEL: 'Add channel to team'
- extendedWaitUntil:
visible:
id: add-channel-team-view
@@ -78,13 +128,11 @@ tags:
# Create new channel for team
- tapOn:
id: add-channel-team-view-create-channel
-- assertVisible:
- id: select-users-view-search
-- tapOn:
- id: select-users-view-search
-- inputText:
- id: select-users-view-search
- text: rocket.cat
+- runFlow:
+ file: '../../helpers/tap-search-field.yaml'
+ env:
+ SEARCH_ID: 'select-users-view-search'
+- inputText: rocket.cat
- extendedWaitUntil:
visible:
id: select-users-view-item-rocket.cat
@@ -95,8 +143,11 @@ tags:
visible:
id: selected-user-rocket.cat
timeout: 60000
-- tapOn:
- id: selected-users-view-submit
+- runFlow:
+ file: '../../helpers/tap-header-item.yaml'
+ env:
+ ANDROID_ID: 'selected-users-view-submit'
+ IOS_LABEL: 'Next'
- extendedWaitUntil:
visible:
id: create-channel-view
@@ -119,10 +170,19 @@ tags:
id: room-view
timeout: 60000
label: should navigate to room view
-- assertVisible:
- id: room-header
-- tapOn:
- id: room-header
+- runFlow:
+ when:
+ platform: android
+ commands:
+ - assertVisible:
+ id: room-header
+- runFlow:
+ when:
+ platform: iOS
+ commands:
+ - assertVisible:
+ text: 'More'
+- runFlow: '../../helpers/open-room-actions.yaml'
- assertVisible:
id: room-actions-teams
- tapOn:
@@ -141,18 +201,42 @@ tags:
id: rooms-list-view-item-${output.privateRoomName}
- tapOn:
id: rooms-list-view-item-${output.privateRoomName}
-- extendedWaitUntil:
- visible:
- id: room-view-title-${output.privateRoomName}
- timeout: 60000
-- assertVisible:
- id: room-view-title-${output.privateRoomName}
-- assertVisible:
- id: room-view-header-call
-- assertVisible:
- id: room-view-header-threads
-- assertVisible:
- id: room-view-search
+- runFlow:
+ file: '../../helpers/assert-room-title.yaml'
+ env:
+ ROOM: ${output.privateRoomName}
+- runFlow:
+ file: '../../helpers/assert-room-title.yaml'
+ env:
+ ROOM: ${output.privateRoomName}
+- runFlow:
+ when:
+ platform: android
+ commands:
+ - assertVisible:
+ id: room-view-header-call
+ - assertVisible:
+ id: room-view-header-threads
+ - assertVisible:
+ id: room-view-search
+- runFlow:
+ when:
+ platform: iOS
+ commands:
+ - assertVisible:
+ text: '.*Call.*'
+ - assertVisible:
+ text: 'Threads'
+ - tapOn:
+ text: 'More'
+ - extendedWaitUntil:
+ visible:
+ id: 'action-sheet'
+ timeout: 60000
+ - assertVisible:
+ text: 'Search messages'
+ - tapOn:
+ id: 'action-sheet-handle'
- runFlow: '../../helpers/go-back.yaml'
# should add existing channel to team
@@ -160,10 +244,19 @@ tags:
file: '../../helpers/navigate-to-room.yaml'
env:
ROOM: ${output.team}
-- assertVisible:
- id: room-header
-- tapOn:
- id: room-header
+- runFlow:
+ when:
+ platform: android
+ commands:
+ - assertVisible:
+ id: room-header
+- runFlow:
+ when:
+ platform: iOS
+ commands:
+ - assertVisible:
+ text: 'More'
+- runFlow: '../../helpers/open-room-actions.yaml'
- assertVisible:
id: room-actions-teams
- tapOn:
@@ -173,8 +266,11 @@ tags:
id: team-channels-view
timeout: 60000
label: Should navigate to team channels view
-- tapOn:
- id: team-channels-view-create
+- runFlow:
+ file: '../../helpers/tap-header-item.yaml'
+ env:
+ ANDROID_ID: 'team-channels-view-create'
+ IOS_LABEL: 'Add channel to team'
- extendedWaitUntil:
visible:
id: add-channel-team-view
@@ -198,12 +294,11 @@ tags:
label: should have submit button
- tapOn:
id: add-existing-channel-view-submit
-- extendedWaitUntil:
- visible:
- id: room-view-title-${output.team}
- timeout: 60000
-- tapOn:
- id: room-header
+- runFlow:
+ file: '../../helpers/assert-room-title.yaml'
+ env:
+ ROOM: ${output.team}
+- runFlow: '../../helpers/open-room-actions.yaml'
- assertVisible:
id: room-actions-teams
- tapOn:
@@ -272,12 +367,7 @@ tags:
visible:
id: room-view
timeout: 60000
-- tapOn:
- id: room-header
-- extendedWaitUntil:
- visible:
- id: room-actions-view
- timeout: 60000
+- runFlow: '../../helpers/open-room-actions.yaml'
# should add users to the team
- tapOn:
@@ -292,10 +382,10 @@ tags:
timeout: 60000
- tapOn:
id: room-actions-add-user
-- assertVisible:
- id: select-users-view-search
-- tapOn:
- id: select-users-view-search
+- runFlow:
+ file: '../../helpers/tap-search-field.yaml'
+ env:
+ SEARCH_ID: 'select-users-view-search'
- inputText: rocket.cat
- runFlow: '../../helpers/hide-keyboard.yaml'
- extendedWaitUntil:
@@ -308,12 +398,10 @@ tags:
visible:
id: selected-user-rocket.cat
timeout: 60000
-- extendedWaitUntil:
- visible:
- id: select-users-view-search
- timeout: 60000
-- tapOn:
- id: select-users-view-search
+- runFlow:
+ file: '../../helpers/tap-search-field.yaml'
+ env:
+ SEARCH_ID: 'select-users-view-search'
- eraseText
- inputText: ${output.secondUser.username}
- runFlow: '../../helpers/hide-keyboard.yaml'
@@ -327,21 +415,23 @@ tags:
visible:
id: selected-user-${output.secondUser.username}
timeout: 60000
-- assertVisible:
- id: selected-users-view-submit
-- tapOn:
- id: selected-users-view-submit
+- runFlow:
+ file: '../../helpers/wait-header-item.yaml'
+ env:
+ ANDROID_ID: 'selected-users-view-submit'
+ IOS_LABEL: 'Next'
+- runFlow:
+ file: '../../helpers/tap-header-item.yaml'
+ env:
+ ANDROID_ID: 'selected-users-view-submit'
+ IOS_LABEL: 'Next'
-- assertVisible:
- id: room-members-view-filter
-- tapOn:
- id: room-members-view-filter
-- extendedWaitUntil:
- visible:
- id: room-members-view-toggle-status-all
- timeout: 60000
-- tapOn:
- id: room-members-view-toggle-status-all
+- runFlow:
+ file: '../../helpers/select-header-filter.yaml'
+ env:
+ ANDROID_FILTER_ID: 'room-members-view-filter'
+ ANDROID_OPTION_ID: 'room-members-view-toggle-status-all'
+ IOS_OPTION: 'All'
- extendedWaitUntil:
visible:
id: room-members-view-item-${output.secondUser.username}
diff --git a/.maestro/tests/teams/utils/create-channel.yaml b/.maestro/tests/teams/utils/create-channel.yaml
index b84015412ad..18d8139ed92 100644
--- a/.maestro/tests/teams/utils/create-channel.yaml
+++ b/.maestro/tests/teams/utils/create-channel.yaml
@@ -3,12 +3,11 @@ tags:
- 'util'
---
-- extendedWaitUntil:
- visible:
- id: rooms-list-view-create-channel
- timeout: 60000
-- tapOn:
- id: rooms-list-view-create-channel
+- runFlow:
+ file: '../../../helpers/tap-header-item.yaml'
+ env:
+ ANDROID_ID: 'rooms-list-view-create-channel'
+ IOS_LABEL: 'Create new channel, team, direct message or discussion'
- extendedWaitUntil:
visible:
id: new-message-view
@@ -23,10 +22,16 @@ tags:
visible:
id: select-users-view
timeout: 60000
-- assertVisible:
- id: selected-users-view-submit
-- tapOn:
- id: selected-users-view-submit
+- runFlow:
+ file: '../../../helpers/wait-header-item.yaml'
+ env:
+ ANDROID_ID: 'selected-users-view-submit'
+ IOS_LABEL: 'Skip'
+- runFlow:
+ file: '../../../helpers/tap-header-item.yaml'
+ env:
+ ANDROID_ID: 'selected-users-view-submit'
+ IOS_LABEL: 'Skip'
- extendedWaitUntil:
visible:
id: create-channel-view
@@ -54,10 +59,10 @@ tags:
visible:
id: room-view
timeout: 60000
-- extendedWaitUntil:
- visible:
- id: room-view-title-${channelName}
- timeout: 60000
+- runFlow:
+ file: '../../../helpers/assert-room-title.yaml'
+ env:
+ ROOM: ${channelName}
- runFlow: ../../../helpers/go-back.yaml
- extendedWaitUntil:
visible:
diff --git a/.sniffler/config.json b/.sniffler/config.json
index f7726236c8e..0fc3c6ca471 100644
--- a/.sniffler/config.json
+++ b/.sniffler/config.json
@@ -28,6 +28,7 @@
"app/lib/methods/getUsersPresence.ts",
"app/sagas/index.js",
"app/sagas/init.js",
+ "app/sagas/preloadNativeHeaderIcons.js",
"app/lib/methods/loggedInServer.ts",
"app/sagas/state.js",
"app/sagas/selectServer.ts",
diff --git a/.sniffler/test-map.json b/.sniffler/test-map.json
index f467214edcd..bd67980093a 100644
--- a/.sniffler/test-map.json
+++ b/.sniffler/test-map.json
@@ -406,7 +406,7 @@
"test": ".maestro/tests/teams/convert-team.yaml",
"dependsOn": [
"app/views/RoomActionsView/**",
- "app/views/SelectListView.tsx",
+ "app/views/SelectListView/**",
"app/views/CreateChannelView/**",
"app/views/NewMessageView/**",
"app/views/SelectedUsersView/**",
@@ -436,7 +436,7 @@
"app/views/AddExistingChannelView/**",
"app/views/RoomMembersView/**",
"app/views/SelectedUsersView/**",
- "app/views/SelectListView.tsx",
+ "app/views/SelectListView/**",
"app/views/CreateChannelView/**",
"app/sagas/room.js",
"app/sagas/createChannel.js"
diff --git a/app/containers/Avatar/Avatar.tsx b/app/containers/Avatar/Avatar.tsx
index 926a74d841e..15c1dddd9fc 100644
--- a/app/containers/Avatar/Avatar.tsx
+++ b/app/containers/Avatar/Avatar.tsx
@@ -10,6 +10,7 @@ import { SubscriptionType } from '~/definitions';
import { type IAvatar } from './interfaces';
import I18n from '~/i18n';
import Touch from '../Touch';
+import { isIOS26OrLater } from '~/lib/methods/helpers/deviceInfo';
const Avatar = memo(
({
@@ -28,7 +29,7 @@ const Avatar = memo(
serverVersion,
text,
size = 25,
- borderRadius = 4,
+ borderRadius = isIOS26OrLater ? 8 : 4,
type = SubscriptionType.DIRECT,
avatarExternalProviderUrl,
roomAvatarExternalProviderUrl,
diff --git a/app/containers/BackgroundContainer/__snapshots__/index.test.tsx.snap b/app/containers/BackgroundContainer/__snapshots__/index.test.tsx.snap
index 0a5d30836a0..3cd43ba0c33 100644
--- a/app/containers/BackgroundContainer/__snapshots__/index.test.tsx.snap
+++ b/app/containers/BackgroundContainer/__snapshots__/index.test.tsx.snap
@@ -42,6 +42,16 @@ exports[`Story Snapshots: Basic should match snapshot 1`] = `
}
/>
+
+
+
`;
@@ -87,26 +97,37 @@ exports[`Story Snapshots: BlackThemeLoading should match snapshot 1`] = `
}
/>
-
+ contentInsetAdjustmentBehavior="automatic"
+ >
+
+
+
+
`;
@@ -152,32 +173,43 @@ exports[`Story Snapshots: BlackThemeText should match snapshot 1`] = `
}
/>
-
- Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries
-
+
+
+ Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries
+
+
+
`;
@@ -223,26 +255,37 @@ exports[`Story Snapshots: DarkThemeLoading should match snapshot 1`] = `
}
/>
-
+ contentInsetAdjustmentBehavior="automatic"
+ >
+
+
+
+
`;
@@ -288,32 +331,43 @@ exports[`Story Snapshots: DarkThemeText should match snapshot 1`] = `
}
/>
-
- Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries
-
+
+
+ Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries
+
+
+
`;
@@ -359,26 +413,37 @@ exports[`Story Snapshots: Loading should match snapshot 1`] = `
}
/>
-
+ contentInsetAdjustmentBehavior="automatic"
+ >
+
+
+
+
`;
@@ -424,32 +489,43 @@ exports[`Story Snapshots: LongText should match snapshot 1`] = `
}
/>
-
- Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries
-
+
+
+ Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries
+
+
+
`;
@@ -495,31 +571,42 @@ exports[`Story Snapshots: Text should match snapshot 1`] = `
}
/>
-
- Text here
-
+
+
+ Text here
+
+
+
`;
diff --git a/app/containers/BackgroundContainer/index.tsx b/app/containers/BackgroundContainer/index.tsx
index 57a64dad1d5..180ff2fec18 100644
--- a/app/containers/BackgroundContainer/index.tsx
+++ b/app/containers/BackgroundContainer/index.tsx
@@ -1,5 +1,5 @@
import { type ReactElement } from 'react';
-import { ActivityIndicator, ImageBackground, StyleSheet, Text, View } from 'react-native';
+import { ActivityIndicator, ImageBackground, ScrollView, StyleSheet, Text, View } from 'react-native';
import { useTheme } from '~/theme';
import sharedStyles from '~/views/Styles';
@@ -36,9 +36,11 @@ const BackgroundContainer = ({ text, loading }: IBackgroundContainer): ReactElem
return (
- {text && !loading ? {text} : null}
- {/* @ts-ignore */}
- {loading ? : null}
+
+ {text && !loading ? {text} : null}
+ {/* @ts-ignore */}
+ {loading ? : null}
+
);
};
diff --git a/app/containers/DirectoryItem/__snapshots__/DirectoryItem.test.tsx.snap b/app/containers/DirectoryItem/__snapshots__/DirectoryItem.test.tsx.snap
index 1bc1299cc61..e3b93fff7d4 100644
--- a/app/containers/DirectoryItem/__snapshots__/DirectoryItem.test.tsx.snap
+++ b/app/containers/DirectoryItem/__snapshots__/DirectoryItem.test.tsx.snap
@@ -10,288 +10,216 @@ exports[`Story Snapshots: CustomStyle should match snapshot 1`] = `
>
-
+
+
+
-
-
-
-
-
-
-
-
-
-
- Styled Room
-
-
-
- Custom style applied
-
-
-
+ ],
+ ],
+ {
+ "fontFamily": "custom",
+ "fontStyle": "normal",
+ "fontWeight": "normal",
+ },
+ {},
+ ]
+ }
+ >
+
+
+
+ Styled Room
+
+
+ Custom style applied
+
-
+
@@ -307,286 +235,216 @@ exports[`Story Snapshots: Default should match snapshot 1`] = `
>
-
+
+
+
-
-
-
-
-
-
-
-
-
-
- General
-
-
-
- A public room
-
-
-
+ ],
+ ],
+ {
+ "fontFamily": "custom",
+ "fontStyle": "normal",
+ "fontWeight": "normal",
+ },
+ {},
+ ]
+ }
+ >
+
+
+
+ General
+
+
+ A public room
+
-
+
@@ -602,255 +460,183 @@ exports[`Story Snapshots: DirectMessage should match snapshot 1`] = `
>
-
+
+
+
-
-
-
-
-
-
-
- Alice Johnson
-
-
-
- Hey there!
-
-
-
+ Alice Johnson
+
+
+ Hey there!
+
-
+
@@ -866,308 +652,241 @@ exports[`Story Snapshots: LongRoomName should match snapshot 1`] = `
>
-
+
+
+
-
-
-
-
-
-
-
-
-
-
- This is a very very very very very very very long room name that should be truncated
-
-
-
- Long name test
-
-
-
- 9999 members
-
-
+ ],
+ ],
+ {
+ "fontFamily": "custom",
+ "fontStyle": "normal",
+ "fontWeight": "normal",
+ },
+ {},
+ ]
+ }
+ >
+
+
+
+ This is a very very very very very very very long room name that should be truncated
+
+
+ Long name test
+
-
+
+ 9999 members
+
+
@@ -1183,188 +902,144 @@ exports[`Story Snapshots: OnlyTitle should match snapshot 1`] = `
>
-
-
-
+
-
-
-
-
-
- Just a title
-
-
-
-
+ "flexShrink": 1,
+ "fontSize": 17,
+ "fontWeight": "500",
+ },
+ {
+ "color": "#2F343D",
+ },
+ ]
+ }
+ >
+ Just a title
+
-
+
@@ -1380,286 +1055,216 @@ exports[`Story Snapshots: TeamMain should match snapshot 1`] = `
>
-
+
+
+
-
-
-
-
-
-
-
-
-
-
- Engineering Team
-
-
-
- Main team room
-
-
-
+ ],
+ ],
+ {
+ "fontFamily": "custom",
+ "fontStyle": "normal",
+ "fontWeight": "normal",
+ },
+ {},
+ ]
+ }
+ >
+
+
+
+ Engineering Team
+
+
+ Main team room
+
-
+
@@ -1675,308 +1280,241 @@ exports[`Story Snapshots: WithRightLabel should match snapshot 1`] = `
>
-
+
+
+
-
-
-
-
-
-
-
-
-
-
- General
-
-
-
- Room with label
-
-
-
- 123 members
-
-
+ ],
+ ],
+ {
+ "fontFamily": "custom",
+ "fontStyle": "normal",
+ "fontWeight": "normal",
+ },
+ {},
+ ]
+ }
+ >
+
+
+
+ General
+
+
+ Room with label
+
-
+
+ 123 members
+
+
@@ -1992,247 +1530,201 @@ exports[`Story Snapshots: WithoutDescription should match snapshot 1`] = `
>
-
+
+
+
-
-
-
-
-
-
-
-
-
-
- No description room
-
-
-
-
+ "fontFamily": "custom",
+ "fontStyle": "normal",
+ "fontWeight": "normal",
+ },
+ {},
+ ]
+ }
+ >
+
+
+
+ No description room
+
-
+
diff --git a/app/containers/DirectoryItem/index.ios.tsx b/app/containers/DirectoryItem/index.ios.tsx
new file mode 100644
index 00000000000..68dedcb848b
--- /dev/null
+++ b/app/containers/DirectoryItem/index.ios.tsx
@@ -0,0 +1,52 @@
+import { type ReactElement } from 'react';
+import { Text } from 'react-native';
+
+import Avatar from '../Avatar';
+import RoomTypeIcon from '../RoomTypeIcon';
+import NativeListRow from '../NativeListRow';
+import { AVATAR_SIZE } from '../NativeListRow/constants';
+import styles from './styles';
+import { useTheme } from '~/theme';
+import usePreviewFormatText from '~/lib/hooks/usePreviewFormatText';
+import { type IDirectoryItem } from './index';
+
+export { ROW_HEIGHT } from '../NativeListRow/constants';
+
+const DirectoryItem = ({
+ title,
+ description,
+ avatar,
+ onPress,
+ testID,
+ rightLabel,
+ type,
+ rid,
+ teamMain,
+ isFirst,
+ isLast
+}: IDirectoryItem): ReactElement => {
+ const { colors } = useTheme();
+ const formattedDescription = usePreviewFormatText(description ?? '');
+ return (
+ }
+ titleLeading={type !== 'd' ? : undefined}
+ trailing={
+ rightLabel ? (
+
+ {rightLabel}
+
+ ) : undefined
+ }
+ />
+ );
+};
+
+export default DirectoryItem;
diff --git a/app/containers/DirectoryItem/index.tsx b/app/containers/DirectoryItem/index.tsx
index 77881bd3924..4572badd5a5 100644
--- a/app/containers/DirectoryItem/index.tsx
+++ b/app/containers/DirectoryItem/index.tsx
@@ -15,7 +15,7 @@ interface IDirectoryItemLabel {
color: string;
}
-interface IDirectoryItem {
+export interface IDirectoryItem {
title: string;
description?: string;
avatar?: string;
@@ -26,6 +26,8 @@ interface IDirectoryItem {
rightLabel?: string;
rid?: string;
teamMain?: boolean;
+ isFirst?: boolean;
+ isLast?: boolean;
}
const DirectoryItemLabel = memo(({ text, color }: IDirectoryItemLabel) => {
diff --git a/app/containers/DirectoryItem/styles.ts b/app/containers/DirectoryItem/styles.ts
index 23298b6f5c8..8f7af1781c0 100644
--- a/app/containers/DirectoryItem/styles.ts
+++ b/app/containers/DirectoryItem/styles.ts
@@ -31,6 +31,12 @@ export default StyleSheet.create({
fontSize: 14,
...sharedStyles.textRegular
},
+ titleIcon: {
+ marginRight: 0
+ },
+ nativeRowLabel: {
+ marginTop: StyleSheet.hairlineWidth
+ },
directoryItemLabel: {
fontSize: 14,
paddingLeft: 10,
diff --git a/app/containers/Header/components/HeaderButton/HeaderButtonItemBadge.tsx b/app/containers/Header/components/HeaderButton/HeaderButtonItemBadge.tsx
index c11284c588f..ad5c0bf70a5 100644
--- a/app/containers/Header/components/HeaderButton/HeaderButtonItemBadge.tsx
+++ b/app/containers/Header/components/HeaderButton/HeaderButtonItemBadge.tsx
@@ -1,7 +1,9 @@
import { type ReactElement } from 'react';
-import { StyleSheet, View } from 'react-native';
+import { StyleSheet, Text, useWindowDimensions, View } from 'react-native';
import UnreadBadge from '~/containers/UnreadBadge';
+import { useTheme } from '~/theme';
+import sharedStyles from '~/views/Styles';
const styles = StyleSheet.create({
badgeContainer: {
@@ -12,6 +14,10 @@ const styles = StyleSheet.create({
borderRadius: 10,
alignItems: 'center',
justifyContent: 'center'
+ },
+ countText: {
+ fontSize: 10,
+ ...sharedStyles.textSemibold
}
});
@@ -20,3 +26,20 @@ export const BadgeUnread = ({ ...props }): ReactElement => (
);
+
+export const BadgeCount = ({ value, color }: { value: number; color: string }): ReactElement => {
+ const { colors } = useTheme();
+ const { fontScale } = useWindowDimensions();
+ const text = value >= 100 ? '+99' : String(value);
+ return (
+
+
+ {text}
+
+
+ );
+};
diff --git a/app/containers/List/ListSection.tsx b/app/containers/List/ListSection.tsx
deleted file mode 100644
index a326722bec3..00000000000
--- a/app/containers/List/ListSection.tsx
+++ /dev/null
@@ -1,29 +0,0 @@
-import { type ReactElement } from 'react';
-import { StyleSheet, View } from 'react-native';
-
-import Header from './ListHeader';
-
-const styles = StyleSheet.create({
- container: {
- marginBottom: 16
- }
-});
-
-interface IListSection {
- children: (ReactElement | null)[] | ReactElement | null;
- title?: string;
- translateTitle?: boolean;
-}
-
-const ListSection = ({ children, title, translateTitle }: IListSection) => {
- return (
-
- {title ? : null}
- {children}
-
- );
-};
-
-ListSection.displayName = 'List.Section';
-
-export default ListSection;
diff --git a/app/containers/List/__snapshots__/List.test.tsx.snap b/app/containers/List/__snapshots__/List.test.tsx.snap
deleted file mode 100644
index e13bf9441eb..00000000000
--- a/app/containers/List/__snapshots__/List.test.tsx.snap
+++ /dev/null
@@ -1,10901 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`Story Snapshots: Alert should match snapshot 1`] = `
-
-
-
-
-
-
-
-
- Chats
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Chats
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-`;
-
-exports[`Story Snapshots: Header should match snapshot 1`] = `
-
-
-
-
- Chats
-
-
-
-
- Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries
-
-
-
-
-`;
-
-exports[`Story Snapshots: Icon should match snapshot 1`] = `
-
-
-
-
-
-
-
-
-
-`;
-
-exports[`Story Snapshots: ListItemWithRightContainerStyle should match snapshot 1`] = `
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Chats
-
-
-
- All
-
-
-
-
-
-
-
-
-
-
-
-
-
-`;
-
-exports[`Story Snapshots: Pressable should match snapshot 1`] = `
-
-
-
-
-
-
-
-
-
-
- Press me
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- I'm disabled
-
-
-
-
-
-
-
-
-
-
-`;
-
-exports[`Story Snapshots: Radio should match snapshot 1`] = `
-
-
-
-
-
-
-
-
-
-
- Option 1
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Option 2
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Option 3
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries
-
-
-
- Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-`;
-
-exports[`Story Snapshots: SectionAndInfo should match snapshot 1`] = `
-
-
-
-
-
-
-
-
-
-
- Section Item
-
-
-
-
-
-
-
-
-
-
-
- Section Item
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Section Item
-
-
-
-
-
-
-
-
-
-
-
- Section Item
-
-
-
-
-
-
-
-
-
-
- Chats
-
-
-
-
-
-
-
-
- Section Item
-
-
-
-
-
-
-
-
-
-
-
- Section Item
-
-
-
-
-
-
-
-
- Chats
-
-
-
-
-
-
- Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries
-
-
-
-
-
-
-
-
- Section Item
-
-
-
-
-
-
-
-
-
-
-
- Section Item
-
-
-
-
-
-
-
-
- Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries
-
-
-
-
-
-
-`;
-
-exports[`Story Snapshots: Separator should match snapshot 1`] = `
-
-
-
-
-
-`;
-
-exports[`Story Snapshots: TitleAndSubtitle should match snapshot 1`] = `
-
-
-
-
-
-
-
-
- Chats
-
-
-
-
-
-
-
-
-
-
-
- Chats
-
-
-
- All
-
-
-
-
-
-
-
-
-
-
- Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries
-
-
-
- Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries
-
-
-
-
-
-
-
-
-
-
- Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries
-
-
-
- Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries
-
-
-
-
-
-
-
-`;
-
-exports[`Story Snapshots: WithBiggerFont should match snapshot 1`] = `
-
-
-
-
-
-
- Chats
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Chats
-
-
-
- All
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Chats
-
-
-
- All
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Chats
-
-
-
-
-
-
- Chats
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Chats
-
-
-
- All
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Chats
-
-
-
- All
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Chats
-
-
-
-
-
-
-`;
-
-exports[`Story Snapshots: WithBlackTheme should match snapshot 1`] = `
-
-
-
-
-
-
- Chats
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Chats
-
-
-
- All
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Chats
-
-
-
- All
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Chats
-
-
-
-
-
-
- Chats
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Chats
-
-
-
- All
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Chats
-
-
-
- All
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Chats
-
-
-
-
-
-
-`;
-
-exports[`Story Snapshots: WithCustomColors should match snapshot 1`] = `
-
-
-
-
-
-
-
-
- Chats
-
-
-
-
-
-
-
-
-
-
-
-
-
- Press me!
-
-
-
-
-
-
-
-
-
-
-`;
-
-exports[`Story Snapshots: WithDarkTheme should match snapshot 1`] = `
-
-
-
-
-
-
- Chats
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Chats
-
-
-
- All
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Chats
-
-
-
- All
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Chats
-
-
-
-
-
-
- Chats
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Chats
-
-
-
- All
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Chats
-
-
-
- All
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Chats
-
-
-
-
-
-
-`;
-
-exports[`Story Snapshots: WithFlatList should match snapshot 1`] = `
-
-
-
-
-
-
-
-
-
-
-
-
- 0
-
-
-
-
-
-
-
-
-
-
-
-
-
- 1
-
-
-
-
-
-
-
-
-
-
-
-
-
- 2
-
-
-
-
-
-
-
-
-
-
-
-
-
- 3
-
-
-
-
-
-
-
-
-
-
-
-
-
- 4
-
-
-
-
-
-
-
-
-
-
-
-
-
- 5
-
-
-
-
-
-
-
-
-
-
-
-
-
- 6
-
-
-
-
-
-
-
-
-
-
-
-
-
- 7
-
-
-
-
-
-
-
-
-
-
-
-
-
- 8
-
-
-
-
-
-
-
-
-
-
-
-
-
- 9
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-`;
-
-exports[`Story Snapshots: WithIcon should match snapshot 1`] = `
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Icon Left
-
-
-
-
-
-
-
-
-
-
-
- Icon Right
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries
-
-
-
- Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Show Action Indicator
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-`;
-
-exports[`Story Snapshots: WithSmallFont should match snapshot 1`] = `
-
-
-
-
-
-
- Chats
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Chats
-
-
-
- All
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Chats
-
-
-
- All
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Chats
-
-
-
-
-
-
- Chats
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Chats
-
-
-
- All
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Chats
-
-
-
- All
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Chats
-
-
-
-
-
-
-`;
diff --git a/app/containers/List/components/ListCheckbox.tsx b/app/containers/List/components/ListCheckbox.tsx
new file mode 100644
index 00000000000..fed58469189
--- /dev/null
+++ b/app/containers/List/components/ListCheckbox.tsx
@@ -0,0 +1,19 @@
+import { type ReactElement } from 'react';
+
+import { useTheme } from '~/theme';
+import ListIcon from './ListIcon';
+
+export interface IListCheckbox {
+ value: boolean;
+ onValueChange: (value: boolean) => void;
+ testID?: string;
+}
+
+const ListCheckbox = ({ value }: IListCheckbox): ReactElement => {
+ const { colors } = useTheme();
+ return ;
+};
+
+ListCheckbox.displayName = 'List.Checkbox';
+
+export default ListCheckbox;
diff --git a/app/containers/List/components/ListContainer.ios.tsx b/app/containers/List/components/ListContainer.ios.tsx
new file mode 100644
index 00000000000..2531903567f
--- /dev/null
+++ b/app/containers/List/components/ListContainer.ios.tsx
@@ -0,0 +1,109 @@
+import { useState, type ReactElement } from 'react';
+import { StyleSheet, View } from 'react-native';
+import { Host } from '@expo/ui';
+import { Group, List, RNHostView } from '@expo/ui/swift-ui';
+import {
+ alignmentGuide,
+ frame,
+ listRowInsets,
+ listStyle,
+ onGeometryChange,
+ scrollContentBackground,
+ tag
+} from '@expo/ui/swift-ui/modifiers';
+
+import { useTheme } from '~/theme';
+import ListSection from './ListSection';
+import ListItem from './ListItem';
+import ListRadio from './ListRadio';
+import { isNativeListRow, isNativeListSection } from '../native/utils/rowMarkers';
+import { flattenListChildren, isListSeparator } from '../utils/listChildren';
+import { NativeListContext } from '../native/context';
+import { ICON_SIZE, PADDING_HORIZONTAL } from '../constants';
+
+const styles = StyleSheet.create({
+ host: {
+ flex: 1
+ }
+});
+
+const insetGroupedModifiers = [listStyle('insetGrouped')];
+const sidebarModifiers = [listStyle('sidebar')];
+const hiddenBackgroundModifiers = [scrollContentBackground('hidden')];
+
+export interface IListSelection {
+ selectedTag: string | null;
+}
+
+interface IListContainer {
+ children: (ReactElement | null)[] | ReactElement | null;
+ testID?: string;
+ selection?: IListSelection;
+ backgroundHidden?: boolean;
+}
+
+const isSection = (element: ReactElement) => element.type === ListSection || isNativeListSection(element.type);
+const isNativeRow = (element: ReactElement) =>
+ element.type === ListItem || element.type === ListRadio || isNativeListRow(element.type);
+const hasLeftIcon = (element: ReactElement) => Boolean((element.props as { left?: unknown }).left);
+const rowSelectionTag = (element: ReactElement) => (element.props as { testID?: string }).testID;
+
+const selectedTags = ({ selectedTag }: IListSelection) => (selectedTag ? [selectedTag] : []);
+
+const ListContainer = ({ children, testID, selection, backgroundHidden }: IListContainer) => {
+ const { theme } = useTheme();
+ const [rowWidth, setRowWidth] = useState(0);
+
+ const selectionTag = (row: ReactElement) => {
+ const rowTag = rowSelectionTag(row);
+ return rowTag && selection ? [tag(rowTag)] : [];
+ };
+
+ const rowModifiers = (row: ReactElement) => [
+ frame({ maxWidth: Number.MAX_SAFE_INTEGER }),
+ alignmentGuide('listRowSeparatorLeading', hasLeftIcon(row) ? PADDING_HORIZONTAL * 2 + ICON_SIZE : PADDING_HORIZONTAL),
+ onGeometryChange(({ width }) => setRowWidth(current => (current === width ? current : width))),
+ listRowInsets({ top: 0, leading: 0, bottom: 0, trailing: 0 }),
+ ...selectionTag(row)
+ ];
+
+ const renderHostedRow = (row: ReactElement) => (
+
+
+
+ {row}
+
+
+
+ );
+
+ const renderNativeRow = (row: ReactElement) => (
+
+ {row}
+
+ );
+
+ const renderRow = (row: ReactElement) => (isNativeRow(row) ? renderNativeRow(row) : renderHostedRow(row));
+
+ return (
+
+
+
+ {flattenListChildren(children)
+ .filter(element => !isListSeparator(element))
+ .map(element => (isSection(element) ? element : renderRow(element)))}
+
+
+
+ );
+};
+
+ListContainer.displayName = 'List.Container';
+
+export default ListContainer;
diff --git a/app/containers/List/ListContainer.tsx b/app/containers/List/components/ListContainer.tsx
similarity index 86%
rename from app/containers/List/ListContainer.tsx
rename to app/containers/List/components/ListContainer.tsx
index df3c14bdc1c..60fcf2995e2 100644
--- a/app/containers/List/ListContainer.tsx
+++ b/app/containers/List/components/ListContainer.tsx
@@ -13,8 +13,9 @@ const styles = StyleSheet.create({
interface IListContainer extends ScrollViewProps {
children: (ReactElement | null)[] | ReactElement | null;
testID?: string;
+ backgroundHidden?: boolean;
}
-const ListContainer = ({ children, ...props }: IListContainer) => {
+const ListContainer = ({ children, backgroundHidden: _backgroundHidden, ...props }: IListContainer) => {
const { bottom } = useSafeAreaInsets();
return (
diff --git a/app/containers/List/ListHeader.tsx b/app/containers/List/components/ListHeader.tsx
similarity index 94%
rename from app/containers/List/ListHeader.tsx
rename to app/containers/List/components/ListHeader.tsx
index f8ee321aed0..2583d206cbc 100644
--- a/app/containers/List/ListHeader.tsx
+++ b/app/containers/List/components/ListHeader.tsx
@@ -5,7 +5,7 @@ import sharedStyles from '~/views/Styles';
import { themes } from '~/lib/constants/colors';
import I18n from '~/i18n';
import { useTheme } from '~/theme';
-import { PADDING_HORIZONTAL } from './constants';
+import { PADDING_HORIZONTAL } from '../constants';
const styles = StyleSheet.create({
container: {
diff --git a/app/containers/List/ListIcon.tsx b/app/containers/List/components/ListIcon.tsx
similarity index 86%
rename from app/containers/List/ListIcon.tsx
rename to app/containers/List/components/ListIcon.tsx
index 2fa41cd25b8..46a76120beb 100644
--- a/app/containers/List/ListIcon.tsx
+++ b/app/containers/List/components/ListIcon.tsx
@@ -1,8 +1,8 @@
import { type ReactElement } from 'react';
import { type StyleProp, StyleSheet, View, type ViewStyle } from 'react-native';
-import { CustomIcon, type TIconsName } from '../CustomIcon';
-import { ICON_SIZE } from './constants';
+import { CustomIcon, type TIconsName } from '~/containers/CustomIcon';
+import { ICON_SIZE } from '../constants';
import { useTheme } from '~/theme';
export interface IListIcon {
diff --git a/app/containers/List/ListInfo.tsx b/app/containers/List/components/ListInfo.tsx
similarity index 94%
rename from app/containers/List/ListInfo.tsx
rename to app/containers/List/components/ListInfo.tsx
index c91ee9e4814..181d98cac2b 100644
--- a/app/containers/List/ListInfo.tsx
+++ b/app/containers/List/components/ListInfo.tsx
@@ -4,7 +4,7 @@ import { StyleSheet, Text, View } from 'react-native';
import sharedStyles from '~/views/Styles';
import { themes } from '~/lib/constants/colors';
import { useTheme } from '~/theme';
-import { PADDING_HORIZONTAL } from './constants';
+import { PADDING_HORIZONTAL } from '../constants';
import I18n from '~/i18n';
const styles = StyleSheet.create({
diff --git a/app/containers/List/ListItem.tsx b/app/containers/List/components/ListItem.tsx
similarity index 91%
rename from app/containers/List/ListItem.tsx
rename to app/containers/List/components/ListItem.tsx
index ed783e558b0..eabe200baa5 100644
--- a/app/containers/List/ListItem.tsx
+++ b/app/containers/List/components/ListItem.tsx
@@ -11,16 +11,18 @@ import {
type ViewStyle
} from 'react-native';
-import Touch from '../Touch';
+import Touch from '~/containers/Touch';
import sharedStyles from '~/views/Styles';
import { useTheme } from '~/theme';
import I18n from '~/i18n';
import Icon from './ListIcon';
-import { BASE_HEIGHT, ICON_SIZE, PADDING_HORIZONTAL } from './constants';
-import { CustomIcon } from '../CustomIcon';
+import { BASE_HEIGHT, ICON_SIZE, PADDING_HORIZONTAL } from '../constants';
+import { useNativeListMode } from '../native/context';
+import NativeListItem from '../native/components/Item';
+import { CustomIcon } from '~/containers/CustomIcon';
import { useResponsiveLayout } from '~/lib/hooks/useResponsiveLayout/useResponsiveLayout';
import EventEmitter from '~/lib/methods/helpers/events';
-import { LISTENER } from '../Toast';
+import { LISTENER } from '~/containers/Toast';
import { isIOS } from '~/lib/methods/helpers';
// Maestro fail to click on child component when we enable accessibility in parent component on iOS
@@ -256,13 +258,19 @@ export interface IListItem extends Omit, Omit {
const { colors } = useTheme();
+ const nativeListMode = useNativeListMode();
+ const backgroundColor = props.backgroundColor || (nativeListMode ? 'transparent' : colors.surfaceRoom);
+
+ if (nativeListMode === 'native') {
+ return ;
+ }
if (props.onPress) {
const { onPress } = props;
- return ;
+ return ;
}
return (
-
+
);
diff --git a/app/containers/List/ListRadio.tsx b/app/containers/List/components/ListRadio.tsx
similarity index 74%
rename from app/containers/List/ListRadio.tsx
rename to app/containers/List/components/ListRadio.tsx
index fe014a45600..101fea96d35 100644
--- a/app/containers/List/ListRadio.tsx
+++ b/app/containers/List/components/ListRadio.tsx
@@ -4,6 +4,8 @@ import i18n from '~/i18n';
import ListItem, { type IListItem } from './ListItem';
import ListIcon from './ListIcon';
import { useTheme } from '~/theme';
+import Radio from '~/containers/Radio';
+import { useNativeListMode } from '../native/context';
interface IListRadio extends IListItem {
value: any;
@@ -13,6 +15,7 @@ interface IListRadio extends IListItem {
const ListRadio = ({ value: _, isSelected, ...rest }: IListRadio) => {
const { colors } = useTheme();
+ const isNativeRow = useNativeListMode() === 'native';
const iconName = isSelected ? 'radio-checked' : 'radio-unchecked';
const iconColor = isSelected ? colors.badgeBackgroundLevel2 : colors.strokeMedium;
@@ -20,7 +23,7 @@ const ListRadio = ({ value: _, isSelected, ...rest }: IListRadio) => {
return (
}
+ right={() => (isNativeRow ? : )}
additionalAccessibilityLabel={isSelected ? i18n.t('Selected') : i18n.t('Unselected')}
accessibilityRole='radio'
/>
diff --git a/app/containers/List/components/ListSection.tsx b/app/containers/List/components/ListSection.tsx
new file mode 100644
index 00000000000..349229c78d1
--- /dev/null
+++ b/app/containers/List/components/ListSection.tsx
@@ -0,0 +1,41 @@
+import { type ReactNode } from 'react';
+import { StyleSheet, View } from 'react-native';
+
+import Header from './ListHeader';
+import NativeListSection from '../native/components/Section';
+import { useNativeListMode } from '../native/context';
+
+const styles = StyleSheet.create({
+ container: {
+ marginBottom: 16
+ }
+});
+
+interface IListSection {
+ children: ReactNode;
+ title?: string;
+ translateTitle?: boolean;
+}
+
+const ListSection = ({ children, title, translateTitle }: IListSection) => {
+ const nativeListMode = useNativeListMode();
+
+ if (nativeListMode === 'native') {
+ return (
+
+ {children}
+
+ );
+ }
+
+ return (
+
+ {title ? : null}
+ {children}
+
+ );
+};
+
+ListSection.displayName = 'List.Section';
+
+export default ListSection;
diff --git a/app/containers/List/ListSeparator.tsx b/app/containers/List/components/ListSeparator.tsx
similarity index 80%
rename from app/containers/List/ListSeparator.tsx
rename to app/containers/List/components/ListSeparator.tsx
index 442e99fdfd9..d5bab0fcbf9 100644
--- a/app/containers/List/ListSeparator.tsx
+++ b/app/containers/List/components/ListSeparator.tsx
@@ -3,6 +3,7 @@ import { StyleSheet, View, type ViewStyle } from 'react-native';
import { themes } from '~/lib/constants/colors';
import { useTheme } from '~/theme';
+import { useNativeListMode } from '../native/context';
const styles = StyleSheet.create({
separator: {
@@ -16,6 +17,11 @@ interface IListSeparator {
const ListSeparator = memo(({ style }: IListSeparator) => {
const { theme } = useTheme();
+ const isInNativeList = useNativeListMode();
+
+ if (isInNativeList) {
+ return null;
+ }
return ;
});
diff --git a/app/containers/List/components/__tests__/ListSection.test.tsx b/app/containers/List/components/__tests__/ListSection.test.tsx
new file mode 100644
index 00000000000..0f0a3ce14a3
--- /dev/null
+++ b/app/containers/List/components/__tests__/ListSection.test.tsx
@@ -0,0 +1,43 @@
+import { Text } from 'react-native';
+import { render, screen } from '@testing-library/react-native';
+
+import ListSection from '../ListSection';
+import { NativeListContext } from '~/containers/List/native/context';
+import { asNativeListSection, isNativeListRow, isNativeListSection } from '~/containers/List/native/utils/rowMarkers';
+
+jest.mock('~/containers/List/native/components/Section', () => {
+ const { Text: MockText } = jest.requireActual('react-native');
+ return ({ title }: { title?: string }) => {`native section ${title}`};
+});
+
+describe('ListSection', () => {
+ it('renders as a native section inside a native list', async () => {
+ await render(
+ row }}>
+
+ row
+
+
+ );
+ expect(screen.getByText('native section Calls')).toBeTruthy();
+ expect(screen.queryByText('row')).toBeNull();
+ });
+
+ it('renders its children outside a native list', async () => {
+ await render(
+
+ row
+
+ );
+ expect(screen.getByText('row')).toBeTruthy();
+ });
+});
+
+describe('asNativeListSection', () => {
+ it('marks a component as a whole section rather than a row', () => {
+ const CallRows = asNativeListSection(() => null);
+ expect(isNativeListSection(CallRows)).toBe(true);
+ expect(isNativeListRow(CallRows)).toBe(false);
+ expect(isNativeListSection(() => null)).toBe(false);
+ });
+});
diff --git a/app/containers/List/index.ts b/app/containers/List/index.ts
index 76002b160db..6dffdcc56d9 100644
--- a/app/containers/List/index.ts
+++ b/app/containers/List/index.ts
@@ -1,9 +1,10 @@
-export { default as Container } from './ListContainer';
-export { default as Item } from './ListItem';
-export { default as Radio } from './ListRadio';
-export { default as Section } from './ListSection';
-export { default as Icon } from './ListIcon';
-export { default as Separator } from './ListSeparator';
-export { default as Header } from './ListHeader';
-export { default as Info } from './ListInfo';
+export { default as Container } from './components/ListContainer';
+export { default as Item } from './components/ListItem';
+export { default as Radio } from './components/ListRadio';
+export { default as Section } from './components/ListSection';
+export { default as Icon } from './components/ListIcon';
+export { default as Checkbox } from './components/ListCheckbox';
+export { default as Separator } from './components/ListSeparator';
+export { default as Header } from './components/ListHeader';
+export { default as Info } from './components/ListInfo';
export * from './styles';
diff --git a/app/containers/List/native/components/Accessory.ios.tsx b/app/containers/List/native/components/Accessory.ios.tsx
new file mode 100644
index 00000000000..147d86e4ec8
--- /dev/null
+++ b/app/containers/List/native/components/Accessory.ios.tsx
@@ -0,0 +1,58 @@
+import { Checkbox } from '@expo/ui';
+import { Image, RNHostView, Text, Toggle } from '@expo/ui/swift-ui';
+import { disabled, font, foregroundStyle, labelsHidden, lineLimit, tint } from '@expo/ui/swift-ui/modifiers';
+
+import { useTheme } from '~/theme';
+import NativeListIcon from './Icon.ios';
+import NativeListIndicator from './Indicator.ios';
+import NativeListStatus from './Status.ios';
+import { type TNativeListAccessory } from '../utils/describeAccessory';
+
+const NativeListAccessory = ({ accessory }: { accessory: TNativeListAccessory }) => {
+ const { colors } = useTheme();
+
+ switch (accessory.kind) {
+ case 'icon':
+ return ;
+ case 'indicator':
+ return ;
+ case 'check':
+ return (
+
+ );
+ case 'status':
+ return ;
+ case 'toggle':
+ return (
+
+ );
+ case 'checkbox':
+ return (
+
+ );
+ case 'text':
+ return (
+
+ {accessory.text}
+
+ );
+ case 'hosted':
+ return {accessory.element};
+ }
+};
+
+export default NativeListAccessory;
diff --git a/app/containers/List/native/components/Icon.ios.tsx b/app/containers/List/native/components/Icon.ios.tsx
new file mode 100644
index 00000000000..5bbeb1e719c
--- /dev/null
+++ b/app/containers/List/native/components/Icon.ios.tsx
@@ -0,0 +1,22 @@
+import { Text } from '@expo/ui/swift-ui';
+import { font, foregroundStyle } from '@expo/ui/swift-ui/modifiers';
+
+import { type TIconsName } from '~/containers/CustomIcon';
+import { mappedIcons } from '~/containers/CustomIcon/mappedIcons';
+import { ICON_SIZE } from '~/containers/List/constants';
+
+interface INativeListIcon {
+ name: TIconsName;
+ color: string;
+ size?: number;
+}
+
+const ICON_FONT_FAMILY = 'custom';
+
+const NativeListIcon = ({ name, color, size = ICON_SIZE }: INativeListIcon) => (
+
+ {String.fromCodePoint(mappedIcons[name])}
+
+);
+
+export default NativeListIcon;
diff --git a/app/containers/List/native/components/Indicator.ios.tsx b/app/containers/List/native/components/Indicator.ios.tsx
new file mode 100644
index 00000000000..b68690a07c6
--- /dev/null
+++ b/app/containers/List/native/components/Indicator.ios.tsx
@@ -0,0 +1,26 @@
+import { type ComponentProps } from 'react';
+import { Image } from '@expo/ui/swift-ui';
+import { font } from '@expo/ui/swift-ui/modifiers';
+
+import { useTheme } from '~/theme';
+
+export type TNativeListIndicator = 'disclosure' | 'external';
+
+const SYSTEM_NAMES: Record['systemName']> = {
+ disclosure: 'chevron.forward',
+ external: 'arrow.up.forward'
+};
+
+const NativeListIndicator = ({ indicator }: { indicator: TNativeListIndicator }) => {
+ const { colors } = useTheme();
+
+ return (
+
+ );
+};
+
+export default NativeListIndicator;
diff --git a/app/containers/List/native/components/Item.ios.tsx b/app/containers/List/native/components/Item.ios.tsx
new file mode 100644
index 00000000000..c4618b6e3e7
--- /dev/null
+++ b/app/containers/List/native/components/Item.ios.tsx
@@ -0,0 +1,104 @@
+import { type ReactNode } from 'react';
+import { Button, HStack, RNHostView, Spacer, Text, VStack } from '@expo/ui/swift-ui';
+import {
+ accessibilityLabel,
+ buttonStyle,
+ contentShape,
+ font,
+ foregroundStyle,
+ frame,
+ lineLimit,
+ listRowInsets,
+ opacity,
+ shapes
+} from '@expo/ui/swift-ui/modifiers';
+
+import { useTheme } from '~/theme';
+import { useResponsiveLayout } from '~/lib/hooks/useResponsiveLayout/useResponsiveLayout';
+import NativeListAccessory from './Accessory.ios';
+import NativeListIcon from './Icon.ios';
+import NativeListIndicator from './Indicator.ios';
+import { type IListItem } from '~/containers/List/components/ListItem';
+import { type INativeListItem } from '../types';
+import { describeNativeListAccessory } from '../utils/describeAccessory';
+import { BASE_HEIGHT, PADDING_HORIZONTAL } from '~/containers/List/constants';
+import {
+ nativeListItemAccessibilityLabel,
+ nativeListItemSubtitle,
+ nativeListItemTitle,
+ pressNativeListItem
+} from '../utils/itemProps';
+
+const NativeListItemTitle = ({ item }: { item: IListItem }) => {
+ const { colors } = useTheme();
+ const title = nativeListItemTitle(item);
+
+ if (typeof item.title === 'function') {
+ const customTitle = item.title();
+ return customTitle ? {customTitle} : null;
+ }
+ return (
+
+
+ {title}
+
+ {item.alert ? : null}
+
+ );
+};
+
+const NativeListItemRow = ({ item, children }: { item: IListItem; children: ReactNode }) => {
+ const { fontScale } = useResponsiveLayout();
+ const rowModifiers = [
+ accessibilityLabel(nativeListItemAccessibilityLabel(item)),
+ frame({ minHeight: (item.heightContainer ?? BASE_HEIGHT) * fontScale }),
+ listRowInsets({ leading: PADDING_HORIZONTAL, trailing: PADDING_HORIZONTAL }),
+ ...(item.disabled ? [opacity(0.3)] : [])
+ ];
+
+ if (!item.onPress) {
+ return (
+
+ {children}
+
+ );
+ }
+ return (
+
+ );
+};
+
+const NativeListItem = ({ item }: INativeListItem) => {
+ const { colors } = useTheme();
+ const subtitle = nativeListItemSubtitle(item);
+ const leading = describeNativeListAccessory(item.left?.());
+ const trailing = describeNativeListAccessory(item.right?.());
+
+ return (
+
+ {leading ? : null}
+
+
+ {subtitle ? (
+
+ {subtitle}
+
+ ) : null}
+
+
+ {trailing ? : null}
+ {item.showActionIndicator ? : null}
+
+ );
+};
+
+export default NativeListItem;
diff --git a/app/containers/List/native/components/Item.tsx b/app/containers/List/native/components/Item.tsx
new file mode 100644
index 00000000000..fa70f339efb
--- /dev/null
+++ b/app/containers/List/native/components/Item.tsx
@@ -0,0 +1,5 @@
+import { type INativeListItem } from '../types';
+
+const NativeListItem = (_: INativeListItem) => null;
+
+export default NativeListItem;
diff --git a/app/containers/List/native/components/Picker.ios.tsx b/app/containers/List/native/components/Picker.ios.tsx
new file mode 100644
index 00000000000..b45fce048c8
--- /dev/null
+++ b/app/containers/List/native/components/Picker.ios.tsx
@@ -0,0 +1,36 @@
+import { Picker, Text } from '@expo/ui/swift-ui';
+import { font, foregroundStyle, frame, listRowInsets, pickerStyle, tag, tint } from '@expo/ui/swift-ui/modifiers';
+
+import { useTheme } from '~/theme';
+import { useResponsiveLayout } from '~/lib/hooks/useResponsiveLayout/useResponsiveLayout';
+import { BASE_HEIGHT, PADDING_HORIZONTAL } from '~/containers/List/constants';
+import { type INativeListPicker } from '../types';
+
+const NativeListPicker = ({ title, testID, options, selection, onSelectionChange }: INativeListPicker) => {
+ const { colors } = useTheme();
+ const { fontScale } = useResponsiveLayout();
+
+ return (
+ {title}
+ }
+ modifiers={[
+ pickerStyle('menu'),
+ tint(colors.fontSecondaryInfo),
+ frame({ minHeight: BASE_HEIGHT * fontScale }),
+ listRowInsets({ leading: PADDING_HORIZONTAL, trailing: PADDING_HORIZONTAL })
+ ]}>
+ {options.map(option => (
+
+ {option.label}
+
+ ))}
+
+ );
+};
+
+export default NativeListPicker;
diff --git a/app/containers/List/native/components/Picker.tsx b/app/containers/List/native/components/Picker.tsx
new file mode 100644
index 00000000000..a58d3a39071
--- /dev/null
+++ b/app/containers/List/native/components/Picker.tsx
@@ -0,0 +1,5 @@
+import { type INativeListPicker } from '../types';
+
+const NativeListPicker = (_: INativeListPicker) => null;
+
+export default NativeListPicker;
diff --git a/app/containers/List/native/components/Section.ios.tsx b/app/containers/List/native/components/Section.ios.tsx
new file mode 100644
index 00000000000..949351955de
--- /dev/null
+++ b/app/containers/List/native/components/Section.ios.tsx
@@ -0,0 +1,41 @@
+import { useContext, type ReactElement } from 'react';
+import { Section, Text } from '@expo/ui/swift-ui';
+
+import ListInfo from '~/containers/List/components/ListInfo';
+import { flattenListChildren, isListSeparator } from '~/containers/List/utils/listChildren';
+import { NativeListContext } from '../context';
+import { translateListText } from '../utils/itemProps';
+import { type INativeListSection } from '../types';
+
+interface IInfoProps {
+ info: string;
+ translateInfo?: boolean;
+}
+
+const isInfo = (element: ReactElement): element is ReactElement => element.type === ListInfo;
+
+const NativeListSection = ({ children, title, translateTitle }: INativeListSection) => {
+ const { renderRow } = useContext(NativeListContext);
+ const elements = flattenListChildren(children).filter(element => !isListSeparator(element));
+ const infos = elements.filter(isInfo);
+ const rows = elements.filter(element => !isInfo(element));
+ const footer = infos.length ? (
+ <>
+ {infos.map(info => (
+ {translateListText(info.props.info, info.props.translateInfo)}
+ ))}
+ >
+ ) : undefined;
+
+ if (!rows.length && !infos.length) {
+ return null;
+ }
+
+ return (
+
+ {rows.map(renderRow)}
+
+ );
+};
+
+export default NativeListSection;
diff --git a/app/containers/List/native/components/Section.tsx b/app/containers/List/native/components/Section.tsx
new file mode 100644
index 00000000000..33d2c909b34
--- /dev/null
+++ b/app/containers/List/native/components/Section.tsx
@@ -0,0 +1,5 @@
+import { type INativeListSection } from '../types';
+
+const NativeListSection = (_: INativeListSection) => null;
+
+export default NativeListSection;
diff --git a/app/containers/List/native/components/Status.ios.tsx b/app/containers/List/native/components/Status.ios.tsx
new file mode 100644
index 00000000000..6bd2ed7570c
--- /dev/null
+++ b/app/containers/List/native/components/Status.ios.tsx
@@ -0,0 +1,14 @@
+import { type TUserStatus } from '~/definitions';
+import { useUserStatusColor } from '~/lib/hooks/useUserStatusColor';
+import { useTheme } from '~/theme';
+import { getStatusIconName } from '~/containers/Status/getStatusIconName';
+import NativeListIcon from './Icon.ios';
+
+const NativeListStatus = ({ status }: { status: TUserStatus }) => {
+ const { colors } = useTheme();
+ const statusColor = useUserStatusColor(status);
+
+ return ;
+};
+
+export default NativeListStatus;
diff --git a/app/containers/List/native/context.ts b/app/containers/List/native/context.ts
new file mode 100644
index 00000000000..7cd85f92865
--- /dev/null
+++ b/app/containers/List/native/context.ts
@@ -0,0 +1,12 @@
+import { createContext, useContext, type ReactElement } from 'react';
+
+export type TNativeListMode = false | 'native' | 'hosted';
+
+interface INativeListContext {
+ mode: TNativeListMode;
+ renderRow: (row: ReactElement) => ReactElement;
+}
+
+export const NativeListContext = createContext({ mode: false, renderRow: row => row });
+
+export const useNativeListMode = () => useContext(NativeListContext).mode;
diff --git a/app/containers/List/native/types.ts b/app/containers/List/native/types.ts
new file mode 100644
index 00000000000..0cc6ee5af21
--- /dev/null
+++ b/app/containers/List/native/types.ts
@@ -0,0 +1,27 @@
+import { type ReactNode } from 'react';
+
+import { type IListItem } from '../components/ListItem';
+
+export interface INativeListItem {
+ item: IListItem;
+}
+
+export interface INativeListSection {
+ children: ReactNode;
+ title?: string;
+ translateTitle?: boolean;
+}
+
+export interface INativeListPickerOption {
+ label: string;
+ value: string;
+ testID?: string;
+}
+
+export interface INativeListPicker {
+ title: string;
+ testID?: string;
+ options: INativeListPickerOption[];
+ selection: string;
+ onSelectionChange: (value: string) => void;
+}
diff --git a/app/containers/List/native/utils/__tests__/describeAccessory.test.tsx b/app/containers/List/native/utils/__tests__/describeAccessory.test.tsx
new file mode 100644
index 00000000000..cecd5fe53a8
--- /dev/null
+++ b/app/containers/List/native/utils/__tests__/describeAccessory.test.tsx
@@ -0,0 +1,86 @@
+import { Text, View } from 'react-native';
+
+import Avatar from '~/containers/Avatar';
+import { CustomIcon } from '~/containers/CustomIcon';
+import NewWindowIcon from '~/containers/NewWindowIcon';
+import Radio from '~/containers/Radio';
+import Status from '~/containers/Status/Status';
+import Switch from '~/containers/Switch';
+import ListCheckbox from '~/containers/List/components/ListCheckbox';
+import ListIcon from '~/containers/List/components/ListIcon';
+import { describeNativeListAccessory } from '../describeAccessory';
+
+describe('describeNativeListAccessory', () => {
+ it('has nothing to render for an empty slot', () => {
+ expect(describeNativeListAccessory(null)).toBeNull();
+ });
+
+ it('maps List.Icon and CustomIcon to icon font glyphs', () => {
+ expect(describeNativeListAccessory()).toEqual({ kind: 'icon', name: 'moon' });
+ expect(describeNativeListAccessory()).toEqual({
+ kind: 'icon',
+ name: 'warning',
+ color: 'red',
+ size: 20
+ });
+ });
+
+ it('ignores an empty icon color', () => {
+ expect(describeNativeListAccessory()).toEqual({
+ kind: 'icon',
+ name: 'checkbox-unchecked'
+ });
+ });
+
+ it('maps the external link icon to the external indicator', () => {
+ expect(describeNativeListAccessory()).toEqual({ kind: 'indicator', indicator: 'external' });
+ });
+
+ it('maps the chevron icon to the disclosure indicator', () => {
+ expect(describeNativeListAccessory()).toEqual({
+ kind: 'indicator',
+ indicator: 'disclosure'
+ });
+ });
+
+ it('shows a checkmark only for a checked radio', () => {
+ expect(describeNativeListAccessory()).toEqual({ kind: 'check' });
+ expect(describeNativeListAccessory()).toBeNull();
+ });
+
+ it('maps the user status', () => {
+ expect(describeNativeListAccessory()).toEqual({ kind: 'status', status: 'away' });
+ });
+
+ it('maps a Switch to a toggle keeping value, handler and disabled state', () => {
+ const onValueChange = jest.fn();
+ const accessory = describeNativeListAccessory();
+ expect(accessory).toEqual({ kind: 'toggle', isOn: true, onValueChange, disabled: true, testID: 'switch' });
+ });
+
+ it('maps List.Checkbox to a checkbox keeping value, handler and testID', () => {
+ const onValueChange = jest.fn();
+ expect(describeNativeListAccessory()).toEqual({
+ kind: 'checkbox',
+ value: true,
+ onValueChange,
+ testID: 'checkbox'
+ });
+ });
+
+ it('maps plain text, also when wrapped in a single View', () => {
+ expect(describeNativeListAccessory(Off)).toEqual({ kind: 'text', text: 'Off' });
+ expect(
+ describeNativeListAccessory(
+
+ Toasts
+
+ )
+ ).toEqual({ kind: 'text', text: 'Toasts' });
+ });
+
+ it('hosts anything else as React Native', () => {
+ const avatar = ;
+ expect(describeNativeListAccessory(avatar)).toEqual({ kind: 'hosted', element: avatar });
+ });
+});
diff --git a/app/containers/List/native/utils/__tests__/itemProps.test.ts b/app/containers/List/native/utils/__tests__/itemProps.test.ts
new file mode 100644
index 00000000000..d77d6f08566
--- /dev/null
+++ b/app/containers/List/native/utils/__tests__/itemProps.test.ts
@@ -0,0 +1,68 @@
+import EventEmitter from '~/lib/methods/helpers/events';
+import { LISTENER } from '~/containers/Toast';
+import { type IListItem } from '~/containers/List/components/ListItem';
+import { nativeListItemAccessibilityLabel, nativeListItemTitle, pressNativeListItem } from '../itemProps';
+
+jest.mock('~/i18n', () => ({ t: (key: string) => `t:${key}` }));
+
+describe('nativeListItemTitle', () => {
+ it('translates string titles', () => {
+ expect(nativeListItemTitle({ title: 'Theme' })).toBe('t:Theme');
+ });
+
+ it('has no text for custom title components', () => {
+ expect(nativeListItemTitle({ title: () => null })).toBeUndefined();
+ });
+});
+
+describe('nativeListItemAccessibilityLabel', () => {
+ it('prefers the explicit label', () => {
+ expect(nativeListItemAccessibilityLabel({ title: 'Theme', accessibilityLabel: 'Custom' })).toBe('Custom');
+ });
+
+ it('joins translated title, subtitle and switch state', () => {
+ expect(
+ nativeListItemAccessibilityLabel({
+ title: 'Crash_report',
+ subtitle: 'Info',
+ translateSubtitle: false,
+ additionalAccessibilityLabel: true
+ })
+ ).toBe('t:Crash_report Info t:Enabled');
+ });
+
+ it('uses checked wording for checkboxes', () => {
+ expect(
+ nativeListItemAccessibilityLabel({
+ title: 'Name',
+ translateTitle: false,
+ additionalAccessibilityLabel: false,
+ additionalAccessibilityLabelCheck: true
+ })
+ ).toBe('Name t:Unchecked');
+ });
+});
+
+describe('pressNativeListItem', () => {
+ const onPress = jest.fn();
+ const item: IListItem = { title: 'Theme', onPress };
+
+ beforeEach(() => onPress.mockClear());
+
+ it('calls onPress with the title', () => {
+ pressNativeListItem(item);
+ expect(onPress).toHaveBeenCalledWith('Theme');
+ });
+
+ it('ignores presses on disabled rows', () => {
+ pressNativeListItem({ title: 'Theme', onPress, disabled: true });
+ expect(onPress).not.toHaveBeenCalled();
+ });
+
+ it('shows the disabled reason instead of pressing', () => {
+ const emit = jest.spyOn(EventEmitter, 'emit');
+ pressNativeListItem({ title: 'Theme', onPress, disabled: true, disabledReason: 'Not allowed' });
+ expect(emit).toHaveBeenCalledWith(LISTENER, { message: 'Not allowed' });
+ expect(onPress).not.toHaveBeenCalled();
+ });
+});
diff --git a/app/containers/List/native/utils/describeAccessory.ts b/app/containers/List/native/utils/describeAccessory.ts
new file mode 100644
index 00000000000..a1feb7393c6
--- /dev/null
+++ b/app/containers/List/native/utils/describeAccessory.ts
@@ -0,0 +1,91 @@
+import { Children, isValidElement, type ReactElement, type ReactNode } from 'react';
+import { Text, View, type SwitchProps } from 'react-native';
+
+import { type TUserStatus } from '~/definitions';
+import { CustomIcon, type TIconsName } from '~/containers/CustomIcon';
+import NewWindowIcon from '~/containers/NewWindowIcon';
+import Radio from '~/containers/Radio';
+import Status from '~/containers/Status/Status';
+import Switch from '~/containers/Switch';
+import ListCheckbox, { type IListCheckbox } from '~/containers/List/components/ListCheckbox';
+import ListIcon from '~/containers/List/components/ListIcon';
+
+export type TNativeListAccessory =
+ | { kind: 'icon'; name: TIconsName; color?: string; size?: number }
+ | { kind: 'check' }
+ | { kind: 'indicator'; indicator: 'disclosure' | 'external' }
+ | { kind: 'status'; status: TUserStatus }
+ | { kind: 'toggle'; isOn: boolean; onValueChange?: (value: boolean) => void; disabled: boolean; testID?: string }
+ | { kind: 'checkbox'; value: boolean; onValueChange: (value: boolean) => void; testID?: string }
+ | { kind: 'text'; text: string }
+ | { kind: 'hosted'; element: ReactElement };
+
+interface IIconProps {
+ name: TIconsName;
+ color?: string;
+ size?: number;
+}
+
+const iconAccessory = (name: TIconsName, { color, size }: Partial): TNativeListAccessory => {
+ if (name === 'chevron-right') {
+ return { kind: 'indicator', indicator: 'disclosure' };
+ }
+ if (name === 'new-window') {
+ return { kind: 'indicator', indicator: 'external' };
+ }
+ return { kind: 'icon', name, color: color || undefined, size };
+};
+
+const textContent = (children: ReactNode) => {
+ const parts = Children.toArray(children);
+ return parts.every(part => typeof part === 'string' || typeof part === 'number') ? parts.join('') : null;
+};
+
+const onlyChild = (children: ReactNode) => {
+ const parts = Children.toArray(children);
+ return parts.length === 1 && isValidElement(parts[0]) ? parts[0] : null;
+};
+
+type TProps = Record;
+type TDescriber = (props: TProps) => TNativeListAccessory | null | undefined;
+
+const describeText: TDescriber = ({ children }) => {
+ const text = textContent(children);
+ return text === null ? undefined : { kind: 'text', text };
+};
+
+const describeToggle: TDescriber = props => {
+ const { value, onValueChange, disabled, testID } = props as SwitchProps;
+ return { kind: 'toggle', isOn: Boolean(value), onValueChange: onValueChange ?? undefined, disabled: Boolean(disabled), testID };
+};
+
+const describeCheckbox: TDescriber = props => {
+ const { value, onValueChange, testID } = props as IListCheckbox;
+ return { kind: 'checkbox', value, onValueChange, testID };
+};
+
+const describeWrapper: TDescriber = ({ children }) => {
+ const child = onlyChild(children);
+ const described = child ? describeNativeListAccessory(child) : null;
+ return described?.kind === 'hosted' ? undefined : described;
+};
+
+const describers = new Map([
+ [ListCheckbox, describeCheckbox],
+ [ListIcon, props => iconAccessory(props.name, props)],
+ [CustomIcon, props => iconAccessory(props.name, props)],
+ [NewWindowIcon, () => ({ kind: 'indicator', indicator: 'external' })],
+ [Radio, ({ check }) => (check ? { kind: 'check' } : null)],
+ [Status, ({ status }) => ({ kind: 'status', status: status ?? 'offline' })],
+ [Switch, describeToggle],
+ [Text, describeText],
+ [View, describeWrapper]
+]);
+
+export function describeNativeListAccessory(node: ReactNode): TNativeListAccessory | null {
+ if (!isValidElement(node)) {
+ return null;
+ }
+ const described = describers.get(node.type)?.(node.props);
+ return described === undefined ? { kind: 'hosted', element: node } : described;
+}
diff --git a/app/containers/List/native/utils/itemProps.ts b/app/containers/List/native/utils/itemProps.ts
new file mode 100644
index 00000000000..78dcf7a90b2
--- /dev/null
+++ b/app/containers/List/native/utils/itemProps.ts
@@ -0,0 +1,39 @@
+import I18n from '~/i18n';
+import EventEmitter from '~/lib/methods/helpers/events';
+import { LISTENER } from '~/containers/Toast';
+import { type IListItem } from '~/containers/List/components/ListItem';
+
+export const translateListText = (text: string, shouldTranslate = true) => (shouldTranslate ? I18n.t(text) : text);
+
+export const nativeListItemTitle = ({ title, translateTitle }: IListItem) =>
+ typeof title === 'string' ? translateListText(title, translateTitle) : undefined;
+
+export const nativeListItemSubtitle = ({ subtitle, translateSubtitle }: IListItem) =>
+ subtitle ? translateListText(subtitle, translateSubtitle) : undefined;
+
+const stateLabel = ({ additionalAccessibilityLabel, additionalAccessibilityLabelCheck }: IListItem) => {
+ if (typeof additionalAccessibilityLabel === 'string') {
+ return additionalAccessibilityLabel;
+ }
+ if (typeof additionalAccessibilityLabel !== 'boolean') {
+ return undefined;
+ }
+ if (additionalAccessibilityLabelCheck) {
+ return I18n.t(additionalAccessibilityLabel ? 'Checked' : 'Unchecked');
+ }
+ return I18n.t(additionalAccessibilityLabel ? 'Enabled' : 'Disabled');
+};
+
+export const nativeListItemAccessibilityLabel = (item: IListItem) =>
+ item.accessibilityLabel ??
+ [nativeListItemTitle(item), nativeListItemSubtitle(item), stateLabel(item)].filter(Boolean).join(' ');
+
+export const pressNativeListItem = ({ disabled, disabledReason, onPress, title }: IListItem) => {
+ if (disabled && disabledReason) {
+ EventEmitter.emit(LISTENER, { message: disabledReason });
+ return;
+ }
+ if (!disabled) {
+ onPress?.(title);
+ }
+};
diff --git a/app/containers/List/native/utils/rowMarkers.ts b/app/containers/List/native/utils/rowMarkers.ts
new file mode 100644
index 00000000000..14e3e2e595b
--- /dev/null
+++ b/app/containers/List/native/utils/rowMarkers.ts
@@ -0,0 +1,16 @@
+import { type ComponentType } from 'react';
+
+const createComponentMarker = () => {
+ const markedTypes = new WeakSet