Title: [212507] trunk
Revision
212507
Author
wenson_hs...@apple.com
Date
2017-02-16 17:01:36 -0800 (Thu, 16 Feb 2017)

Log Message

[WK2] Add additional test infrastructure and unit tests for data interaction
https://bugs.webkit.org/show_bug.cgi?id=168439
<rdar://problem/30557942>

Reviewed by Tim Horton.

Source/WebKit2:

Adds two new _WKTestingDelegate protocol methods that are fired when a 'start data interaction' request has been
sent to the web process, and when a response has been received. See Tools/ChangeLog for more details.

* UIProcess/API/Cocoa/_WKTestingDelegate.h:

Tools:

Adds test support for additional data interaction scenarios that we currently cannot test, and also adds 7 new
test cases to DataInteractionTests. Most of the changes here refactor and augment DataInteractionSimulator to
support data interaction from  See per-method descriptions below for more details.

* Configurations/TestWebKitAPI.xcconfig:

Add MobileCoreServices to the list of additional frameworks to link against on iOS.

* TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:

Add a new build phase that copies additional resources from WebKitAdditions/Resources/TestWebKitAPI and dumps
them into TestWebKitAPI.resources/ in the build directory, if the WebKitAdditions folder exists.

* TestWebKitAPI/Tests/ios/DataInteractionTests.mm:
(-[TestWKWebView editorContainsImageElement]):
(-[TestWKWebView editorValue]):

New helper methods for querying information from the "editor" element in a test page.

(TestWebKitAPI::TEST):
(TestWebKitAPI::runTestsExpectingToObserveEvents): Deleted.

Moves logic for capturing events during a simulated data interaction run from the test file to
DataInteractionSimulator. See -[DataInteractionSimulator observedEventNames].

* TestWebKitAPI/cocoa/TestWKWebView.h:
* TestWebKitAPI/cocoa/TestWKWebView.mm:
(-[TestMessageHandler removeMessage:]):
(-[TestWKWebView clearMessageHandlers:]):

Add the ability to clear message handlers from the TestWKWebView.

* TestWebKitAPI/ios/DataInteractionSimulator.h:
* TestWebKitAPI/ios/DataInteractionSimulator.mm:
(dataInteractionEventNames):
(-[DataInteractionSimulator initWithWebView:]):
(-[DataInteractionSimulator _resetSimulatedState]):

Moves logic to clear test harness state from any previous runs into a helper. Called at the beginning when
simulating data interaction.

(-[DataInteractionSimulator observedEventNames]):

Returns a list of the names of events relevant to data interaction that were observed over the course of the
most recent run.

(-[DataInteractionSimulator runFrom:to:]):

Changes -run to -runFrom:to:, which takes window-relative start and end locations. This allows the test harness
to run the same data interaction for multiple simulated gestures.

(-[DataInteractionSimulator _advanceProgress]):
(-[DataInteractionSimulator _finishDataInteraction]):
(-[DataInteractionSimulator externalItemProvider]):
(-[DataInteractionSimulator setExternalItemProvider:]):

Adds the -externalItemProvider property to DataInteractionSimulator. Setting this skips the gesture recognition
phase of a test run.

(-[DataInteractionSimulator webViewDidPerformDataInteractionControllerOperation:]):
(-[DataInteractionSimulator webView:beginDataInteractionWithSourceIndex:gestureRecognizer:]):
(-[DataInteractionSimulator webViewDidSendDataInteractionStartRequest:]):
(-[DataInteractionSimulator webView:didReceiveDataInteractionStartResponse:]):

While a request to start data interaction is in flight, put the remainder of the test on hold until the web
process returns. Then continue the test by scheduling a progress advance call. This addresses a race condition
wherein the the web process might take longer than usual to process the request to start data interaction, and
in the meantime, DataInteractionSimulator would end up completing the rest of the test before a response from
the web process is received, which then causes no simulated delegate methods to be fired.

(-[DataInteractionSimulator initWithWebView:startLocation:endLocation:]): Deleted.
(-[DataInteractionSimulator run]): Deleted.

Modified Paths

Diff

Modified: trunk/Source/WebKit2/ChangeLog (212506 => 212507)


--- trunk/Source/WebKit2/ChangeLog	2017-02-17 00:57:05 UTC (rev 212506)
+++ trunk/Source/WebKit2/ChangeLog	2017-02-17 01:01:36 UTC (rev 212507)
@@ -1,3 +1,16 @@
+2017-02-16  Wenson Hsieh  <wenson_hs...@apple.com>
+
+        [WK2] Add additional test infrastructure and unit tests for data interaction
+        https://bugs.webkit.org/show_bug.cgi?id=168439
+        <rdar://problem/30557942>
+
+        Reviewed by Tim Horton.
+
+        Adds two new _WKTestingDelegate protocol methods that are fired when a 'start data interaction' request has been
+        sent to the web process, and when a response has been received. See Tools/ChangeLog for more details.
+
+        * UIProcess/API/Cocoa/_WKTestingDelegate.h:
+
 2017-02-16  Aakash Jain  <aakash_j...@apple.com>
 
         Remove unused method WKBundlePageCopyContextMenuItemTitle

