From 90f6849617f00aa3e02bfd04742fb1dd14d24eea Mon Sep 17 00:00:00 2001 From: Wenson Hsieh Date: Wed, 17 May 2023 06:35:15 -0700 Subject: [PATCH] [iOS] Several API tests fail when run against an iPhone 12 simulator https://bugs.webkit.org/show_bug.cgi?id=256860 rdar://109230218 Reviewed by Aditya Keerthi. Adjust several API tests and test infrastructure to be more robust to underlying platform changes, and also ensure consistent test results when running a subset of API tests against notchless vs. notched iPhone models when using `TestWKWebView`, by normalizing the safe area insets to 0 by default. * Tools/TestWebKitAPI/Tests/WebKitCocoa/RestoreScrollPosition.mm: (-[RestoreScrollPositionWithLargeContentInsetWebView safeAreaInsets]): Deleted. Remove this subclass entirely, and instead use the new `-setOverrideTopSafeAreaInset:` helper. * Tools/TestWebKitAPI/Tests/ios/KeyboardInputTestsIOS.mm: (-[TestWKWebView waitForCaretVisibility:]): Make this test robust against platform differences on iOS in caret UI and whether or not we zoom upon focusing an element, by making these tests check for the presence or absence of the caret rather than specific caret rects. This was the original intent of the API test added in 203447@main, anyways. (-[TestWKWebView waitForCaretViewFrameToBecome:]): Deleted. * Tools/TestWebKitAPI/cocoa/TestWKWebView.h: * Tools/TestWebKitAPI/cocoa/TestWKWebView.mm: (-[TestWKWebView initWithFrame:configuration:addToWindow:]): (-[TestWKWebView overrideSafeAreaInset]): (-[TestWKWebView setOverrideSafeAreaInset:]): (-[TestWKWebView safeAreaInsets]): Canonical link: https://commits.webkit.org/264150@main --- .../WebKitCocoa/RestoreScrollPosition.mm | 15 ++-------- .../Tests/ios/KeyboardInputTestsIOS.mm | 30 ++++++++++--------- Tools/TestWebKitAPI/cocoa/TestWKWebView.h | 1 + Tools/TestWebKitAPI/cocoa/TestWKWebView.mm | 19 ++++++++++++ 4 files changed, 38 insertions(+), 27 deletions(-) diff --git a/Tools/TestWebKitAPI/Tests/WebKitCocoa/RestoreScrollPosition.mm b/Tools/TestWebKitAPI/Tests/WebKitCocoa/RestoreScrollPosition.mm index cfb9eda0c437..05c808b4fb32 100644 --- a/Tools/TestWebKitAPI/Tests/WebKitCocoa/RestoreScrollPosition.mm +++ b/Tools/TestWebKitAPI/Tests/WebKitCocoa/RestoreScrollPosition.mm @@ -32,18 +32,6 @@ #import #import -#if PLATFORM(IOS_FAMILY) -@interface RestoreScrollPositionWithLargeContentInsetWebView : TestWKWebView -@end - -@implementation RestoreScrollPositionWithLargeContentInsetWebView -- (UIEdgeInsets)safeAreaInsets -{ - return UIEdgeInsetsMake(141, 0, 0, 0); -} -@end -#endif - namespace TestWebKitAPI { #if PLATFORM(IOS_FAMILY) @@ -52,7 +40,8 @@ - (UIEdgeInsets)safeAreaInsets { auto topInset = 1165; - auto webView = adoptNS([[RestoreScrollPositionWithLargeContentInsetWebView alloc] initWithFrame:CGRectMake(0, 0, 375, 1024)]); + auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 375, 1024)]); + [webView setOverrideSafeAreaInset:UIEdgeInsetsMake(141, 0, 0, 0)]; [webView synchronouslyLoadTestPageNamed:@"simple-tall"]; diff --git a/Tools/TestWebKitAPI/Tests/ios/KeyboardInputTestsIOS.mm b/Tools/TestWebKitAPI/Tests/ios/KeyboardInputTestsIOS.mm index e92013446ddf..472c7376b3c9 100644 --- a/Tools/TestWebKitAPI/Tests/ios/KeyboardInputTestsIOS.mm +++ b/Tools/TestWebKitAPI/Tests/ios/KeyboardInputTestsIOS.mm @@ -42,6 +42,12 @@ #import #import +namespace TestWebKitAPI { + +enum class CaretVisibility : bool { Hidden, Visible }; + +} + @interface WKContentView () @property (nonatomic, readonly) NSUndoManager *undoManagerForWebView; - (BOOL)_shouldSimulateKeyboardInputOnTextInsertion; @@ -109,20 +115,20 @@ static CGRect rounded(CGRect rect) return CGRectMake(std::round(rect.origin.x), std::round(rect.origin.y), std::round(rect.size.width), std::round(rect.size.height)); } -- (void)waitForCaretViewFrameToBecome:(CGRect)frame +- (void)waitForCaretVisibility:(TestWebKitAPI::CaretVisibility)visibility { BOOL hasEmittedWarning = NO; NSTimeInterval secondsToWaitUntilWarning = 2; NSTimeInterval startTime = [NSDate timeIntervalSinceReferenceDate]; while ([[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantPast]]) { - CGRect currentFrame = rounded(self.caretViewRectInContentCoordinates); - if (CGRectEqualToRect(currentFrame, frame)) + BOOL sizeIsEmpty = CGSizeEqualToSize(self.caretViewRectInContentCoordinates.size, CGSizeZero); + if ((visibility == TestWebKitAPI::CaretVisibility::Hidden) == sizeIsEmpty) break; if (hasEmittedWarning || startTime + secondsToWaitUntilWarning >= [NSDate timeIntervalSinceReferenceDate]) continue; - NSLog(@"Expected a caret rect of %@, but still observed %@", NSStringFromCGRect(frame), NSStringFromCGRect(currentFrame)); + NSLog(@"Expected the caret to %s", visibility == TestWebKitAPI::CaretVisibility::Hidden ? "disappear" : "appear"); hasEmittedWarning = YES; } } @@ -477,19 +483,17 @@ - (NSUndoManager *)undoManager TEST(KeyboardInputTests, CaretSelectionRectAfterRestoringFirstResponderWithRetainActiveFocusedState) { - // This difference in caret width is due to the fact that we don't zoom in to the input field on iPad, but do on iPhone. - auto expectedCaretRect = CGRectMake(14, 11, UIDevice.currentDevice.userInterfaceIdiom == UIUserInterfaceIdiomPad ? 3 : 2, 15); auto [webView, inputDelegate] = webViewAndInputDelegateWithAutofocusedInput(); EXPECT_WK_STREQ("INPUT", [webView stringByEvaluatingJavaScript:@"document.activeElement.tagName"]); - [webView waitForCaretViewFrameToBecome:expectedCaretRect]; + [webView waitForCaretVisibility:CaretVisibility::Visible]; dispatch_block_t restoreActiveFocusState = [webView _retainActiveFocusedState]; [webView resignFirstResponder]; restoreActiveFocusState(); - [webView waitForCaretViewFrameToBecome:CGRectZero]; + [webView waitForCaretVisibility:CaretVisibility::Hidden]; [webView becomeFirstResponder]; - [webView waitForCaretViewFrameToBecome:expectedCaretRect]; + [webView waitForCaretVisibility:CaretVisibility::Visible]; } TEST(KeyboardInputTests, RangedSelectionRectAfterRestoringFirstResponderWithRetainActiveFocusedState) @@ -513,17 +517,15 @@ - (NSUndoManager *)undoManager TEST(KeyboardInputTests, CaretSelectionRectAfterRestoringFirstResponder) { - // This difference in caret width is due to the fact that we don't zoom in to the input field on iPad, but do on iPhone. - auto expectedCaretRect = CGRectMake(14, 11, UIDevice.currentDevice.userInterfaceIdiom == UIUserInterfaceIdiomPad ? 3 : 2, 15); auto [webView, inputDelegate] = webViewAndInputDelegateWithAutofocusedInput(); EXPECT_WK_STREQ("INPUT", [webView stringByEvaluatingJavaScript:@"document.activeElement.tagName"]); - [webView waitForCaretViewFrameToBecome:expectedCaretRect]; + [webView waitForCaretVisibility:CaretVisibility::Visible]; [webView resignFirstResponder]; - [webView waitForCaretViewFrameToBecome:CGRectZero]; + [webView waitForCaretVisibility:CaretVisibility::Hidden]; [webView becomeFirstResponder]; - [webView waitForCaretViewFrameToBecome:expectedCaretRect]; + [webView waitForCaretVisibility:CaretVisibility::Visible]; } TEST(KeyboardInputTests, RangedSelectionRectAfterRestoringFirstResponder) diff --git a/Tools/TestWebKitAPI/cocoa/TestWKWebView.h b/Tools/TestWebKitAPI/cocoa/TestWKWebView.h index f0ce8146d1bf..0d200533a65e 100644 --- a/Tools/TestWebKitAPI/cocoa/TestWKWebView.h +++ b/Tools/TestWebKitAPI/cocoa/TestWKWebView.h @@ -124,6 +124,7 @@ @end @interface TestWKWebView (IOSOnly) +@property (nonatomic) UIEdgeInsets overrideSafeAreaInset; @property (nonatomic, readonly) CGRect caretViewRectInContentCoordinates; @property (nonatomic, readonly) NSArray *selectionViewRectsInContentCoordinates; - (_WKActivatedElementInfo *)activatedElementAtPosition:(CGPoint)position; diff --git a/Tools/TestWebKitAPI/cocoa/TestWKWebView.mm b/Tools/TestWebKitAPI/cocoa/TestWKWebView.mm index 2bd2e9e8e7ad..498b3bd94a7e 100644 --- a/Tools/TestWebKitAPI/cocoa/TestWKWebView.mm +++ b/Tools/TestWebKitAPI/cocoa/TestWKWebView.mm @@ -476,6 +476,7 @@ @implementation TestWKWebView { #if PLATFORM(IOS_FAMILY) std::unique_ptr _sharedCalloutBarSwizzler; InputSessionChangeCount _inputSessionChangeCount; + UIEdgeInsets _overrideSafeAreaInset; #endif #if PLATFORM(MAC) BOOL _forceWindowToBecomeKey; @@ -516,6 +517,9 @@ - (instancetype)initWithFrame:(CGRect)frame configuration:(WKWebViewConfiguratio // FIXME: Remove this workaround once is fixed. _sharedCalloutBarSwizzler = makeUnique([UICalloutBar class], @selector(sharedCalloutBar), reinterpret_cast(suppressUICalloutBar)); _inputSessionChangeCount = 0; + // We suppress safe area insets by default in order to ensure consistent results when running against device models + // that may or may not have safe area insets, have insets with different values (e.g. iOS devices with a notch). + _overrideSafeAreaInset = UIEdgeInsetsZero; #endif return self; @@ -760,6 +764,21 @@ - (void)evaluateJavaScriptAndWaitForInputSessionToChange:(NSString *)script } } +- (UIEdgeInsets)overrideSafeAreaInset +{ + return _overrideSafeAreaInset; +} + +- (void)setOverrideSafeAreaInset:(UIEdgeInsets)inset +{ + _overrideSafeAreaInset = inset; +} + +- (UIEdgeInsets)safeAreaInsets +{ + return _overrideSafeAreaInset; +} + - (CGRect)caretViewRectInContentCoordinates { UIView *caretView = nil;