mirror of
https://github.com/flutter/packages.git
synced 2025-07-01 07:08:10 +08:00
[image_picker_ios] Update UITests for Xcode 15/iOS 17 (#5176)
With Xcode 15, XCTest's `addUIInterruptionMonitorWithDescription` sometimes doesn't work. To fix, I added a fallback to query for the buttons in the permissions dialog. Also, the Allow text in the permissions dialog is different in iOS 17 than previous versions. Fixes https://github.com/flutter/flutter/issues/136747 Example passing on Xcode 15 with iOS 17 simulator: https://ci.chromium.org/ui/p/flutter/builders/try/Mac_arm64%20ios_platform_tests_shard_3%20master/7604/overview
This commit is contained in:

committed by
GitHub

parent
f95d53480a
commit
353e9a2f95
@ -11,24 +11,30 @@ const int kElementWaitingTime = 30;
|
||||
|
||||
@property(nonatomic, strong) XCUIApplication *app;
|
||||
|
||||
@property(nonatomic, assign) BOOL interceptedPermissionInterruption;
|
||||
|
||||
@end
|
||||
|
||||
@implementation ImagePickerFromGalleryUITests
|
||||
|
||||
- (void)setUp {
|
||||
[super setUp];
|
||||
// Delete the app if already exists, to test permission popups
|
||||
|
||||
self.continueAfterFailure = NO;
|
||||
self.app = [[XCUIApplication alloc] init];
|
||||
if (@available(iOS 13.4, *)) {
|
||||
// Reset the authorization status for Photos to test permission popups
|
||||
[self.app resetAuthorizationStatusForResource:XCUIProtectedResourcePhotos];
|
||||
}
|
||||
[self.app launch];
|
||||
self.interceptedPermissionInterruption = NO;
|
||||
__weak typeof(self) weakSelf = self;
|
||||
[self addUIInterruptionMonitorWithDescription:@"Permission popups"
|
||||
handler:^BOOL(XCUIElement *_Nonnull interruptingElement) {
|
||||
if (@available(iOS 14, *)) {
|
||||
XCUIElement *allPhotoPermission =
|
||||
interruptingElement
|
||||
.buttons[@"Allow Access to All Photos"];
|
||||
.buttons[weakSelf.allowAccessPermissionText];
|
||||
if (![allPhotoPermission waitForExistenceWithTimeout:
|
||||
kElementWaitingTime]) {
|
||||
os_log_error(OS_LOG_DEFAULT, "%@",
|
||||
@ -50,6 +56,7 @@ const int kElementWaitingTime = 30;
|
||||
}
|
||||
[ok tap];
|
||||
}
|
||||
weakSelf.interceptedPermissionInterruption = YES;
|
||||
return YES;
|
||||
}];
|
||||
}
|
||||
@ -59,6 +66,46 @@ const int kElementWaitingTime = 30;
|
||||
[self.app terminate];
|
||||
}
|
||||
|
||||
- (NSString *)allowAccessPermissionText {
|
||||
NSString *fullAccessButtonText = @"Allow Access to All Photos";
|
||||
if (@available(iOS 17, *)) {
|
||||
fullAccessButtonText = @"Allow Full Access";
|
||||
}
|
||||
return fullAccessButtonText;
|
||||
}
|
||||
|
||||
- (void)handlePermissionInterruption {
|
||||
// addUIInterruptionMonitorWithDescription is only invoked when trying to interact with an element
|
||||
// (the app in this case) the alert is blocking. We expect a permission popup here so do a swipe
|
||||
// up action (which should be harmless).
|
||||
[self.app swipeUp];
|
||||
|
||||
if (@available(iOS 17, *)) {
|
||||
// addUIInterruptionMonitorWithDescription does not work consistently on Xcode 15 simulators, so
|
||||
// use a backup method of accepting permissions popup.
|
||||
|
||||
if (self.interceptedPermissionInterruption == YES) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If cancel button exists, permission has already been given.
|
||||
XCUIElement *cancelButton = self.app.buttons[@"Cancel"].firstMatch;
|
||||
if ([cancelButton waitForExistenceWithTimeout:kElementWaitingTime]) {
|
||||
return;
|
||||
}
|
||||
|
||||
XCUIApplication *springboardApp =
|
||||
[[XCUIApplication alloc] initWithBundleIdentifier:@"com.apple.springboard"];
|
||||
XCUIElement *allowButton = springboardApp.buttons[self.allowAccessPermissionText];
|
||||
if (![allowButton waitForExistenceWithTimeout:kElementWaitingTime]) {
|
||||
os_log_error(OS_LOG_DEFAULT, "%@", self.app.debugDescription);
|
||||
XCTFail(@"Failed due to not able to find Allow Access button with %@ seconds",
|
||||
@(kElementWaitingTime));
|
||||
}
|
||||
[allowButton tap];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)testCancel {
|
||||
// Find and tap on the pick from gallery button.
|
||||
XCUIElement *imageFromGalleryButton =
|
||||
@ -80,9 +127,7 @@ const int kElementWaitingTime = 30;
|
||||
|
||||
[pickButton tap];
|
||||
|
||||
// There is a known bug where the permission popups interruption won't get fired until a tap
|
||||
// happened in the app. We expect a permission popup so we do a tap here.
|
||||
[self.app tap];
|
||||
[self handlePermissionInterruption];
|
||||
|
||||
// Find and tap on the `Cancel` button.
|
||||
XCUIElement *cancelButton = self.app.buttons[@"Cancel"].firstMatch;
|
||||
@ -151,9 +196,7 @@ const int kElementWaitingTime = 30;
|
||||
}
|
||||
[pickButton tap];
|
||||
|
||||
// There is a known bug where the permission popups interruption won't get fired until a tap
|
||||
// happened in the app. We expect a permission popup so we do a tap here.
|
||||
[self.app tap];
|
||||
[self handlePermissionInterruption];
|
||||
|
||||
// Find an image and tap on it. (IOS 14 UI, images are showing directly)
|
||||
XCUIElement *aImage;
|
||||
|
@ -11,16 +11,21 @@ const int kLimitedElementWaitingTime = 30;
|
||||
|
||||
@property(nonatomic, strong) XCUIApplication *app;
|
||||
|
||||
@property(nonatomic, assign) BOOL interceptedPermissionInterruption;
|
||||
|
||||
@end
|
||||
|
||||
@implementation ImagePickerFromLimitedGalleryUITests
|
||||
|
||||
- (void)setUp {
|
||||
[super setUp];
|
||||
// Delete the app if already exists, to test permission popups
|
||||
|
||||
self.continueAfterFailure = NO;
|
||||
self.app = [[XCUIApplication alloc] init];
|
||||
if (@available(iOS 13.4, *)) {
|
||||
// Reset the authorization status for Photos to test permission popups
|
||||
[self.app resetAuthorizationStatusForResource:XCUIProtectedResourcePhotos];
|
||||
}
|
||||
[self.app launch];
|
||||
__weak typeof(self) weakSelf = self;
|
||||
[self addUIInterruptionMonitorWithDescription:@"Permission popups"
|
||||
@ -37,6 +42,7 @@ const int kLimitedElementWaitingTime = 30;
|
||||
@(kLimitedElementWaitingTime));
|
||||
}
|
||||
[limitedPhotoPermission tap];
|
||||
weakSelf.interceptedPermissionInterruption = YES;
|
||||
return YES;
|
||||
}];
|
||||
}
|
||||
@ -46,6 +52,38 @@ const int kLimitedElementWaitingTime = 30;
|
||||
[self.app terminate];
|
||||
}
|
||||
|
||||
- (void)handlePermissionInterruption {
|
||||
// addUIInterruptionMonitorWithDescription is only invoked when trying to interact with an element
|
||||
// (the app in this case) the alert is blocking. We expect a permission popup here so do a swipe
|
||||
// up action (which should be harmless).
|
||||
[self.app swipeUp];
|
||||
|
||||
if (@available(iOS 17, *)) {
|
||||
// addUIInterruptionMonitorWithDescription does not work consistently on Xcode 15 simulators, so
|
||||
// use a backup method of accepting permissions popup.
|
||||
|
||||
if (self.interceptedPermissionInterruption == YES) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If cancel button exists, permission has already been given.
|
||||
XCUIElement *cancelButton = self.app.buttons[@"Cancel"].firstMatch;
|
||||
if ([cancelButton waitForExistenceWithTimeout:kLimitedElementWaitingTime]) {
|
||||
return;
|
||||
}
|
||||
|
||||
XCUIApplication *springboardApp =
|
||||
[[XCUIApplication alloc] initWithBundleIdentifier:@"com.apple.springboard"];
|
||||
XCUIElement *allowButton = springboardApp.buttons[@"Limit Access…"];
|
||||
if (![allowButton waitForExistenceWithTimeout:kLimitedElementWaitingTime]) {
|
||||
os_log_error(OS_LOG_DEFAULT, "%@", self.app.debugDescription);
|
||||
XCTFail(@"Failed due to not able to find Limit Access button with %@ seconds",
|
||||
@(kLimitedElementWaitingTime));
|
||||
}
|
||||
[allowButton tap];
|
||||
}
|
||||
}
|
||||
|
||||
// Test the `Select Photos` button which is available after iOS 14.
|
||||
- (void)testSelectingFromGallery API_AVAILABLE(ios(14)) {
|
||||
// Find and tap on the pick from gallery button.
|
||||
@ -66,9 +104,7 @@ const int kLimitedElementWaitingTime = 30;
|
||||
}
|
||||
[pickButton tap];
|
||||
|
||||
// There is a known bug where the permission popups interruption won't get fired until a tap
|
||||
// happened in the app. We expect a permission popup so we do a tap here.
|
||||
[self.app tap];
|
||||
[self handlePermissionInterruption];
|
||||
|
||||
// Find an image and tap on it.
|
||||
XCUIElement *aImage = [self.app.scrollViews.firstMatch.images elementBoundByIndex:1];
|
||||
|
Reference in New Issue
Block a user