Modified: trunk/Source/WebKit2/UIProcess/API/Cocoa/_WKTestingDelegate.h (212506 => 212507)


--- trunk/Source/WebKit2/UIProcess/API/Cocoa/_WKTestingDelegate.h	2017-02-17 00:57:05 UTC (rev 212506)
+++ trunk/Source/WebKit2/UIProcess/API/Cocoa/_WKTestingDelegate.h	2017-02-17 01:01:36 UTC (rev 212507)
@@ -43,6 +43,8 @@
 
 #if TARGET_OS_IPHONE
 @property (nonatomic, readonly) UILongPressGestureRecognizer *dataInteractionGestureRecognizer;
+- (void)webViewDidSendDataInteractionStartRequest:(WKWebView *)webView;
+- (void)webView:(WKWebView *)webView didReceiveDataInteractionStartResponse:(BOOL)started;
 - (void)webViewDidPerformDataInteractionControllerOperation:(WKWebView *)webView;
 - (void)webView:(WKWebView *)webView beginDataInteractionWithSourceIndex:(NSInteger)sourceIndex gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer;
 #endif // TARGET_OS_PHONE

Modified: trunk/Tools/ChangeLog (212506 => 212507)


--- trunk/Tools/ChangeLog	2017-02-17 00:57:05 UTC (rev 212506)
+++ trunk/Tools/ChangeLog	2017-02-17 01:01:36 UTC (rev 212507)
@@ -1,5 +1,86 @@
 2017-02-16  Wenson Hsieh  <wenson_hs...@apple.com>
 
+        [WK2] Add additional test infrastructure and unit tests for data interaction
+        https://bugs.webkit.org/show_bug.cgi?id=168439
+        <rdar://problem/30557942>
+
+        Reviewed by Tim Horton.
+
+        Adds test support for additional data interaction scenarios that we currently cannot test, and also adds 7 new
+        test cases to DataInteractionTests. Most of the changes here refactor and augment DataInteractionSimulator to
+        support data interaction from  See per-method descriptions below for more details.
+
+        * Configurations/TestWebKitAPI.xcconfig:
+
+        Add MobileCoreServices to the list of additional frameworks to link against on iOS.
+
+        * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+
+        Add a new build phase that copies additional resources from WebKitAdditions/Resources/TestWebKitAPI and dumps
+        them into TestWebKitAPI.resources/ in the build directory, if the WebKitAdditions folder exists.
+
+        * TestWebKitAPI/Tests/ios/DataInteractionTests.mm:
+        (-[TestWKWebView editorContainsImageElement]):
+        (-[TestWKWebView editorValue]):
+
+        New helper methods for querying information from the "editor" element in a test page.
+
+        (TestWebKitAPI::TEST):
+        (TestWebKitAPI::runTestsExpectingToObserveEvents): Deleted.
+
+        Moves logic for capturing events during a simulated data interaction run from the test file to
+        DataInteractionSimulator. See -[DataInteractionSimulator observedEventNames].
+
+        * TestWebKitAPI/cocoa/TestWKWebView.h:
+        * TestWebKitAPI/cocoa/TestWKWebView.mm:
+        (-[TestMessageHandler removeMessage:]):
+        (-[TestWKWebView clearMessageHandlers:]):
+
+        Add the ability to clear message handlers from the TestWKWebView.
+
+        * TestWebKitAPI/ios/DataInteractionSimulator.h:
+        * TestWebKitAPI/ios/DataInteractionSimulator.mm:
+        (dataInteractionEventNames):
+        (-[DataInteractionSimulator initWithWebView:]):
+        (-[DataInteractionSimulator _resetSimulatedState]):
+
+        Moves logic to clear test harness state from any previous runs into a helper. Called at the beginning when
+        simulating data interaction.
+
+        (-[DataInteractionSimulator observedEventNames]):
+
+        Returns a list of the names of events relevant to data interaction that were observed over the course of the
+        most recent run.
+
+        (-[DataInteractionSimulator runFrom:to:]):
+
+        Changes -run to -runFrom:to:, which takes window-relative start and end locations. This allows the test harness
+        to run the same data interaction for multiple simulated gestures.
+
+        (-[DataInteractionSimulator _advanceProgress]):
+        (-[DataInteractionSimulator _finishDataInteraction]):
+        (-[DataInteractionSimulator externalItemProvider]):
+        (-[DataInteractionSimulator setExternalItemProvider:]):
+
+        Adds the -externalItemProvider property to DataInteractionSimulator. Setting this skips the gesture recognition
+        phase of a test run.
+
+        (-[DataInteractionSimulator webViewDidPerformDataInteractionControllerOperation:]):
+        (-[DataInteractionSimulator webView:beginDataInteractionWithSourceIndex:gestureRecognizer:]):
+        (-[DataInteractionSimulator webViewDidSendDataInteractionStartRequest:]):
+        (-[DataInteractionSimulator webView:didReceiveDataInteractionStartResponse:]):
+
+        While a request to start data interaction is in flight, put the remainder of the test on hold until the web
+        process returns. Then continue the test by scheduling a progress advance call. This addresses a race condition
+        wherein the the web process might take longer than usual to process the request to start data interaction, and
+        in the meantime, DataInteractionSimulator would end up completing the rest of the test before a response from
+        the web process is received, which then causes no simulated delegate methods to be fired.
+
+        (-[DataInteractionSimulator initWithWebView:startLocation:endLocation:]): Deleted.
+        (-[DataInteractionSimulator run]): Deleted.
+
+2017-02-16  Wenson Hsieh  <wenson_hs...@apple.com>
+
         Remove unused test pages in TestWebKitAPI
         https://bugs.webkit.org/show_bug.cgi?id=168462
 

