Modified: trunk/Tools/ChangeLog (240300 => 240301)
--- trunk/Tools/ChangeLog 2019-01-22 23:08:36 UTC (rev 240300)
+++ trunk/Tools/ChangeLog 2019-01-22 23:21:45 UTC (rev 240301)
@@ -1,3 +1,53 @@
+2019-01-22 Wenson Hsieh <wenson_hs...@apple.com>
+
+ [iOS] Multiple WKWebViewAutofillTests are flaky failures
+ https://bugs.webkit.org/show_bug.cgi?id=189165
+ <rdar://problem/47433765>
+
+ Reviewed by Tim Horton.
+
+ These tests are currently flaky because they expect an invocation of "Element.blur()" in the web process to
+ immediately dispatch an IPC message to notify the UI process that the element has been blurred. In particular,
+ the -textInputHasAutofillContext helper assumes that waiting for the next remote layer tree commit in the UI
+ process in sufficient to ensure that any previous action that blurred the focused element in the web process
+ would make its way to the UI process by the time the layer tree commit is finished.
+
+ However, WebPage::elementDidBlur sends its IPC message to the UI process asynchronously, using callOnMainThread.
+ This means that if a layer tree flush was already scheduled in the web process before the element was blurred,
+ the element blur IPC message to the UI process will lose the race against the layer tree commit, and the test
+ will fail because it asks for -_autofillContext too early.
+
+ To fix this, we tweak these tests to actually wait until the intended input session change triggered by script
+ is handled in the UI process.
+
+ * TestWebKitAPI/Tests/ios/WKWebViewAutofillTests.mm:
+
+ Tweak some of these tests to wait for input session changes before checking for the presence of an autofill
+ context. The only exception is an existing test that doesn't allow programmatic focus to begin input sessions
+ by default; to fix this test, we simply wait for _WKInputDelegate to be invoked, instead of waiting for a new
+ input session.
+
+ (-[AutofillTestView textInputHasAutofillContext]):
+
+ Remove the incorrect presentation update here. This helper now assumes that the UI process is up to date.
+
+ * TestWebKitAPI/cocoa/TestWKWebView.h:
+ * TestWebKitAPI/cocoa/TestWKWebView.mm:
+ (nextInputSessionChangeCount):
+
+ Monotonically increasing identifier that's incremented whenever an input session is started in the UI process.
+ This includes changing the focused element from one to another.
+
+ (-[TestWKWebView initWithFrame:configuration:addToWindow:]):
+ (-[TestWKWebView didStartFormControlInteraction]):
+ (-[TestWKWebView didEndFormControlInteraction]):
+ (-[TestWKWebView evaluateJavaScriptAndWaitForInputSessionToChange:]):
+
+ Add a helper to evaluate _javascript_ and wait for this script to cause some change in the input session. This
+ handles three cases: (1) changing focus from an element that doesn't require an input session to one that does,
+ (2) changing focus between elements that require input sessions, and (3) changing focus from an input session
+ that doesn't require an input session to one that doesn't.
+
2019-01-22 David Kilzer <ddkil...@apple.com>
check-webkit-style reports false-positive whitespace/init warning in C++ initialization parameters
Modified: trunk/Tools/TestWebKitAPI/Tests/ios/WKWebViewAutofillTests.mm (240300 => 240301)
--- trunk/Tools/TestWebKitAPI/Tests/ios/WKWebViewAutofillTests.mm 2019-01-22 23:08:36 UTC (rev 240300)
+++ trunk/Tools/TestWebKitAPI/Tests/ios/WKWebViewAutofillTests.mm 2019-01-22 23:21:45 UTC (rev 240301)
@@ -64,7 +64,6 @@
- (BOOL)textInputHasAutofillContext
{
- [self waitForNextPresentationUpdate];
NSURL *url = "" objectForKey:@"_WebViewURL"];
if (![url isKindOfClass:[NSURL class]])
return NO;
@@ -81,10 +80,10 @@
{
auto webView = adoptNS([[AutofillTestView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
[webView synchronouslyLoadHTMLString:@"<input id='user' type='email'><input id='password' type='password'>"];
- [webView stringByEvaluatingJavaScript:@"user.focus()"];
+ [webView evaluateJavaScriptAndWaitForInputSessionToChange:@"user.focus()"];
EXPECT_TRUE([webView textInputHasAutofillContext]);
- [webView stringByEvaluatingJavaScript:@"password.focus()"];
+ [webView evaluateJavaScriptAndWaitForInputSessionToChange:@"password.focus()"];
EXPECT_TRUE([webView textInputHasAutofillContext]);
auto credentialSuggestion = [UITextAutofillSuggestion autofillSuggestionWithUsername:@"frederik" password:@"famos"];
@@ -92,7 +91,7 @@
EXPECT_WK_STREQ("famos", [webView stringByEvaluatingJavaScript:@"password.value"]);
- [webView stringByEvaluatingJavaScript:@"document.activeElement.blur()"];
+ [webView evaluateJavaScriptAndWaitForInputSessionToChange:@"document.activeElement.blur()"];
EXPECT_FALSE([webView textInputHasAutofillContext]);
}
@@ -100,10 +99,10 @@
{
auto webView = adoptNS([[AutofillTestView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
[webView synchronouslyLoadHTMLString:@"<input id='user' type='email'><input type='radio' name='radio_button' value='radio'><input id='password' type='password'>"];
- [webView stringByEvaluatingJavaScript:@"user.focus()"];
+ [webView evaluateJavaScriptAndWaitForInputSessionToChange:@"user.focus()"];
EXPECT_TRUE([webView textInputHasAutofillContext]);
- [webView stringByEvaluatingJavaScript:@"password.focus()"];
+ [webView evaluateJavaScriptAndWaitForInputSessionToChange:@"password.focus()"];
EXPECT_TRUE([webView textInputHasAutofillContext]);
auto credentialSuggestion = [UITextAutofillSuggestion autofillSuggestionWithUsername:@"frederik" password:@"famos"];
@@ -112,7 +111,7 @@
EXPECT_WK_STREQ("frederik", [webView stringByEvaluatingJavaScript:@"user.value"]);
EXPECT_WK_STREQ("famos", [webView stringByEvaluatingJavaScript:@"password.value"]);
- [webView stringByEvaluatingJavaScript:@"document.activeElement.blur()"];
+ [webView evaluateJavaScriptAndWaitForInputSessionToChange:@"document.activeElement.blur()"];
EXPECT_FALSE([webView textInputHasAutofillContext]);
}
@@ -120,10 +119,10 @@
{
auto webView = adoptNS([[AutofillTestView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
[webView synchronouslyLoadHTMLString:@"<input id='text1' type='email'><input id='text2' type='text'>"];
- [webView stringByEvaluatingJavaScript:@"text1.focus()"];
+ [webView evaluateJavaScriptAndWaitForInputSessionToChange:@"text1.focus()"];
EXPECT_FALSE([webView textInputHasAutofillContext]);
- [webView stringByEvaluatingJavaScript:@"text2.focus()"];
+ [webView evaluateJavaScriptAndWaitForInputSessionToChange:@"text2.focus()"];
EXPECT_FALSE([webView textInputHasAutofillContext]);
}
@@ -131,7 +130,7 @@
{
auto webView = adoptNS([[AutofillTestView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
[webView synchronouslyLoadHTMLString:@"<input id='password' type='password'>"];
- [webView stringByEvaluatingJavaScript:@"password.focus()"];
+ [webView evaluateJavaScriptAndWaitForInputSessionToChange:@"password.focus()"];
EXPECT_TRUE([webView textInputHasAutofillContext]);
auto credentialSuggestion = [UITextAutofillSuggestion autofillSuggestionWithUsername:@"frederik" password:@"famos"];
@@ -139,7 +138,7 @@
EXPECT_WK_STREQ("famos", [webView stringByEvaluatingJavaScript:@"password.value"]);
- [webView stringByEvaluatingJavaScript:@"document.activeElement.blur()"];
+ [webView evaluateJavaScriptAndWaitForInputSessionToChange:@"document.activeElement.blur()"];
EXPECT_FALSE([webView textInputHasAutofillContext]);
}
@@ -147,7 +146,7 @@
{
auto webView = adoptNS([[AutofillTestView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
[webView synchronouslyLoadHTMLString:@"<input id='textfield' type='text'>"];
- [webView stringByEvaluatingJavaScript:@"textfield.focus()"];
+ [webView evaluateJavaScriptAndWaitForInputSessionToChange:@"textfield.focus()"];
EXPECT_FALSE([webView textInputHasAutofillContext]);
}
@@ -155,13 +154,13 @@
{
auto webView = adoptNS([[AutofillTestView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
[webView synchronouslyLoadHTMLString:@"<input id='user' type='email'><input id='password' type='password'><input id='confirm_password' type='password'>"];
- [webView stringByEvaluatingJavaScript:@"user.focus()"];
+ [webView evaluateJavaScriptAndWaitForInputSessionToChange:@"user.focus()"];
EXPECT_FALSE([webView textInputHasAutofillContext]);
- [webView stringByEvaluatingJavaScript:@"password.focus()"];
+ [webView evaluateJavaScriptAndWaitForInputSessionToChange:@"password.focus()"];
EXPECT_FALSE([webView textInputHasAutofillContext]);
- [webView stringByEvaluatingJavaScript:@"confirm_password.focus()"];
+ [webView evaluateJavaScriptAndWaitForInputSessionToChange:@"confirm_password.focus()"];
EXPECT_FALSE([webView textInputHasAutofillContext]);
}
@@ -174,12 +173,15 @@
{
ClassMethodSwizzler swizzler([UIKeyboard class], @selector(isInHardwareKeyboardMode), reinterpret_cast<IMP>(overrideIsInHardwareKeyboardMode));
+ bool done = false;
auto webView = adoptNS([[AutofillTestView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
- [(TestInputDelegate *)[webView _inputDelegate] setFocusStartsInputSessionPolicyHandler:[] (WKWebView *, id <_WKFocusedElementInfo>) -> _WKFocusStartsInputSessionPolicy {
+ [(TestInputDelegate *)[webView _inputDelegate] setFocusStartsInputSessionPolicyHandler:[&done] (WKWebView *, id <_WKFocusedElementInfo>) -> _WKFocusStartsInputSessionPolicy {
+ done = true;
return _WKFocusStartsInputSessionPolicyAuto;
}];
[webView synchronouslyLoadHTMLString:@"<input id='user' type='email'><input id='password' type='password'>"];
[webView stringByEvaluatingJavaScript:@"user.focus()"];
+ Util::run(&done);
EXPECT_FALSE([webView textInputHasAutofillContext]);
}
Modified: trunk/Tools/TestWebKitAPI/cocoa/TestWKWebView.h (240300 => 240301)
--- trunk/Tools/TestWebKitAPI/cocoa/TestWKWebView.h 2019-01-22 23:08:36 UTC (rev 240300)
+++ trunk/Tools/TestWebKitAPI/cocoa/TestWKWebView.h 2019-01-22 23:21:45 UTC (rev 240301)
@@ -87,6 +87,7 @@
@property (nonatomic, readonly) CGRect caretViewRectInContentCoordinates;
@property (nonatomic, readonly) NSArray<NSValue *> *selectionViewRectsInContentCoordinates;
- (_WKActivatedElementInfo *)activatedElementAtPosition:(CGPoint)position;
+- (void)evaluateJavaScriptAndWaitForInputSessionToChange:(NSString *)script;
@end
#endif
Modified: trunk/Tools/TestWebKitAPI/cocoa/TestWKWebView.mm (240300 => 240301)
--- trunk/Tools/TestWebKitAPI/cocoa/TestWKWebView.mm 2019-01-22 23:08:36 UTC (rev 240300)
+++ trunk/Tools/TestWebKitAPI/cocoa/TestWKWebView.mm 2019-01-22 23:21:45 UTC (rev 240301)
@@ -249,11 +249,23 @@
@end
+#if PLATFORM(IOS_FAMILY)
+
+using InputSessionChangeCount = NSUInteger;
+static InputSessionChangeCount nextInputSessionChangeCount()
+{
+ static InputSessionChangeCount gInputSessionChangeCount = 0;
+ return ++gInputSessionChangeCount;
+}
+
+#endif
+
@implementation TestWKWebView {
RetainPtr<TestWKWebViewHostWindow> _hostWindow;
RetainPtr<TestMessageHandler> _testHandler;
#if PLATFORM(IOS_FAMILY)
std::unique_ptr<ClassMethodSwizzler> _sharedCalloutBarSwizzler;
+ InputSessionChangeCount _inputSessionChangeCount;
#endif
}
@@ -289,6 +301,7 @@
#if PLATFORM(IOS_FAMILY)
// FIXME: Remove this workaround once <https://webkit.org/b/175204> is fixed.
_sharedCalloutBarSwizzler = std::make_unique<ClassMethodSwizzler>([UICalloutBar class], @selector(sharedCalloutBar), reinterpret_cast<IMP>(suppressUICalloutBar));
+ _inputSessionChangeCount = 0;
#endif
return self;
@@ -409,6 +422,20 @@
[self evaluateJavaScript:@"getSelection().collapseToEnd()" completionHandler:nil];
}
+#if PLATFORM(IOS_FAMILY)
+
+- (void)didStartFormControlInteraction
+{
+ _inputSessionChangeCount = nextInputSessionChangeCount();
+}
+
+- (void)didEndFormControlInteraction
+{
+ _inputSessionChangeCount = 0;
+}
+
+#endif // PLATFORM(IOS_FAMILY)
+
@end
#if PLATFORM(IOS_FAMILY)
@@ -415,6 +442,26 @@
@implementation TestWKWebView (IOSOnly)
+- (void)evaluateJavaScriptAndWaitForInputSessionToChange:(NSString *)script
+{
+ auto initialChangeCount = _inputSessionChangeCount;
+ BOOL hasEmittedWarning = NO;
+ NSTimeInterval secondsToWaitUntilWarning = 2;
+ NSTimeInterval startTime = [NSDate timeIntervalSinceReferenceDate];
+
+ [self objectByEvaluatingJavaScript:script];
+ while ([[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantPast]]) {
+ if (_inputSessionChangeCount != initialChangeCount)
+ break;
+
+ if (hasEmittedWarning || startTime + secondsToWaitUntilWarning >= [NSDate timeIntervalSinceReferenceDate])
+ continue;
+
+ NSLog(@"Warning: expecting input session change count to differ from %tu", initialChangeCount);
+ hasEmittedWarning = YES;
+ }
+}
+
- (UIView <UITextInputPrivate, UITextInputMultiDocument> *)textInputContentView
{
return (UIView <UITextInputPrivate, UITextInputMultiDocument> *)[self valueForKey:@"_currentContentView"];