mirror of
https://github.com/flutter/packages.git
synced 2025-07-01 23:51:55 +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, strong) XCUIApplication *app;
|
||||||
|
|
||||||
|
@property(nonatomic, assign) BOOL interceptedPermissionInterruption;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation ImagePickerFromGalleryUITests
|
@implementation ImagePickerFromGalleryUITests
|
||||||
|
|
||||||
- (void)setUp {
|
- (void)setUp {
|
||||||
[super setUp];
|
[super setUp];
|
||||||
// Delete the app if already exists, to test permission popups
|
|
||||||
|
|
||||||
self.continueAfterFailure = NO;
|
self.continueAfterFailure = NO;
|
||||||
self.app = [[XCUIApplication alloc] init];
|
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.app launch];
|
||||||
|
self.interceptedPermissionInterruption = NO;
|
||||||
__weak typeof(self) weakSelf = self;
|
__weak typeof(self) weakSelf = self;
|
||||||
[self addUIInterruptionMonitorWithDescription:@"Permission popups"
|
[self addUIInterruptionMonitorWithDescription:@"Permission popups"
|
||||||
handler:^BOOL(XCUIElement *_Nonnull interruptingElement) {
|
handler:^BOOL(XCUIElement *_Nonnull interruptingElement) {
|
||||||
if (@available(iOS 14, *)) {
|
if (@available(iOS 14, *)) {
|
||||||
XCUIElement *allPhotoPermission =
|
XCUIElement *allPhotoPermission =
|
||||||
interruptingElement
|
interruptingElement
|
||||||
.buttons[@"Allow Access to All Photos"];
|
.buttons[weakSelf.allowAccessPermissionText];
|
||||||
if (![allPhotoPermission waitForExistenceWithTimeout:
|
if (![allPhotoPermission waitForExistenceWithTimeout:
|
||||||
kElementWaitingTime]) {
|
kElementWaitingTime]) {
|
||||||
os_log_error(OS_LOG_DEFAULT, "%@",
|
os_log_error(OS_LOG_DEFAULT, "%@",
|
||||||
@ -50,6 +56,7 @@ const int kElementWaitingTime = 30;
|
|||||||
}
|
}
|
||||||
[ok tap];
|
[ok tap];
|
||||||
}
|
}
|
||||||
|
weakSelf.interceptedPermissionInterruption = YES;
|
||||||
return YES;
|
return YES;
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
@ -59,6 +66,46 @@ const int kElementWaitingTime = 30;
|
|||||||
[self.app terminate];
|
[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 {
|
- (void)testCancel {
|
||||||
// Find and tap on the pick from gallery button.
|
// Find and tap on the pick from gallery button.
|
||||||
XCUIElement *imageFromGalleryButton =
|
XCUIElement *imageFromGalleryButton =
|
||||||
@ -80,9 +127,7 @@ const int kElementWaitingTime = 30;
|
|||||||
|
|
||||||
[pickButton tap];
|
[pickButton tap];
|
||||||
|
|
||||||
// There is a known bug where the permission popups interruption won't get fired until a tap
|
[self handlePermissionInterruption];
|
||||||
// happened in the app. We expect a permission popup so we do a tap here.
|
|
||||||
[self.app tap];
|
|
||||||
|
|
||||||
// Find and tap on the `Cancel` button.
|
// Find and tap on the `Cancel` button.
|
||||||
XCUIElement *cancelButton = self.app.buttons[@"Cancel"].firstMatch;
|
XCUIElement *cancelButton = self.app.buttons[@"Cancel"].firstMatch;
|
||||||
@ -151,9 +196,7 @@ const int kElementWaitingTime = 30;
|
|||||||
}
|
}
|
||||||
[pickButton tap];
|
[pickButton tap];
|
||||||
|
|
||||||
// There is a known bug where the permission popups interruption won't get fired until a tap
|
[self handlePermissionInterruption];
|
||||||
// happened in the app. We expect a permission popup so we do a tap here.
|
|
||||||
[self.app tap];
|
|
||||||
|
|
||||||
// Find an image and tap on it. (IOS 14 UI, images are showing directly)
|
// Find an image and tap on it. (IOS 14 UI, images are showing directly)
|
||||||
XCUIElement *aImage;
|
XCUIElement *aImage;
|
||||||
|
@ -11,16 +11,21 @@ const int kLimitedElementWaitingTime = 30;
|
|||||||
|
|
||||||
@property(nonatomic, strong) XCUIApplication *app;
|
@property(nonatomic, strong) XCUIApplication *app;
|
||||||
|
|
||||||
|
@property(nonatomic, assign) BOOL interceptedPermissionInterruption;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation ImagePickerFromLimitedGalleryUITests
|
@implementation ImagePickerFromLimitedGalleryUITests
|
||||||
|
|
||||||
- (void)setUp {
|
- (void)setUp {
|
||||||
[super setUp];
|
[super setUp];
|
||||||
// Delete the app if already exists, to test permission popups
|
|
||||||
|
|
||||||
self.continueAfterFailure = NO;
|
self.continueAfterFailure = NO;
|
||||||
self.app = [[XCUIApplication alloc] init];
|
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.app launch];
|
||||||
__weak typeof(self) weakSelf = self;
|
__weak typeof(self) weakSelf = self;
|
||||||
[self addUIInterruptionMonitorWithDescription:@"Permission popups"
|
[self addUIInterruptionMonitorWithDescription:@"Permission popups"
|
||||||
@ -37,6 +42,7 @@ const int kLimitedElementWaitingTime = 30;
|
|||||||
@(kLimitedElementWaitingTime));
|
@(kLimitedElementWaitingTime));
|
||||||
}
|
}
|
||||||
[limitedPhotoPermission tap];
|
[limitedPhotoPermission tap];
|
||||||
|
weakSelf.interceptedPermissionInterruption = YES;
|
||||||
return YES;
|
return YES;
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
@ -46,6 +52,38 @@ const int kLimitedElementWaitingTime = 30;
|
|||||||
[self.app terminate];
|
[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.
|
// Test the `Select Photos` button which is available after iOS 14.
|
||||||
- (void)testSelectingFromGallery API_AVAILABLE(ios(14)) {
|
- (void)testSelectingFromGallery API_AVAILABLE(ios(14)) {
|
||||||
// Find and tap on the pick from gallery button.
|
// Find and tap on the pick from gallery button.
|
||||||
@ -66,9 +104,7 @@ const int kLimitedElementWaitingTime = 30;
|
|||||||
}
|
}
|
||||||
[pickButton tap];
|
[pickButton tap];
|
||||||
|
|
||||||
// There is a known bug where the permission popups interruption won't get fired until a tap
|
[self handlePermissionInterruption];
|
||||||
// happened in the app. We expect a permission popup so we do a tap here.
|
|
||||||
[self.app tap];
|
|
||||||
|
|
||||||
// Find an image and tap on it.
|
// Find an image and tap on it.
|
||||||
XCUIElement *aImage = [self.app.scrollViews.firstMatch.images elementBoundByIndex:1];
|
XCUIElement *aImage = [self.app.scrollViews.firstMatch.images elementBoundByIndex:1];
|
||||||
|
Reference in New Issue
Block a user