Modified: trunk/Tools/TestWebKitAPI/Configurations/TestWebKitAPI.xcconfig (212506 => 212507)


--- trunk/Tools/TestWebKitAPI/Configurations/TestWebKitAPI.xcconfig	2017-02-17 00:57:05 UTC (rev 212506)
+++ trunk/Tools/TestWebKitAPI/Configurations/TestWebKitAPI.xcconfig	2017-02-17 01:01:36 UTC (rev 212507)
@@ -32,6 +32,6 @@
 OTHER_LDFLAGS_PLATFORM[sdk=macosx*] = -framework Cocoa -framework Carbon;
 
 // FIXME: This should not be built on iOS. Instead we should create and use a TestWebKitAPI application.
-OTHER_LDFLAGS_PLATFORM[sdk=iphone*] = -framework WebCore -framework CoreGraphics -framework UIKit;
+OTHER_LDFLAGS_PLATFORM[sdk=iphone*] = -framework WebCore -framework CoreGraphics -framework UIKit -framework MobileCoreServices;
 
 LD_RUNPATH_SEARCH_PATHS = "@loader_path";

Modified: trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj (212506 => 212507)


--- trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj	2017-02-17 00:57:05 UTC (rev 212506)
+++ trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj	2017-02-17 01:01:36 UTC (rev 212507)
@@ -2391,6 +2391,7 @@
 				8DD76F9B0486AA7600D96B5E /* Frameworks */,
 				8DD76F9E0486AA7600D96B5E /* CopyFiles */,
 				BCB9F4FB112384C000A137E0 /* Copy Resources */,
+				F471CB8B1E565C0F0028055C /* ShellScript */,
 			);
 			buildRules = (
 			);
@@ -2501,6 +2502,23 @@
 		};
 /* End PBXResourcesBuildPhase section */
 
