@croacroa/react-native-template 2.1.0 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (172) hide show
  1. package/.env.example +5 -0
  2. package/.eslintrc.js +8 -0
  3. package/.github/workflows/ci.yml +187 -187
  4. package/.github/workflows/eas-build.yml +55 -55
  5. package/.github/workflows/eas-update.yml +50 -50
  6. package/.github/workflows/npm-publish.yml +57 -0
  7. package/CHANGELOG.md +195 -106
  8. package/CONTRIBUTING.md +377 -377
  9. package/LICENSE +21 -21
  10. package/README.md +446 -402
  11. package/__tests__/accessibility/components.test.tsx +285 -0
  12. package/__tests__/components/Button.test.tsx +2 -4
  13. package/__tests__/components/__snapshots__/snapshots.test.tsx.snap +512 -0
  14. package/__tests__/components/snapshots.test.tsx +131 -131
  15. package/__tests__/helpers/a11y.ts +54 -0
  16. package/__tests__/hooks/useAnalytics.test.ts +100 -0
  17. package/__tests__/hooks/useAnimations.test.ts +70 -0
  18. package/__tests__/hooks/useAuth.test.tsx +71 -28
  19. package/__tests__/hooks/useMedia.test.ts +318 -0
  20. package/__tests__/hooks/usePayments.test.tsx +307 -0
  21. package/__tests__/hooks/usePermission.test.ts +230 -0
  22. package/__tests__/hooks/useWebSocket.test.ts +329 -0
  23. package/__tests__/integration/auth-api.test.tsx +224 -227
  24. package/__tests__/performance/VirtualizedList.perf.test.tsx +385 -362
  25. package/__tests__/services/api.test.ts +24 -6
  26. package/app/(auth)/home.tsx +11 -9
  27. package/app/(auth)/profile.tsx +8 -6
  28. package/app/(auth)/settings.tsx +11 -9
  29. package/app/(public)/forgot-password.tsx +25 -15
  30. package/app/(public)/login.tsx +48 -12
  31. package/app/(public)/onboarding.tsx +5 -5
  32. package/app/(public)/register.tsx +24 -15
  33. package/app/_layout.tsx +6 -3
  34. package/app.config.ts +27 -2
  35. package/assets/images/.gitkeep +7 -7
  36. package/assets/images/adaptive-icon.png +0 -0
  37. package/assets/images/favicon.png +0 -0
  38. package/assets/images/icon.png +0 -0
  39. package/assets/images/notification-icon.png +0 -0
  40. package/assets/images/splash.png +0 -0
  41. package/components/ErrorBoundary.tsx +73 -28
  42. package/components/auth/SocialLoginButtons.tsx +168 -0
  43. package/components/forms/FormInput.tsx +5 -3
  44. package/components/onboarding/OnboardingScreen.tsx +370 -370
  45. package/components/onboarding/index.ts +2 -2
  46. package/components/providers/AnalyticsProvider.tsx +67 -0
  47. package/components/providers/SuspenseBoundary.tsx +359 -357
  48. package/components/providers/index.ts +24 -21
  49. package/components/ui/AnimatedButton.tsx +1 -9
  50. package/components/ui/AnimatedList.tsx +98 -0
  51. package/components/ui/AnimatedScreen.tsx +89 -0
  52. package/components/ui/Avatar.tsx +319 -316
  53. package/components/ui/Badge.tsx +416 -416
  54. package/components/ui/BottomSheet.tsx +307 -307
  55. package/components/ui/Button.tsx +11 -3
  56. package/components/ui/Checkbox.tsx +261 -261
  57. package/components/ui/FeatureGate.tsx +57 -0
  58. package/components/ui/ForceUpdateScreen.tsx +108 -0
  59. package/components/ui/ImagePickerButton.tsx +180 -0
  60. package/components/ui/Input.stories.tsx +2 -10
  61. package/components/ui/Input.tsx +2 -10
  62. package/components/ui/OptimizedImage.tsx +369 -369
  63. package/components/ui/Paywall.tsx +253 -0
  64. package/components/ui/PermissionGate.tsx +155 -0
  65. package/components/ui/PurchaseButton.tsx +84 -0
  66. package/components/ui/Select.tsx +240 -240
  67. package/components/ui/Skeleton.tsx +3 -1
  68. package/components/ui/Toast.tsx +427 -418
  69. package/components/ui/UploadProgress.tsx +189 -0
  70. package/components/ui/VirtualizedList.tsx +288 -285
  71. package/components/ui/index.ts +28 -30
  72. package/constants/config.ts +135 -97
  73. package/docs/adr/001-state-management.md +79 -79
  74. package/docs/adr/002-styling-approach.md +130 -130
  75. package/docs/adr/003-data-fetching.md +155 -155
  76. package/docs/adr/004-auth-adapter-pattern.md +144 -144
  77. package/docs/adr/README.md +78 -78
  78. package/docs/guides/analytics-posthog.md +121 -0
  79. package/docs/guides/auth-supabase.md +162 -0
  80. package/docs/guides/feature-flags-launchdarkly.md +150 -0
  81. package/docs/guides/payments-revenuecat.md +169 -0
  82. package/docs/plans/2026-02-22-phase6-implementation.md +3222 -0
  83. package/docs/plans/2026-02-22-phase6-template-completion-design.md +196 -0
  84. package/docs/plans/2026-02-23-npm-publish-design.md +31 -0
  85. package/docs/plans/2026-02-23-phase7-polish-documentation-design.md +79 -0
  86. package/docs/plans/2026-02-23-phase8-additional-features-design.md +136 -0
  87. package/eas.json +2 -1
  88. package/hooks/index.ts +70 -40
  89. package/hooks/useAnimatedEntry.ts +204 -0
  90. package/hooks/useApi.ts +5 -4
  91. package/hooks/useAuth.tsx +7 -3
  92. package/hooks/useBiometrics.ts +295 -295
  93. package/hooks/useChannel.ts +111 -0
  94. package/hooks/useDeepLinking.ts +256 -256
  95. package/hooks/useExperiment.ts +36 -0
  96. package/hooks/useFeatureFlag.ts +59 -0
  97. package/hooks/useForceUpdate.ts +91 -0
  98. package/hooks/useImagePicker.ts +281 -375
  99. package/hooks/useInAppReview.ts +64 -0
  100. package/hooks/useMFA.ts +509 -499
  101. package/hooks/useParallax.ts +142 -0
  102. package/hooks/usePerformance.ts +434 -434
  103. package/hooks/usePermission.ts +190 -0
  104. package/hooks/usePresence.ts +129 -0
  105. package/hooks/useProducts.ts +36 -0
  106. package/hooks/usePurchase.ts +103 -0
  107. package/hooks/useRateLimit.ts +70 -0
  108. package/hooks/useSubscription.ts +49 -0
  109. package/hooks/useTrackEvent.ts +52 -0
  110. package/hooks/useTrackScreen.ts +40 -0
  111. package/hooks/useUpdates.ts +358 -358
  112. package/hooks/useUpload.ts +165 -0
  113. package/hooks/useWebSocket.ts +111 -0
  114. package/i18n/index.ts +197 -194
  115. package/i18n/locales/ar.json +170 -101
  116. package/i18n/locales/de.json +170 -101
  117. package/i18n/locales/en.json +170 -101
  118. package/i18n/locales/es.json +170 -101
  119. package/i18n/locales/fr.json +170 -101
  120. package/jest.config.js +1 -1
  121. package/maestro/README.md +113 -113
  122. package/maestro/config.yaml +35 -35
  123. package/maestro/flows/login.yaml +62 -62
  124. package/maestro/flows/mfa-login.yaml +92 -92
  125. package/maestro/flows/mfa-setup.yaml +86 -86
  126. package/maestro/flows/navigation.yaml +68 -68
  127. package/maestro/flows/offline-conflict.yaml +101 -101
  128. package/maestro/flows/offline-sync.yaml +128 -128
  129. package/maestro/flows/offline.yaml +60 -60
  130. package/maestro/flows/register.yaml +94 -94
  131. package/package.json +188 -176
  132. package/scripts/generate-placeholders.js +38 -0
  133. package/services/analytics/adapters/console.ts +50 -0
  134. package/services/analytics/analytics-adapter.ts +94 -0
  135. package/services/analytics/types.ts +73 -0
  136. package/services/analytics.ts +428 -428
  137. package/services/api.ts +419 -340
  138. package/services/auth/social/apple.ts +110 -0
  139. package/services/auth/social/google.ts +159 -0
  140. package/services/auth/social/social-auth.ts +100 -0
  141. package/services/auth/social/types.ts +80 -0
  142. package/services/authAdapter.ts +333 -333
  143. package/services/backgroundSync.ts +652 -626
  144. package/services/feature-flags/adapters/mock.ts +108 -0
  145. package/services/feature-flags/feature-flag-adapter.ts +174 -0
  146. package/services/feature-flags/types.ts +79 -0
  147. package/services/force-update.ts +140 -0
  148. package/services/index.ts +116 -54
  149. package/services/media/compression.ts +91 -0
  150. package/services/media/media-picker.ts +151 -0
  151. package/services/media/media-upload.ts +160 -0
  152. package/services/payments/adapters/mock.ts +159 -0
  153. package/services/payments/payment-adapter.ts +118 -0
  154. package/services/payments/types.ts +131 -0
  155. package/services/permissions/permission-manager.ts +284 -0
  156. package/services/permissions/types.ts +104 -0
  157. package/services/realtime/types.ts +100 -0
  158. package/services/realtime/websocket-manager.ts +441 -0
  159. package/services/security.ts +289 -286
  160. package/services/sentry.ts +4 -4
  161. package/stores/appStore.ts +9 -0
  162. package/stores/notificationStore.ts +3 -1
  163. package/tailwind.config.js +47 -47
  164. package/tsconfig.json +37 -13
  165. package/types/user.ts +1 -1
  166. package/utils/accessibility.ts +446 -446
  167. package/utils/animations/presets.ts +182 -0
  168. package/utils/animations/transitions.ts +62 -0
  169. package/utils/index.ts +63 -52
  170. package/utils/toast.ts +9 -2
  171. package/utils/validation.ts +4 -1
  172. package/utils/withAccessibility.tsx +272 -272
