@croacroa/react-native-template 2.0.1 → 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.
- package/.env.example +5 -0
- package/.eslintrc.js +8 -0
- package/.github/workflows/ci.yml +187 -187
- package/.github/workflows/eas-build.yml +55 -55
- package/.github/workflows/eas-update.yml +50 -50
- package/.github/workflows/npm-publish.yml +57 -0
- package/CHANGELOG.md +195 -106
- package/CONTRIBUTING.md +377 -377
- package/LICENSE +21 -0
- package/README.md +446 -399
- package/__tests__/accessibility/components.test.tsx +285 -0
- package/__tests__/components/Button.test.tsx +2 -4
- package/__tests__/components/__snapshots__/snapshots.test.tsx.snap +512 -0
- package/__tests__/components/snapshots.test.tsx +131 -131
- package/__tests__/helpers/a11y.ts +54 -0
- package/__tests__/hooks/useAnalytics.test.ts +100 -0
- package/__tests__/hooks/useAnimations.test.ts +70 -0
- package/__tests__/hooks/useAuth.test.tsx +71 -28
- package/__tests__/hooks/useMedia.test.ts +318 -0
- package/__tests__/hooks/usePayments.test.tsx +307 -0
- package/__tests__/hooks/usePermission.test.ts +230 -0
- package/__tests__/hooks/useWebSocket.test.ts +329 -0
- package/__tests__/integration/auth-api.test.tsx +224 -227
- package/__tests__/performance/VirtualizedList.perf.test.tsx +385 -362
- package/__tests__/services/api.test.ts +24 -6
- package/app/(auth)/home.tsx +11 -9
- package/app/(auth)/profile.tsx +8 -6
- package/app/(auth)/settings.tsx +11 -9
- package/app/(public)/forgot-password.tsx +25 -15
- package/app/(public)/login.tsx +48 -12
- package/app/(public)/onboarding.tsx +5 -5
- package/app/(public)/register.tsx +24 -15
- package/app/_layout.tsx +6 -3
- package/app.config.ts +27 -2
- package/assets/images/.gitkeep +7 -7
- package/assets/images/adaptive-icon.png +0 -0
- package/assets/images/favicon.png +0 -0
- package/assets/images/icon.png +0 -0
- package/assets/images/notification-icon.png +0 -0
- package/assets/images/splash.png +0 -0
- package/components/ErrorBoundary.tsx +73 -28
- package/components/auth/SocialLoginButtons.tsx +168 -0
- package/components/forms/FormInput.tsx +5 -3
- package/components/onboarding/OnboardingScreen.tsx +370 -370
- package/components/onboarding/index.ts +2 -2
- package/components/providers/AnalyticsProvider.tsx +67 -0
- package/components/providers/SuspenseBoundary.tsx +359 -357
- package/components/providers/index.ts +24 -21
- package/components/ui/AnimatedButton.tsx +1 -9
- package/components/ui/AnimatedList.tsx +98 -0
- package/components/ui/AnimatedScreen.tsx +89 -0
- package/components/ui/Avatar.tsx +319 -316
- package/components/ui/Badge.tsx +416 -416
- package/components/ui/BottomSheet.tsx +307 -307
- package/components/ui/Button.tsx +11 -3
- package/components/ui/Checkbox.tsx +261 -261
- package/components/ui/FeatureGate.tsx +57 -0
- package/components/ui/ForceUpdateScreen.tsx +108 -0
- package/components/ui/ImagePickerButton.tsx +180 -0
- package/components/ui/Input.stories.tsx +2 -10
- package/components/ui/Input.tsx +2 -10
- package/components/ui/OptimizedImage.tsx +369 -369
- package/components/ui/Paywall.tsx +253 -0
- package/components/ui/PermissionGate.tsx +155 -0
- package/components/ui/PurchaseButton.tsx +84 -0
- package/components/ui/Select.tsx +240 -240
- package/components/ui/Skeleton.tsx +3 -1
- package/components/ui/Toast.tsx +427 -0
- package/components/ui/UploadProgress.tsx +189 -0
- package/components/ui/VirtualizedList.tsx +288 -285
- package/components/ui/index.ts +28 -23
- package/constants/config.ts +135 -97
- package/docs/adr/001-state-management.md +79 -79
- package/docs/adr/002-styling-approach.md +130 -130
- package/docs/adr/003-data-fetching.md +155 -155
- package/docs/adr/004-auth-adapter-pattern.md +144 -144
- package/docs/adr/README.md +78 -78
- package/docs/guides/analytics-posthog.md +121 -0
- package/docs/guides/auth-supabase.md +162 -0
- package/docs/guides/feature-flags-launchdarkly.md +150 -0
- package/docs/guides/payments-revenuecat.md +169 -0
- package/docs/plans/2026-02-22-phase6-implementation.md +3222 -0
- package/docs/plans/2026-02-22-phase6-template-completion-design.md +196 -0
- package/docs/plans/2026-02-23-npm-publish-design.md +31 -0
- package/docs/plans/2026-02-23-phase7-polish-documentation-design.md +79 -0
- package/docs/plans/2026-02-23-phase8-additional-features-design.md +136 -0
- package/eas.json +2 -1
- package/hooks/index.ts +70 -27
- package/hooks/useAnimatedEntry.ts +204 -0
- package/hooks/useApi.ts +64 -4
- package/hooks/useAuth.tsx +7 -3
- package/hooks/useBiometrics.ts +295 -295
- package/hooks/useChannel.ts +111 -0
- package/hooks/useDeepLinking.ts +256 -256
- package/hooks/useExperiment.ts +36 -0
- package/hooks/useFeatureFlag.ts +59 -0
- package/hooks/useForceUpdate.ts +91 -0
- package/hooks/useImagePicker.ts +281 -0
- package/hooks/useInAppReview.ts +64 -0
- package/hooks/useMFA.ts +509 -499
- package/hooks/useParallax.ts +142 -0
- package/hooks/usePerformance.ts +434 -434
- package/hooks/usePermission.ts +190 -0
- package/hooks/usePresence.ts +129 -0
- package/hooks/useProducts.ts +36 -0
- package/hooks/usePurchase.ts +103 -0
- package/hooks/useRateLimit.ts +70 -0
- package/hooks/useSubscription.ts +49 -0
- package/hooks/useTrackEvent.ts +52 -0
- package/hooks/useTrackScreen.ts +40 -0
- package/hooks/useUpdates.ts +358 -358
- package/hooks/useUpload.ts +165 -0
- package/hooks/useWebSocket.ts +111 -0
- package/i18n/index.ts +197 -194
- package/i18n/locales/ar.json +170 -101
- package/i18n/locales/de.json +170 -101
- package/i18n/locales/en.json +170 -101
- package/i18n/locales/es.json +170 -101
- package/i18n/locales/fr.json +170 -101
- package/jest.config.js +1 -1
- package/maestro/README.md +113 -113
- package/maestro/config.yaml +35 -35
- package/maestro/flows/login.yaml +62 -62
- package/maestro/flows/mfa-login.yaml +92 -92
- package/maestro/flows/mfa-setup.yaml +86 -86
- package/maestro/flows/navigation.yaml +68 -68
- package/maestro/flows/offline-conflict.yaml +101 -101
- package/maestro/flows/offline-sync.yaml +128 -128
- package/maestro/flows/offline.yaml +60 -60
- package/maestro/flows/register.yaml +94 -94
- package/package.json +188 -175
- package/scripts/generate-placeholders.js +38 -0
- package/services/analytics/adapters/console.ts +50 -0
- package/services/analytics/analytics-adapter.ts +94 -0
- package/services/analytics/types.ts +73 -0
- package/services/analytics.ts +428 -428
- package/services/api.ts +419 -340
- package/services/auth/social/apple.ts +110 -0
- package/services/auth/social/google.ts +159 -0
- package/services/auth/social/social-auth.ts +100 -0
- package/services/auth/social/types.ts +80 -0
- package/services/authAdapter.ts +333 -333
- package/services/backgroundSync.ts +652 -626
- package/services/feature-flags/adapters/mock.ts +108 -0
- package/services/feature-flags/feature-flag-adapter.ts +174 -0
- package/services/feature-flags/types.ts +79 -0
- package/services/force-update.ts +140 -0
- package/services/index.ts +116 -54
- package/services/media/compression.ts +91 -0
- package/services/media/media-picker.ts +151 -0
- package/services/media/media-upload.ts +160 -0
- package/services/payments/adapters/mock.ts +159 -0
- package/services/payments/payment-adapter.ts +118 -0
- package/services/payments/types.ts +131 -0
- package/services/permissions/permission-manager.ts +284 -0
- package/services/permissions/types.ts +104 -0
- package/services/realtime/types.ts +100 -0
- package/services/realtime/websocket-manager.ts +441 -0
- package/services/security.ts +289 -286
- package/services/sentry.ts +4 -4
- package/stores/appStore.ts +9 -0
- package/stores/notificationStore.ts +3 -1
- package/tailwind.config.js +47 -47
- package/tsconfig.json +37 -13
- package/types/user.ts +1 -1
- package/utils/accessibility.ts +446 -446
- package/utils/animations/presets.ts +182 -0
- package/utils/animations/transitions.ts +62 -0
- package/utils/index.ts +63 -52
- package/utils/toast.ts +9 -2
- package/utils/validation.ts +4 -1
- 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
|