+/* Begin PBXShellScriptBuildPhase section */
+		F471CB8B1E565C0F0028055C /* ShellScript */ = {
+			isa = PBXShellScriptBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			inputPaths = (
+			);
+			outputPaths = (
+			);
+			name = "Copy additional resources";
+			runOnlyForDeploymentPostprocessing = 0;
+			shellPath = /bin/sh;
+			shellScript = "ADDITIONAL_RESOURCES_PATH=\"usr/local/include/WebKitAdditions/Resources/TestWebKitAPI\"\nDESTINATION_PATH=\"$TARGET_BUILD_DIR/TestWebKitAPI.resources\"\nif [ -d $TARGET_BUILD_DIR/$ADDITIONAL_RESOURCES_PATH ]; then\n    cp $TARGET_BUILD_DIR/$ADDITIONAL_RESOURCES_PATH/* $DESTINATION_PATH\nelif [ -d $SDKROOT/$ADDITIONAL_RESOURCES_PATH ]; then\n    cp $SDKROOT/$ADDITIONAL_RESOURCES_PATH/* $DESTINATION_PATH\nfi";
+		};
+/* End PBXShellScriptBuildPhase section */
+
 /* Begin PBXSourcesBuildPhase section */
 		7C83DE961D0A590C00FEBCF3 /* Sources */ = {
 			isa = PBXSourcesBuildPhase;

Modified: trunk/Tools/TestWebKitAPI/Tests/ios/DataInteractionTests.mm (212506 => 212507)


--- trunk/Tools/TestWebKitAPI/Tests/ios/DataInteractionTests.mm	2017-02-17 00:57:05 UTC (rev 212506)
+++ trunk/Tools/TestWebKitAPI/Tests/ios/DataInteractionTests.mm	2017-02-17 01:01:36 UTC (rev 212507)
@@ -30,91 +30,231 @@
 #import "DataInteractionSimulator.h"
 #import "PlatformUtilities.h"
 #import "TestWKWebView.h"
+#import <MobileCoreServices/MobileCoreServices.h>
+#import <UIKit/UIItemProvider_Private.h>
 
-namespace TestWebKitAPI {
+@implementation TestWKWebView (DataInteractionTests)
 
-static void runTestsExpectingToObserveEvents(TestWKWebView *webView, NSArray *eventNamesToObserve, dispatch_block_t test)
+- (BOOL)editorContainsImageElement
 {
-    NSMutableSet *observedEvents = [NSMutableSet set];
-    for (NSString *eventName in eventNamesToObserve) {
-        [webView performAfterReceivingMessage:eventName action:^() {
-            [observedEvents addObject:eventName];
-        }];
-    }
+    return [self stringByEvaluatingJavaScript:@"!!editor.querySelector('img')"].boolValue;
+}
 
-    test();
-
-    for (NSString *eventName in eventNamesToObserve)
-        EXPECT_TRUE([observedEvents containsObject:eventName]);
+- (NSString *)editorValue
+{
+    return [self stringByEvaluatingJavaScript:@"editor.value"];
 }
 
+@end
+
+namespace TestWebKitAPI {
+
 TEST(DataInteractionTests, ImageToContentEditable)
 {
     RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
-    runTestsExpectingToObserveEvents(webView.get(), @[ DataInteractionEnterEventName, DataInteractionOverEventName, DataInteractionPerformOperationEventName ], ^() {
-        [webView synchronouslyLoadTestPageNamed:@"image-and-contenteditable"];
+    [webView synchronouslyLoadTestPageNamed:@"image-and-contenteditable"];
 
-        RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get() startLocation:CGPointMake(100, 100) endLocation:CGPointMake(100, 300)]);
-        [dataInteractionSimulator run];
+    RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
+    [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
 
-        EXPECT_TRUE([webView stringByEvaluatingJavaScript:@"!!editor.querySelector('img')"].boolValue);
-    });
+    EXPECT_TRUE([webView editorContainsImageElement]);
+
+    NSArray *observedEventNames = [dataInteractionSimulator observedEventNames];
+    EXPECT_TRUE([observedEventNames containsObject:DataInteractionEnterEventName]);
+    EXPECT_TRUE([observedEventNames containsObject:DataInteractionOverEventName]);
+    EXPECT_TRUE([observedEventNames containsObject:DataInteractionPerformOperationEventName]);
 }
 
 TEST(DataInteractionTests, ImageToTextarea)
 {
     RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
-    runTestsExpectingToObserveEvents(webView.get(), @[ DataInteractionEnterEventName, DataInteractionOverEventName, DataInteractionPerformOperationEventName ], ^() {
-        [webView synchronouslyLoadTestPageNamed:@"image-and-textarea"];
+    [webView synchronouslyLoadTestPageNamed:@"image-and-textarea"];
 
-        RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get() startLocation:CGPointMake(100, 100) endLocation:CGPointMake(100, 300)]);
-        [dataInteractionSimulator run];
+    RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
+    [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
 
-        NSURL *imageURL = [NSURL fileURLWithPath:[webView stringByEvaluatingJavaScript:@"editor.value"]];
-        EXPECT_WK_STREQ("icon.png", imageURL.lastPathComponent);
-    });
+    NSURL *imageURL = [NSURL fileURLWithPath:[webView editorValue]];
+    EXPECT_WK_STREQ("icon.png", imageURL.lastPathComponent);
+    EXPECT_TRUE([dataInteractionSimulator didTryToBeginDataInteraction]);
+
+    NSArray *observedEventNames = [dataInteractionSimulator observedEventNames];
+    EXPECT_TRUE([observedEventNames containsObject:DataInteractionEnterEventName]);
+    EXPECT_TRUE([observedEventNames containsObject:DataInteractionOverEventName]);
+    EXPECT_TRUE([observedEventNames containsObject:DataInteractionPerformOperationEventName]);
 }
 
 TEST(DataInteractionTests, ContentEditableToContentEditable)
 {
     RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
-    runTestsExpectingToObserveEvents(webView.get(), @[ DataInteractionEnterEventName, DataInteractionOverEventName, DataInteractionPerformOperationEventName ], ^() {
-        [webView synchronouslyLoadTestPageNamed:@"autofocus-contenteditable"];
+    [webView synchronouslyLoadTestPageNamed:@"autofocus-contenteditable"];
 
-        RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get() startLocation:CGPointMake(100, 100) endLocation:CGPointMake(100, 300)]);
-        [dataInteractionSimulator run];
+    RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
+    [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
 
-        EXPECT_EQ([webView stringByEvaluatingJavaScript:@"source.textContent"].length, 0UL);
-        EXPECT_WK_STREQ("Hello world", [webView stringByEvaluatingJavaScript:@"editor.textContent"].UTF8String);
-    });
+    EXPECT_EQ([webView stringByEvaluatingJavaScript:@"source.textContent"].length, 0UL);
+    EXPECT_WK_STREQ("Hello world", [webView stringByEvaluatingJavaScript:@"editor.textContent"].UTF8String);
+    EXPECT_TRUE([dataInteractionSimulator didTryToBeginDataInteraction]);
+
+    NSArray *observedEventNames = [dataInteractionSimulator observedEventNames];
+    EXPECT_TRUE([observedEventNames containsObject:DataInteractionEnterEventName]);
+    EXPECT_TRUE([observedEventNames containsObject:DataInteractionOverEventName]);
+    EXPECT_TRUE([observedEventNames containsObject:DataInteractionPerformOperationEventName]);
 }
 