@@ -1,101 +1,101 @@
1
- appId: ${APP_ID}
2
- name: Offline Conflict Resolution Flow
3
- tags:
4
- - offline
5
- - sync
6
- - conflict
7
- - edge-case
8
- ---
9
- # Offline Conflict Resolution Test
10
- # Tests conflict resolution when offline changes conflict with server
11
-
12
- - launchApp:
13
- clearState: true
14
-
15
- # Login
16
- - tapOn:
17
- text: "Email"
18
- - inputText: "test@example.com"
19
- - tapOn:
20
- text: "Password"
21
- - inputText: "password123"
22
- - tapOn:
23
- text: "Sign In"
24
- index: 1
25
- - waitForAnimationToEnd:
26
- timeout: 5000
27
-
28
- # Navigate to editable content
29
- - tapOn: "Profile"
30
- - waitForAnimationToEnd
31
-
32
- # Note the current state
33
- - assertVisible: "Profile"
34
-
35
- # Go offline
36
- - setAirplaneMode:
37
- enabled: true
38
- - waitForAnimationToEnd:
39
- timeout: 3000
40
-
41
- # Edit while offline
42
- - tapOn:
43
- text: "Edit Profile"
44
- optional: true
45
- - waitForAnimationToEnd
46
- - tapOn:
47
- text: "Name"
48
- optional: true
49
- - clearText
50
- - inputText: "Client Version"
51
- - tapOn:
52
- text: "Save"
53
- optional: true
54
- - waitForAnimationToEnd
55
-
56
- # Simulate server having different version (via test flag if available)
57
- # In real test, another client would have modified the same data
58
-
59
- # Go back online
60
- - setAirplaneMode:
61
- enabled: false
62
- - waitForAnimationToEnd:
63
- timeout: 5000
64
-
65
- # Sync should detect conflict
66
- - waitForAnimationToEnd:
67
- timeout: 10000
68
-
69
- # If conflict dialog appears
70
- - assertVisible:
71
- text:
72
- - "Conflict"
73
- - "modified"
74
- - "resolve"
75
- optional: true
76
-
77
- # Choose resolution strategy (if UI presents options)
78
- - tapOn:
79
- text: "Keep my changes"
80
- optional: true
81
-
82
- # Or
83
- - tapOn:
84
- text: "Use server version"
85
- optional: true
86
-
87
- # Or
88
- - tapOn:
89
- text: "Merge"
90
- optional: true
91
-
92
- - waitForAnimationToEnd:
93
- timeout: 3000
94
-
95
- # Verify resolution completed
96
- - assertVisible:
97
- text:
98
- - "resolved"
99
- - "success"
100
- - "updated"
101
- optional: true
1
+ appId: ${APP_ID}
2
+ name: Offline Conflict Resolution Flow
3
+ tags:
4
+ - offline
5
+ - sync
6
+ - conflict
7
+ - edge-case
8
+ ---
9
+ # Offline Conflict Resolution Test
10
+ # Tests conflict resolution when offline changes conflict with server
11
+
12
+ - launchApp:
13
+ clearState: true
14
+
15
+ # Login
16
+ - tapOn:
17
+ text: "Email"
18
+ - inputText: "test@example.com"
19
+ - tapOn:
20
+ text: "Password"
21
+ - inputText: "password123"
22
+ - tapOn:
23
+ text: "Sign In"
24
+ index: 1
25
+ - waitForAnimationToEnd:
26
+ timeout: 5000
27
+
28
+ # Navigate to editable content
29
+ - tapOn: "Profile"
30
+ - waitForAnimationToEnd
31
+
32
+ # Note the current state
33
+ - assertVisible: "Profile"
34
+
35
+ # Go offline
36
+ - setAirplaneMode:
37
+ enabled: true
38
+ - waitForAnimationToEnd:
39
+ timeout: 3000
40
+
41
+ # Edit while offline
42
+ - tapOn:
43
+ text: "Edit Profile"
44
+ optional: true
45
+ - waitForAnimationToEnd
46
+ - tapOn:
47
+ text: "Name"
48
+ optional: true
49
+ - clearText
50
+ - inputText: "Client Version"
51
+ - tapOn:
52
+ text: "Save"
53
+ optional: true
54
+ - waitForAnimationToEnd
55
+
56
+ # Simulate server having different version (via test flag if available)
57
+ # In real test, another client would have modified the same data
58
+
59
+ # Go back online
60
+ - setAirplaneMode:
61
+ enabled: false
62
+ - waitForAnimationToEnd:
63
+ timeout: 5000
64
+
65
+ # Sync should detect conflict
66
+ - waitForAnimationToEnd:
67
+ timeout: 10000
68
+
69
+ # If conflict dialog appears
70
+ - assertVisible:
71
+ text:
72
+ - "Conflict"
73
+ - "modified"
74
+ - "resolve"
75
+ optional: true
76
+
77
+ # Choose resolution strategy (if UI presents options)
78
+ - tapOn:
79
+ text: "Keep my changes"
80
+ optional: true
81
+
82
+ # Or
83
+ - tapOn:
84
+ text: "Use server version"
85
+ optional: true
86
+
87
+ # Or
88
+ - tapOn:
89
+ text: "Merge"
90
+ optional: true
91
+
92
+ - waitForAnimationToEnd:
93
+ timeout: 3000
94
+
95
+ # Verify resolution completed
96
+ - assertVisible:
97
+ text:
98
+ - "resolved"
99
+ - "success"
100
+ - "updated"
101
+ optional: true
@@ -1,128 +1,128 @@
1
- appId: ${APP_ID}
2
- name: Offline Sync Flow
3
- tags:
4
- - offline
5
- - sync
6
- - edge-case
7
- ---
8
- # Offline Sync Test
9
- # Tests offline mutation queueing and sync when back online
10
-
11
- - launchApp:
12
- clearState: true
13
-
14
- # Login while online
15
- - tapOn:
16
- text: "Email"
17
- - inputText: "test@example.com"
18
- - tapOn:
19
- text: "Password"
20
- - inputText: "password123"
21
- - tapOn:
22
- text: "Sign In"
23
- index: 1
24
- - waitForAnimationToEnd:
25
- timeout: 5000
26
-
27
- # Verify login successful
28
- - assertVisible: "Home"
29
-
30
- # Navigate to a screen where we can create/edit data
31
- - tapOn: "Profile"
32
- - waitForAnimationToEnd
33
-
34
- # Enable airplane mode to go offline
35
- - setAirplaneMode:
36
- enabled: true
37
-
38
- # Wait for offline detection
39
- - waitForAnimationToEnd:
40
- timeout: 3000
41
-
42
- # Verify offline indicator
43
- - assertVisible:
44
- text: "offline"
45
- optional: true
46
-
47
- # Try to edit profile (should queue mutation)
48
- - tapOn:
49
- text: "Edit Profile"
50
- optional: true
51
- - waitForAnimationToEnd
52
-
53
- # Make a change
54
- - tapOn:
55
- text: "Name"
56
- optional: true
57
- - clearText
58
- - inputText: "Offline Updated Name"
59
-
60
- # Save (should queue for sync)
61
- - tapOn:
62
- text: "Save"
63
- optional: true
64
- - waitForAnimationToEnd
65
-
66
- # Verify queued message appears
67
- - assertVisible:
68
- text:
69
- - "queued"
70
- - "pending"
71
- - "sync"
72
- - "offline"
73
- optional: true
74
-
75
- # Make another change while offline
76
- - tapOn:
77
- text: "Edit"
78
- optional: true
79
- - waitForAnimationToEnd
80
- - tapOn:
81
- text: "Bio"
82
- optional: true
83
- - inputText: "Updated while offline"
84
- - tapOn:
85
- text: "Save"
86
- optional: true
87
- - waitForAnimationToEnd
88
-
89
- # Verify multiple items queued
90
- - assertVisible:
91
- text:
92
- - "2 pending"
93
- - "pending sync"
94
- optional: true
95
-
96
- # Go back online
97
- - setAirplaneMode:
98
- enabled: false
99
-
100
- # Wait for sync
101
- - waitForAnimationToEnd:
102
- timeout: 10000
103
-
104
- # Verify sync started
105
- - assertVisible:
106
- text:
107
- - "Syncing"
108
- - "online"
109
- optional: true
110
-
111
- # Wait for sync to complete
112
- - waitForAnimationToEnd:
113
- timeout: 5000
114
-
115
- # Verify sync completed
116
- - assertVisible:
117
- text:
118
- - "synced"
119
- - "updated"
120
- - "success"
121
- optional: true
122
-
123
- # Verify changes persisted
124
- - tapOn: "Profile"
125
- - waitForAnimationToEnd
126
- - assertVisible:
127
- text: "Offline Updated Name"
128
- optional: true
1
+ appId: ${APP_ID}
2
+ name: Offline Sync Flow
3
+ tags:
4
+ - offline
5
+ - sync
6
+ - edge-case
7
+ ---
8
+ # Offline Sync Test
9
+ # Tests offline mutation queueing and sync when back online
10
+
11
+ - launchApp:
12
+ clearState: true
13
+
14
+ # Login while online
15
+ - tapOn:
16
+ text: "Email"
17
+ - inputText: "test@example.com"
18
+ - tapOn:
19
+ text: "Password"
20
+ - inputText: "password123"
21
+ - tapOn:
22
+ text: "Sign In"
23
+ index: 1
24
+ - waitForAnimationToEnd:
25
+ timeout: 5000
26
+
27
+ # Verify login successful
28
+ - assertVisible: "Home"
29
+
30
+ # Navigate to a screen where we can create/edit data
31
+ - tapOn: "Profile"
32
+ - waitForAnimationToEnd
33
+
34
+ # Enable airplane mode to go offline
35
+ - setAirplaneMode:
36
+ enabled: true
37
+
38
+ # Wait for offline detection
39
+ - waitForAnimationToEnd:
40
+ timeout: 3000
41
+
42
+ # Verify offline indicator
43
+ - assertVisible:
44
+ text: "offline"
45
+ optional: true
46
+
47
+ # Try to edit profile (should queue mutation)
48
+ - tapOn:
49
+ text: "Edit Profile"
50
+ optional: true
51
+ - waitForAnimationToEnd
52
+
53
+ # Make a change
54
+ - tapOn:
55
+ text: "Name"
56
+ optional: true
57
+ - clearText
58
+ - inputText: "Offline Updated Name"
59
+
60
+ # Save (should queue for sync)
61
+ - tapOn:
62
+ text: "Save"
63
+ optional: true
64
+ - waitForAnimationToEnd
65
+
66
+ # Verify queued message appears
67
+ - assertVisible:
68
+ text:
69
+ - "queued"
70
+ - "pending"
71
+ - "sync"
72
+ - "offline"
73
+ optional: true
74
+
75
+ # Make another change while offline
76
+ - tapOn:
77
+ text: "Edit"
78
+ optional: true
79
+ - waitForAnimationToEnd
80
+ - tapOn:
81
+ text: "Bio"
82
+ optional: true
83
+ - inputText: "Updated while offline"
84
+ - tapOn:
85
+ text: "Save"
86
+ optional: true
87
+ - waitForAnimationToEnd
88
+
89
+ # Verify multiple items queued
90
+ - assertVisible:
91
+ text:
92
+ - "2 pending"
93
+ - "pending sync"
94
+ optional: true
95
+
96
+ # Go back online
97
+ - setAirplaneMode:
98
+ enabled: false
99
+
100
+ # Wait for sync
101
+ - waitForAnimationToEnd:
102
+ timeout: 10000
103
+
104
+ # Verify sync started
105
+ - assertVisible:
106
+ text:
107
+ - "Syncing"
108
+ - "online"
109
+ optional: true
110
+
111
+ # Wait for sync to complete
112
+ - waitForAnimationToEnd:
113
+ timeout: 5000
114
+
115
+ # Verify sync completed
116
+ - assertVisible:
117
+ text:
118
+ - "synced"
119
+ - "updated"
120
+ - "success"
121
+ optional: true
122
+
123
+ # Verify changes persisted
124
+ - tapOn: "Profile"
125
+ - waitForAnimationToEnd
126
+ - assertVisible:
127
+ text: "Offline Updated Name"
128
+ optional: true
@@ -1,60 +1,60 @@
1
- appId: ${APP_ID}
2
- name: Offline Mode Flow
3
- tags:
4
- - offline
5
- - edge-case
6
- ---
7
- # Offline Mode Test
8
- # Tests app behavior when offline
9
-
10
- - launchApp:
11
- clearState: true
12
-
13
- # Login while online
14
- - tapOn:
15
- text: "Email"
16
- - inputText: "test@example.com"
17
- - tapOn:
18
- text: "Password"
19
- - inputText: "password123"
20
- - tapOn:
21
- text: "Sign In"
22
- index: 1
23
- - waitForAnimationToEnd:
24
- timeout: 5000
25
-
26
- # Verify login successful
27
- - assertVisible: "Home"
28
-
29
- # Enable airplane mode (simulates offline)
30
- - setAirplaneMode:
31
- enabled: true
32
-
33
- # Wait for offline detection
34
- - waitForAnimationToEnd:
35
- timeout: 3000
36
-
37
- # Verify offline indicator appears
38
- - assertVisible:
39
- text: "offline"
40
- optional: true
41
-
42
- # Try to perform an action that requires network
43
- - tapOn: "Profile"
44
- - waitForAnimationToEnd
45
-
46
- # The cached data should still be visible
47
- - assertVisible: "Profile"
48
-
49
- # Disable airplane mode
50
- - setAirplaneMode:
51
- enabled: false
52
-
53
- # Wait for reconnection
54
- - waitForAnimationToEnd:
55
- timeout: 5000
56
-
57
- # Verify back online
58
- - assertVisible:
59
- text: "online"
60
- optional: true
1
+ appId: ${APP_ID}
2
+ name: Offline Mode Flow
3
+ tags:
4
+ - offline
5
+ - edge-case
6
+ ---
7
+ # Offline Mode Test
8
+ # Tests app behavior when offline
9
+
10
+ - launchApp:
11
+ clearState: true
12
+
13
+ # Login while online
14
+ - tapOn:
15
+ text: "Email"
16
+ - inputText: "test@example.com"
17
+ - tapOn:
18
+ text: "Password"
19
+ - inputText: "password123"
20
+ - tapOn:
21
+ text: "Sign In"
22
+ index: 1
23
+ - waitForAnimationToEnd:
24
+ timeout: 5000
25
+
26
+ # Verify login successful
27
+ - assertVisible: "Home"
28
+
29
+ # Enable airplane mode (simulates offline)
30
+ - setAirplaneMode:
31
+ enabled: true
32
+
33
+ # Wait for offline detection
34
+ - waitForAnimationToEnd:
35
+ timeout: 3000
36
+
37
+ # Verify offline indicator appears
38
+ - assertVisible:
39
+ text: "offline"
40
+ optional: true
41
+
42
+ # Try to perform an action that requires network
43
+ - tapOn: "Profile"
44
+ - waitForAnimationToEnd
45
+
46
+ # The cached data should still be visible
47
+ - assertVisible: "Profile"
48
+
49
+ # Disable airplane mode
50
+ - setAirplaneMode:
51
+ enabled: false
52
+
53
+ # Wait for reconnection
54
+ - waitForAnimationToEnd:
55
+ timeout: 5000
56
+
57
+ # Verify back online
58
+ - assertVisible:
59
+ text: "online"
60
+ optional: true