@@ -15,7 +15,7 @@ async function stopScrolling() {
1515 if ( platform === 'android' ) {
1616 // Android's scrollGesture already completes the gesture. A follow-up tap in
1717 // the center of the screen can hit interactive elements like LOGIN USER.
18- await driver . pause ( 150 ) ;
18+ // await driver.pause(150);
1919 return ;
2020 }
2121
@@ -114,120 +114,16 @@ export async function scrollToEl(
114114 throw new Error ( `Element "${ identifier } " not found after ${ maxScrolls } scrolls` ) ;
115115}
116116
117- /**
118- * Wait for an iOS system alert to appear and return its text without
119- * dismissing it. Returns null if no alert appears within the timeout.
120- * iOS-only — used by the location spec which needs to accept with a
121- * specific button label.
122- */
123- export async function waitForAlert ( timeoutMs = 10_000 ) : Promise < string | null > {
124- try {
125- await driver . waitUntil (
126- async ( ) => {
127- try {
128- const buttons = await driver . execute ( 'mobile: alert' , { action : 'getButtons' } ) ;
129- return Array . isArray ( buttons ) && buttons . length > 0 ;
130- } catch {
131- return false ;
132- }
133- } ,
134- { timeout : timeoutMs , interval : 250 } ,
135- ) ;
136- return await driver . getAlertText ( ) ;
137- } catch {
138- return null ;
139- }
140- }
141-
142- /**
143- * Wait for a native system alert/permission dialog, accept it, and return
144- * its text. Returns null if no dialog appears within the timeout.
145- *
146- * iOS: uses XCUITest `mobile: alert` API.
147- * Android: looks for the standard permission dialog "Allow" button via
148- * UiAutomator (works for POST_NOTIFICATIONS, location, etc.). Handles
149- * stock Android, Samsung (`com.samsung.android.permissioncontroller`),
150- * and legacy `com.android.packageinstaller` package variants.
151- */
152- export async function acceptSystemAlert ( timeoutMs = 10_000 ) : Promise < string | null > {
153- const platform = getPlatform ( ) ;
154-
155- try {
156- if ( platform === 'ios' ) {
157- const text = await waitForAlert ( timeoutMs ) ;
158- if ( text ) await driver . acceptAlert ( ) ;
159- return text ;
160- }
161-
162- // Try resource-id first (most robust across OEMs), then fall back to
163- // text match. "Don't allow" contains "Allow" as a substring, so we
164- // must use exact `text()` rather than `textContains()`.
165- const allowSelectors = [
166- 'new UiSelector().resourceIdMatches(".*:id/permission_allow_button")' ,
167- 'new UiSelector().resourceIdMatches(".*:id/permission_allow_foreground_only_button")' ,
168- 'new UiSelector().resourceIdMatches(".*:id/permission_allow_one_time_button")' ,
169- 'new UiSelector().text("Allow")' ,
170- 'new UiSelector().text("ALLOW")' ,
171- 'new UiSelector().text("While using the app")' ,
172- ] ;
173-
174- let allowBtn : Awaited < ReturnType < typeof $ > > | null = null ;
175- const deadline = Date . now ( ) + timeoutMs ;
176- while ( Date . now ( ) < deadline ) {
177- for ( const sel of allowSelectors ) {
178- const el = await $ ( `android=${ sel } ` ) ;
179- if ( await el . isDisplayed ( ) . catch ( ( ) => false ) ) {
180- allowBtn = el ;
181- break ;
182- }
183- }
184- if ( allowBtn ) break ;
185- await driver . pause ( 250 ) ;
186- }
187-
188- if ( ! allowBtn ) return null ;
189-
190- let text = 'Permission dialog' ;
191- try {
192- const msgEl = await $ (
193- 'android=new UiSelector().resourceIdMatches(".*:id/permission_message")' ,
194- ) ;
195- if ( await msgEl . isDisplayed ( ) . catch ( ( ) => false ) ) {
196- text = await msgEl . getText ( ) ;
197- }
198- } catch {
199- /* best-effort */
200- }
201- await allowBtn . click ( ) ;
202- return text ;
203- } catch {
204- return null ;
205- }
206- }
207-
208- async function acceptSystemAlerts ( timeoutMs : number ) : Promise < void > {
209- await browser . waitUntil (
210- async ( ) => {
211- const alertText = await acceptSystemAlert ( 500 ) ;
212- return ! alertText ;
213- } ,
214- { timeout : timeoutMs , interval : 500 } ,
215- ) ;
216- }
217-
218117/**
219118 * Wait for the app to fully launch and the home screen to be visible.
119+ *
120+ * System permission dialogs are handled automatically by Appium via the
121+ * `autoGrantPermissions` (Android) and `autoAcceptAlerts` (iOS) capabilities,
122+ * so no explicit dialog handling is needed here.
220123 */
221124export async function waitForAppReady ( opts : { skipLogin ?: boolean } = { } ) {
222125 const { skipLogin = false } = opts ;
223126
224- const alertHandled = await browser . sharedStore . get ( 'alertHandled' ) ;
225- if ( ! alertHandled ) {
226- // Accept permission dialogs until the app UI is visible.
227- await acceptSystemAlerts ( 5_000 ) ;
228- await browser . sharedStore . set ( 'alertHandled' , true ) ;
229- }
230-
231127 const mainScroll = await byTestId ( 'main_scroll_view' ) ;
232128 await mainScroll . waitForDisplayed ( { timeout : 5_000 } ) ;
233129
0 commit comments