+TEST(DataInteractionTests, ContentEditableToTextarea)
+{
+    RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
+    [webView synchronouslyLoadTestPageNamed:@"contenteditable-and-textarea"];
+
+    RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
+    [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
+
+    EXPECT_EQ([webView stringByEvaluatingJavaScript:@"source.textContent"].length, 0UL);
+    EXPECT_WK_STREQ("Hello world", [webView editorValue].UTF8String);
+    EXPECT_TRUE([dataInteractionSimulator didTryToBeginDataInteraction]);
+
+    NSArray *observedEventNames = [dataInteractionSimulator observedEventNames];
+    EXPECT_TRUE([observedEventNames containsObject:DataInteractionEnterEventName]);
+    EXPECT_TRUE([observedEventNames containsObject:DataInteractionOverEventName]);
+    EXPECT_TRUE([observedEventNames containsObject:DataInteractionPerformOperationEventName]);
+}
+
 TEST(DataInteractionTests, LinkToInput)
 {
     RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
-    runTestsExpectingToObserveEvents(webView.get(), @[ DataInteractionEnterEventName, DataInteractionOverEventName, DataInteractionPerformOperationEventName ], ^() {
-        [webView synchronouslyLoadTestPageNamed:@"link-and-input"];
+    [webView synchronouslyLoadTestPageNamed:@"link-and-input"];
 
-        RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get() startLocation:CGPointMake(100, 100) endLocation:CGPointMake(100, 300)]);
-        [dataInteractionSimulator run];
+    RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
+    [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
 
-        EXPECT_WK_STREQ("https://www.daringfireball.net/", [webView stringByEvaluatingJavaScript:@"editor.value"].UTF8String);
-    });
+    EXPECT_WK_STREQ("https://www.daringfireball.net/", [webView editorValue].UTF8String);
+    EXPECT_TRUE([dataInteractionSimulator didTryToBeginDataInteraction]);
+
+    NSArray *observedEventNames = [dataInteractionSimulator observedEventNames];
+    EXPECT_TRUE([observedEventNames containsObject:DataInteractionEnterEventName]);
+    EXPECT_TRUE([observedEventNames containsObject:DataInteractionOverEventName]);
+    EXPECT_TRUE([observedEventNames containsObject:DataInteractionPerformOperationEventName]);
 }
 
 TEST(DataInteractionTests, BackgroundImageLinkToInput)
 {
     RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
-    runTestsExpectingToObserveEvents(webView.get(), @[ DataInteractionEnterEventName, DataInteractionOverEventName, DataInteractionPerformOperationEventName ], ^() {
-        [webView synchronouslyLoadTestPageNamed:@"background-image-link-and-input"];
+    [webView synchronouslyLoadTestPageNamed:@"background-image-link-and-input"];
 
-        RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get() startLocation:CGPointMake(100, 100) endLocation:CGPointMake(100, 300)]);
-        [dataInteractionSimulator run];
+    RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
+    [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
 
-        EXPECT_WK_STREQ("https://www.daringfireball.net/", [webView stringByEvaluatingJavaScript:@"editor.value"].UTF8String);
-    });
+    EXPECT_WK_STREQ("https://www.daringfireball.net/", [webView editorValue].UTF8String);
+    EXPECT_TRUE([dataInteractionSimulator didTryToBeginDataInteraction]);
+
+    NSArray *observedEventNames = [dataInteractionSimulator observedEventNames];
+    EXPECT_TRUE([observedEventNames containsObject:DataInteractionEnterEventName]);
+    EXPECT_TRUE([observedEventNames containsObject:DataInteractionOverEventName]);
+    EXPECT_TRUE([observedEventNames containsObject:DataInteractionPerformOperationEventName]);
 }
 
