@@ -145,7 +145,9 @@ export async function waitForAlert(timeoutMs = 10_000): Promise<string | null> {
145145 *
146146 * iOS: uses XCUITest `mobile: alert` API.
147147 * Android: looks for the standard permission dialog "Allow" button via
148- * UiAutomator (works for POST_NOTIFICATIONS, location, etc.).
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.
149151 */
150152export async function acceptSystemAlert ( timeoutMs = 10_000 ) : Promise < string | null > {
151153 const platform = getPlatform ( ) ;
@@ -157,14 +159,42 @@ export async function acceptSystemAlert(timeoutMs = 10_000): Promise<string | nu
157159 return text ;
158160 }
159161
160- const allowBtn = await $ ( 'android=new UiSelector().text("Allow")' ) ;
161- await allowBtn . waitForDisplayed ( { timeout : timeoutMs } ) ;
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+
162190 let text = 'Permission dialog' ;
163191 try {
164192 const msgEl = await $ (
165- 'android=new UiSelector().resourceId("com.android.permissioncontroller :id/permission_message")' ,
193+ 'android=new UiSelector().resourceIdMatches(".* :id/permission_message")' ,
166194 ) ;
167- text = await msgEl . getText ( ) ;
195+ if ( await msgEl . isDisplayed ( ) . catch ( ( ) => false ) ) {
196+ text = await msgEl . getText ( ) ;
197+ }
168198 } catch {
169199 /* best-effort */
170200 }
0 commit comments