|  | // Copyright 2022 The Chromium Authors | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #import "ios/testing/system_alert_handler.h" | 
|  |  | 
|  | #import <XCTest/XCTest.h> | 
|  |  | 
|  | #import "base/test/ios/wait_util.h" | 
|  |  | 
|  | using base::test::ios::kWaitForUIElementTimeout; | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | // Returns true if any static text child of `element` (XCUIElement*) contains | 
|  | // `text` (NSString*). | 
|  | BOOL ElementStaticTextContainsText(XCUIElement* element, NSString* text) { | 
|  | NSPredicate* label_contains_text = | 
|  | [NSPredicate predicateWithFormat:@"%K CONTAINS[c] %@", @"label", text]; | 
|  | return | 
|  | [element.staticTexts containingPredicate:label_contains_text].count > 0; | 
|  | } | 
|  |  | 
|  | // Closes the `alert` (XCUIElement*) if it matches a known text/button pair and | 
|  | // returns whether it succeeded or not in closing it. | 
|  | BOOL HandleSingleAlert(XCUIElement* alert) { | 
|  | NSDictionary<NSString*, NSArray<NSString*>*>* text_to_buttons = | 
|  | TextToButtonsOfKnownSystemAlerts(); | 
|  | for (NSString* text in text_to_buttons) { | 
|  | if (ElementStaticTextContainsText(alert, text)) { | 
|  | NSLog(@"Found alert containing text: %@", text); | 
|  |  | 
|  | for (NSString* button in text_to_buttons[text]) { | 
|  | if (!alert.buttons[button].exists) { | 
|  | NSLog(@"Button %@ doesn't exist. Skip tapping.", button); | 
|  | continue; | 
|  | } | 
|  |  | 
|  | NSLog(@"Tapping alert button: %@", button); | 
|  | [alert.buttons[button] tap]; | 
|  | return YES; | 
|  | } | 
|  | } | 
|  | } | 
|  | return NO; | 
|  | } | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | NSDictionary<NSString*, NSArray<NSString*>*>* TextToButtonsOfKnownSystemAlerts( | 
|  | void) { | 
|  | static NSDictionary<NSString*, NSArray<NSString*>*>* text_to_buttons = nil; | 
|  | static dispatch_once_t once_token; | 
|  | dispatch_once(&once_token, ^{ | 
|  | text_to_buttons = @{ | 
|  | @"Software Update" : @[ @"Later", @"Remind Me Later" ], | 
|  | @"A new iOS update is now available." : @[ @"Close" ], | 
|  | @"Carrier Settings Update" : @[ @"Not Now" ], | 
|  | @"would like to find and connect to devices on your local network" : | 
|  | @[ @"OK", @"Allow" ], | 
|  | @"Unable to activate Touch ID on this iPhone." : @[ @"OK" ], | 
|  | @"Like to Access the Microphone" : @[ @"OK" ], | 
|  | @"Edit Home Screen" : @[ @"Dismiss" ], | 
|  | @"Apple ID Verification" : @[ @"Not Now" ], | 
|  | @"iPhone is not Activated" : @[ @"Dismiss" ], | 
|  | @"Account Verification" : @[ @"Not Now" ], | 
|  | @"to find devices on local networks" : @[ @"Allow" ], | 
|  | @"Not Installed" : @[ @"OK" ], | 
|  | @"No SIM Card Installed" : @[ @"OK" ], | 
|  | @"Set Up Cellular" : @[ @"Not Now" ], | 
|  | }; | 
|  | }); | 
|  | return text_to_buttons; | 
|  | } | 
|  |  | 
|  | BOOL HandleKnownSystemAlertsIfVisible(void) { | 
|  | XCUIApplication* springboard_app = [[XCUIApplication alloc] | 
|  | initWithBundleIdentifier:@"com.apple.springboard"]; | 
|  | XCUIElement* alert = springboard_app.alerts.firstMatch; | 
|  |  | 
|  | // Limit attempt times. If attempt limit is exceeded, it means something went | 
|  | // wrong in tapping the buttons. | 
|  | int attempt = 0; | 
|  | while ( | 
|  | attempt < 5 && | 
|  | [alert | 
|  | waitForExistenceWithTimeout:kWaitForUIElementTimeout.InSecondsF()]) { | 
|  | NSLog(@"Alert on screen: %@", alert.label); | 
|  | if (!HandleSingleAlert(alert)) { | 
|  | return NO; | 
|  | } | 
|  | attempt++; | 
|  | } | 
|  | return attempt < 5; | 
|  | } |