+TEST(DataInteractionTests, CanPreventStart)
+{
+    RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
+    [webView synchronouslyLoadTestPageNamed:@"prevent-start"];
+
+    RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
+    [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
+
+    EXPECT_FALSE([webView editorContainsImageElement]);
+    EXPECT_FALSE([dataInteractionSimulator didTryToBeginDataInteraction]);
+
+    NSArray *observedEventNames = [dataInteractionSimulator observedEventNames];
+    EXPECT_FALSE([observedEventNames containsObject:DataInteractionEnterEventName]);
+    EXPECT_FALSE([observedEventNames containsObject:DataInteractionOverEventName]);
+}
+
+TEST(DataInteractionTests, CanPreventOperation)
+{
+    RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
+    [webView synchronouslyLoadTestPageNamed:@"prevent-operation"];
+
+    RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
+    [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
+
+    EXPECT_FALSE([webView editorContainsImageElement]);
+    EXPECT_TRUE([dataInteractionSimulator didTryToBeginDataInteraction]);
+
+    NSArray *observedEventNames = [dataInteractionSimulator observedEventNames];
+    EXPECT_TRUE([observedEventNames containsObject:DataInteractionEnterEventName]);
+    EXPECT_TRUE([observedEventNames containsObject:DataInteractionOverEventName]);
+}
+
+TEST(DataInteractionTests, EnterAndLeaveEvents)
+{
+    RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
+    [webView synchronouslyLoadTestPageNamed:@"link-and-input"];
+
+    RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
+    [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 450)];
+
+    EXPECT_WK_STREQ("", [webView editorValue].UTF8String);
+    EXPECT_TRUE([dataInteractionSimulator didTryToBeginDataInteraction]);
+
+    NSArray *observedEventNames = [dataInteractionSimulator observedEventNames];
+    EXPECT_TRUE([observedEventNames containsObject:DataInteractionEnterEventName]);
+    EXPECT_TRUE([observedEventNames containsObject:DataInteractionOverEventName]);
+    EXPECT_TRUE([observedEventNames containsObject:DataInteractionLeaveEventName]);
+    EXPECT_FALSE([observedEventNames containsObject:DataInteractionPerformOperationEventName]);
+}
+
+TEST(DataInteractionTests, HandlesDataInteractionFailureGracefully)
+{
+    RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
+    [webView synchronouslyLoadTestPageNamed:@"link-and-input"];
+
+    RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
+    [dataInteractionSimulator setForceRequestToFail:YES];
+    [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
+    EXPECT_WK_STREQ("", [webView editorValue].UTF8String);
+
+    // Before r212266, starting a subsequent gesture would have caused a debug assertion in the web process.
+    [dataInteractionSimulator setForceRequestToFail:NO];
+    [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
+    EXPECT_WK_STREQ("https://www.daringfireball.net/", [webView editorValue].UTF8String);
+}
+
+TEST(DataInteractionTests, ExternalSourceUTF8PlainTextOnly)
+{
+    RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
+    [webView synchronouslyLoadTestPageNamed:@"autofocus-contenteditable"];
+
+    NSString *textPayload = @"Ceci n'est pas une string";
+    RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
+    RetainPtr<UIItemProvider> simulatedItemProvider = adoptNS([[UIItemProvider alloc] init]);
+    [simulatedItemProvider registerDataRepresentationForTypeIdentifier:(__bridge NSString *)kUTTypeUTF8PlainText options:nil loadHandler:^NSProgress *(UIItemProviderDataLoadCompletionBlock completionBlock)
+    {
+        completionBlock([textPayload dataUsingEncoding:NSUTF8StringEncoding], nil);
+        return [NSProgress discreteProgressWithTotalUnitCount:100];
+    }];
+    [dataInteractionSimulator setExternalItemProvider:simulatedItemProvider.get()];
+    [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
+    EXPECT_WK_STREQ(textPayload.UTF8String, [webView stringByEvaluatingJavaScript:@"editor.textContent"].UTF8String);
+}
+
+TEST(DataInteractionTests, ExternalSourceJPEGOnly)
+{
+    RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
+    [webView synchronouslyLoadTestPageNamed:@"autofocus-contenteditable"];
+
+    UIImage *testImage = [UIImage imageNamed:@"TestWebKitAPI.resources/icon.png"];
+    RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
+    RetainPtr<UIItemProvider> simulatedItemProvider = adoptNS([[UIItemProvider alloc] init]);
+    [simulatedItemProvider registerDataRepresentationForTypeIdentifier:(__bridge NSString *)kUTTypeJPEG options:nil loadHandler:^NSProgress *(UIItemProviderDataLoadCompletionBlock completionBlock)
+    {
+        completionBlock(UIImageJPEGRepresentation(testImage, 0.5), nil);
+        return [NSProgress discreteProgressWithTotalUnitCount:100];
+    }];
+    [dataInteractionSimulator setExternalItemProvider:simulatedItemProvider.get()];
+    [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
+    EXPECT_TRUE([webView editorContainsImageElement]);
+}
+
 } // namespace TestWebKitAPI
 
 #endif // ENABLE(DATA_INTERACTION)

Modified: trunk/Tools/TestWebKitAPI/cocoa/TestWKWebView.h (212506 => 212507)


--- trunk/Tools/TestWebKitAPI/cocoa/TestWKWebView.h	2017-02-17 00:57:05 UTC (rev 212506)
+++ trunk/Tools/TestWebKitAPI/cocoa/TestWKWebView.h	2017-02-17 01:01:36 UTC (rev 212507)
@@ -32,6 +32,7 @@
 @end
 
 @interface TestWKWebView : WKWebView
+- (void)clearMessageHandlers:(NSArray *)messageNames;
 - (void)performAfterReceivingMessage:(NSString *)message action:(dispatch_block_t)action;
 - (void)loadTestPageNamed:(NSString *)pageName;
 - (void)synchronouslyLoadTestPageNamed:(NSString *)pageName;

Modified: trunk/Tools/TestWebKitAPI/cocoa/TestWKWebView.mm (212506 => 212507)


--- trunk/Tools/TestWebKitAPI/cocoa/TestWKWebView.mm	2017-02-17 00:57:05 UTC (rev 212506)
+++ trunk/Tools/TestWebKitAPI/cocoa/TestWKWebView.mm	2017-02-17 01:01:36 UTC (rev 212507)
@@ -59,6 +59,11 @@
     _messageHandlers[message] = [handler copy];
 }
 
+- (void)removeMessage:(NSString *)message
+{
+    [_messageHandlers removeObjectForKey:message];
+}
+
 - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
 {
     dispatch_block_t handler = _messageHandlers[message.body];
@@ -187,6 +192,12 @@
 #endif
 }
 
+- (void)clearMessageHandlers:(NSArray *)messageNames
+{
+    for (NSString *messageName in messageNames)
+        [_testHandler removeMessage:messageName];
+}
+
 - (void)performAfterReceivingMessage:(NSString *)message action:(dispatch_block_t)action
 {
     if (!_testHandler) {

Modified: trunk/Tools/TestWebKitAPI/ios/DataInteractionSimulator.h (212506 => 212507)


--- trunk/Tools/TestWebKitAPI/ios/DataInteractionSimulator.h	2017-02-17 00:57:05 UTC (rev 212506)
+++ trunk/Tools/TestWebKitAPI/ios/DataInteractionSimulator.h	2017-02-17 01:01:36 UTC (rev 212507)
@@ -25,9 +25,9 @@
 
 #if ENABLE(DATA_INTERACTION)
 
+#import "TestWKWebView.h"
 #import <UIKit/UIItemProvider.h>
 #import <UIKit/UIKit.h>
-#import <WebKit/WebKit.h>
 #import <WebKit/_WKTestingDelegate.h>
 #import <wtf/BlockPtr.h>
 
@@ -37,6 +37,8 @@
 extern NSString * const DataInteractionEnterEventName;
 extern NSString * const DataInteractionOverEventName;
 extern NSString * const DataInteractionPerformOperationEventName;
+extern NSString * const DataInteractionLeaveEventName;
+extern NSString * const DataInteractionStartEventName;
 
 typedef NS_ENUM(NSInteger, DataInteractionPhase) {
     DataInteractionUnrecognized = 1,
@@ -46,20 +48,27 @@
 };
 
 @interface DataInteractionSimulator : NSObject<_WKTestingDelegate> {
-    RetainPtr<WKWebView> _webView;
+    RetainPtr<TestWKWebView> _webView;
     RetainPtr<MockLongPressGestureRecognizer> _gestureRecognizer;
     RetainPtr<MockDataInteractionInfo> _dataInteractionInfo;
+    RetainPtr<NSMutableArray> _observedEventNames;
+    RetainPtr<UIItemProvider> _externalItemProvider;
     CGPoint _startLocation;
     CGPoint _endLocation;
 
     double _gestureProgress;
-    bool _isDoneWithDataInteraction;
+    bool _isDoneWithCurrentRun;
     DataInteractionPhase _phase;
 }
 
-- (instancetype)initWithWebView:(WKWebView *)webView startLocation:(CGPoint)startLocation endLocation:(CGPoint)endLocation;
-- (void)run;
+- (instancetype)initWithWebView:(TestWKWebView *)webView;
+- (void)runFrom:(CGPoint)startLocation to:(CGPoint)endLocation;
 
+@property (nonatomic) BOOL forceRequestToFail;
+@property (nonatomic, strong) UIItemProvider *externalItemProvider;
+@property (nonatomic, readonly) BOOL didTryToBeginDataInteraction;
+@property (nonatomic, readonly) NSArray *observedEventNames;
+
 @end
 
 #endif // ENABLE(DATA_INTERACTION)

Modified: trunk/Tools/TestWebKitAPI/ios/DataInteractionSimulator.mm (212506 => 212507)


--- trunk/Tools/TestWebKitAPI/ios/DataInteractionSimulator.mm	2017-02-17 00:57:05 UTC (rev 212506)
+++ trunk/Tools/TestWebKitAPI/ios/DataInteractionSimulator.mm	2017-02-17 01:01:36 UTC (rev 212507)
@@ -80,17 +80,25 @@
 @end
 
 static double progressIncrementStep = 0.033;
-static double progressTimeStep = 0.03;
+static double progressTimeStep = 0.016;
 
+static NSArray *dataInteractionEventNames()
+{
+    static NSArray *eventNames = nil;
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^() {
+        eventNames = @[ DataInteractionEnterEventName, DataInteractionOverEventName, DataInteractionPerformOperationEventName, DataInteractionLeaveEventName, DataInteractionStartEventName ];
+    });
+    return eventNames;
+}
+
 @implementation DataInteractionSimulator
 
-- (instancetype)initWithWebView:(WKWebView *)webView startLocation:(CGPoint)startLocation endLocation:(CGPoint)endLocation
+- (instancetype)initWithWebView:(TestWKWebView *)webView
 {
     if (self = [super init]) {
         _webView = webView;
         _gestureRecognizer = adoptNS([[MockLongPressGestureRecognizer alloc] initWithWindow:webView.window]);
-        _startLocation = startLocation;
-        _endLocation = endLocation;
 
         [_gestureRecognizer setMockNumberOfTouches:0];
         [_webView _setTestingDelegate:self];
@@ -106,18 +114,47 @@
     [super dealloc];
 }
 
-- (void)run
+- (void)_resetSimulatedState
 {
     _gestureProgress = 0;
     _phase = DataInteractionUnrecognized;
-    _isDoneWithDataInteraction = NO;
+    _isDoneWithCurrentRun = false;
+    _didTryToBeginDataInteraction = NO;
+    _observedEventNames = adoptNS([[NSMutableArray alloc] init]);
+}
+
+- (NSArray *)observedEventNames
+{
+    return _observedEventNames.get();
+}
+
+- (void)runFrom:(CGPoint)startLocation to:(CGPoint)endLocation
+{
+    [self _resetSimulatedState];
+
+    RetainPtr<DataInteractionSimulator> strongSelf = self;
+    for (NSString *eventName in dataInteractionEventNames()) {
+        DataInteractionSimulator *weakSelf = strongSelf.get();
+        [weakSelf->_webView performAfterReceivingMessage:eventName action:^() {
+            [weakSelf->_observedEventNames addObject:eventName];
+        }];
+    }
+
+    _startLocation = startLocation;
+    _endLocation = endLocation;
     [_gestureRecognizer setMockNumberOfTouches:1];
 
-    [self _recognizeGestureAtLocation:_startLocation withState:UIGestureRecognizerStateBegan];
+    if (self.externalItemProvider) {
+        _phase = DataInteractionBegan;
+        _dataInteractionInfo = adoptNS([[MockDataInteractionInfo alloc] initWithProvider:self.externalItemProvider location:startLocation window:[_webView window]]);
+    } else
+        [self _recognizeGestureAtLocation:_startLocation withState:UIGestureRecognizerStateBegan];
+
     [self _scheduleAdvanceProgress];
 
-    TestWebKitAPI::Util::run(&_isDoneWithDataInteraction);
+    Util::run(&_isDoneWithCurrentRun);
     [_gestureRecognizer setMockNumberOfTouches:0];
+    [_webView clearMessageHandlers:dataInteractionEventNames()];
 }
 
 - (void)_advanceProgress
@@ -140,7 +177,6 @@
         [self _scheduleAdvanceProgress];
         break;
     case DataInteractionEntered:
-        [_dataInteractionInfo setMockLocationInWindow:self._currentLocation];
         [_webView _simulateDataInteractionUpdated:_dataInteractionInfo.get()];
         [self _scheduleAdvanceProgress];
         break;
@@ -151,6 +187,12 @@
 
 - (void)_finishDataInteraction
 {
+    if (_phase == DataInteractionUnrecognized) {
+        [self _recognizeGestureAtLocation:self._currentLocation withState:UIGestureRecognizerStateEnded];
+        _isDoneWithCurrentRun = true;
+        return;
+    }
+
     _phase = DataInteractionPerforming;
     [_webView _simulateDataInteractionPerformOperation:_dataInteractionInfo.get()];
     [_webView _simulateDataInteractionEnded:_dataInteractionInfo.get()];
@@ -177,6 +219,16 @@
     [_webView _simulateDataInteractionGestureRecognized];
 }
 
+- (UIItemProvider *)externalItemProvider
+{
+    return _externalItemProvider.get();
+}
+
+- (void)setExternalItemProvider:(UIItemProvider *)externalItemProvider
+{
+    _externalItemProvider = externalItemProvider;
+}
+
 #pragma mark - _WKTestingDelegate
 
 - (UILongPressGestureRecognizer *)dataInteractionGestureRecognizer
@@ -186,11 +238,18 @@
 
 - (void)webViewDidPerformDataInteractionControllerOperation:(WKWebView *)webView
 {
-    _isDoneWithDataInteraction = true;
+    _isDoneWithCurrentRun = true;
 }
 
 - (void)webView:(WKWebView *)webView beginDataInteractionWithSourceIndex:(NSInteger)sourceIndex gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
 {
+    _didTryToBeginDataInteraction = YES;
+
+    if (self.forceRequestToFail) {
+        [_webView _simulateFailedDataInteractionWithIndex:sourceIndex];
+        return;
+    }
+
     _phase = DataInteractionBegan;
 
     // End the data interaction gesture recognizer.
@@ -203,6 +262,20 @@
     [_webView _simulateWillBeginDataInteractionWithIndex:sourceIndex withSession:nil];
 }
 
+- (void)webViewDidSendDataInteractionStartRequest:(WKWebView *)webView
+{
+    // This addresses a race condition in the testing harness wherein the web process might take longer than usual to process the
+    // request to start data interaction, and in the meantime, DataInteractionSimulator would end up completing the rest of the test
+    // before a response from the web process is received. We instead defer test progress until after the web process has indicated
+    // whether or not data interaction should commence.
+    [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(_advanceProgress) object:nil];
+}
+
+- (void)webView:(WKWebView *)webView didReceiveDataInteractionStartResponse:(BOOL)started
+{
+    [self _scheduleAdvanceProgress];
+}
+
 @end
 
 #endif // ENABLE(DATA_INTERACTION)
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to