[WK2] Add infrastructure and unit tests for file uploads using data interaction
authorwenson_hsieh@apple.com <wenson_hsieh@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 19 Apr 2017 04:22:19 +0000 (04:22 +0000)
committerwenson_hsieh@apple.com <wenson_hsieh@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 19 Apr 2017 04:22:19 +0000 (04:22 +0000)
https://bugs.webkit.org/show_bug.cgi?id=170903
<rdar://problem/31314689>

Reviewed by Tim Horton.

Source/WebKit2:

See Tools/ChangeLog for more details. Makes a small adjustment to _simulateDataInteractionUpdated: to return a
BOOL indicating whether or not to allow the operation to proceed. This is necessary for testing scenarios where
multiple files are being "data interacted" onto an element. See <https://bugs.webkit.org/show_bug.cgi?id=170880>
for more details about the change this patch is testing.

* UIProcess/API/Cocoa/WKWebView.mm:
(-[WKWebView _simulateDataInteractionUpdated:]):
* UIProcess/API/Cocoa/WKWebViewPrivate.h:
* UIProcess/ios/WKContentViewInteraction.h:

Tools:

Adds 5 new unit tests covering different cases of uploading files through data interaction, as well as
infrastructure for simulating UIItemProviders that load file data. Makes a few adjustments to the
DataInteractionSimulator along the way, detailed in the per-method annotations below. See
<https://bugs.webkit.org/show_bug.cgi?id=170880> for more details about the change this patch is testing.

New tests:
DataInteractionTests.ExternalSourceImageToFileInput
DataInteractionTests.ExternalSourceHTMLToUploadArea
DataInteractionTests.ExternalSourceImageAndHTMLToSingleFileInput
DataInteractionTests.ExternalSourceImageAndHTMLToMultipleFileInput
DataInteractionTests.ExternalSourceImageAndHTMLToUploadArea

* TestWebKitAPI/Tests/ios/DataInteractionTests.mm:
(testIconImage):
(temporaryURLForDataInteractionFileLoad):
(cleanUpDataInteractionTemporaryPath):

Creates and tears down temporary file directories for testing data interaction.

(-[UIItemProvider registerFileRepresentationForTypeIdentifier:withData:filename:]):
(TestWebKitAPI::TEST):
* TestWebKitAPI/ios/DataInteractionSimulator.h:
* TestWebKitAPI/ios/DataInteractionSimulator.mm:

Make necessary changes to be able to test what happens when data interaction ends over an element with no
operation. Previously, we would always simulate performing a data interaction operation when ending the
simulation, but this causes us to wait indefinitely for a data operation response to arrive in the UI process.
Instead, we need to note whether or not the content view is allowing data interaction, and only perform an
operation and wait for the -didPerform call if the operation was allowed. Otherwise, we immediately transition
the phase to Cancelled and end the run.

(-[DataInteractionSimulator _resetSimulatedState]):
(-[DataInteractionSimulator runFrom:to:]):
(-[DataInteractionSimulator _concludeDataInteractionAndPerformOperationIfNecessary]):
(-[DataInteractionSimulator _advanceProgress]):
(-[DataInteractionSimulator externalItemProviders]):
(-[DataInteractionSimulator setExternalItemProviders:]):

Previously, we hard-coded DataInteractionSimulator to only support a single external item provider. In order to
test the scenario where multiple files are being "data interacted" into a file-type input, we generalize this to
take multiple item providers.

(-[DataInteractionSimulator externalItemProvider]): Deleted.
(-[DataInteractionSimulator setExternalItemProvider:]): Deleted.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@215502 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebKit2/ChangeLog
Source/WebKit2/UIProcess/API/Cocoa/WKWebView.mm
Source/WebKit2/UIProcess/API/Cocoa/WKWebViewPrivate.h
Source/WebKit2/UIProcess/ios/WKContentViewInteraction.h
Tools/ChangeLog
Tools/TestWebKitAPI/Tests/ios/DataInteractionTests.mm
Tools/TestWebKitAPI/ios/DataInteractionSimulator.h
Tools/TestWebKitAPI/ios/DataInteractionSimulator.mm

index 063b4f1601be8e27bafb831312f01c5016f137de..152e69b5724f85398d583ab1669f9a45eb2b7245 100644 (file)
@@ -1,3 +1,21 @@
+2017-04-18  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        [WK2] Add infrastructure and unit tests for file uploads using data interaction
+        https://bugs.webkit.org/show_bug.cgi?id=170903
+        <rdar://problem/31314689>
+
+        Reviewed by Tim Horton.
+
+        See Tools/ChangeLog for more details. Makes a small adjustment to _simulateDataInteractionUpdated: to return a
+        BOOL indicating whether or not to allow the operation to proceed. This is necessary for testing scenarios where
+        multiple files are being "data interacted" onto an element. See <https://bugs.webkit.org/show_bug.cgi?id=170880>
+        for more details about the change this patch is testing.
+
+        * UIProcess/API/Cocoa/WKWebView.mm:
+        (-[WKWebView _simulateDataInteractionUpdated:]):
+        * UIProcess/API/Cocoa/WKWebViewPrivate.h:
+        * UIProcess/ios/WKContentViewInteraction.h:
+
 2017-04-18  Wenson Hsieh  <wenson_hsieh@apple.com>
 
         [WK2] Support DataTransfer::files() when performing a DHTML data interaction
 2017-04-18  Wenson Hsieh  <wenson_hsieh@apple.com>
 
         [WK2] Support DataTransfer::files() when performing a DHTML data interaction
index aeec2601cefc5e902b913479fc52f7b5ea10f483..270afdf724aecb4bd32818d303930f17d20a191e 100644 (file)
@@ -5409,10 +5409,12 @@ static WebCore::UserInterfaceLayoutDirection toUserInterfaceLayoutDirection(UISe
 #endif
 }
 
 #endif
 }
 
-- (void)_simulateDataInteractionUpdated:(id)info
+- (BOOL)_simulateDataInteractionUpdated:(id)info
 {
 #if ENABLE(DATA_INTERACTION)
 {
 #if ENABLE(DATA_INTERACTION)
-    [_contentView _simulateDataInteractionUpdated:info];
+    return [_contentView _simulateDataInteractionUpdated:info];
+#else
+    return NO;
 #endif
 }
 
 #endif
 }
 
index d0e5fc0300d9bfaf23f774d1f575f2f566c906b6..3084d8687ca4579319bd5733286f8e04a518709c 100644 (file)
@@ -328,7 +328,7 @@ typedef NS_ENUM(NSInteger, _WKImmediateActionType) {
 - (NSDictionary *)_propertiesOfLayerWithID:(unsigned long long)layerID WK_API_AVAILABLE(ios(WK_IOS_TBA));
 
 - (void)_simulateDataInteractionEntered:(id)info WK_API_AVAILABLE(ios(WK_IOS_TBA));
 - (NSDictionary *)_propertiesOfLayerWithID:(unsigned long long)layerID WK_API_AVAILABLE(ios(WK_IOS_TBA));
 
 - (void)_simulateDataInteractionEntered:(id)info WK_API_AVAILABLE(ios(WK_IOS_TBA));
-- (void)_simulateDataInteractionUpdated:(id)info WK_API_AVAILABLE(ios(WK_IOS_TBA));
+- (BOOL)_simulateDataInteractionUpdated:(id)info WK_API_AVAILABLE(ios(WK_IOS_TBA));
 - (void)_simulateDataInteractionPerformOperation:(id)info WK_API_AVAILABLE(ios(WK_IOS_TBA));
 - (void)_simulateDataInteractionEnded:(id)info WK_API_AVAILABLE(ios(WK_IOS_TBA));
 - (void)_simulateDataInteractionSessionDidEnd:(id)session WK_API_AVAILABLE(ios(WK_IOS_TBA));
 - (void)_simulateDataInteractionPerformOperation:(id)info WK_API_AVAILABLE(ios(WK_IOS_TBA));
 - (void)_simulateDataInteractionEnded:(id)info WK_API_AVAILABLE(ios(WK_IOS_TBA));
 - (void)_simulateDataInteractionSessionDidEnd:(id)session WK_API_AVAILABLE(ios(WK_IOS_TBA));
index ee205db10352d4258ea75fd8b5b0d170297a2750..9f3add97bb3c5fe9fb8c317147f5d26baaaed35f 100644 (file)
@@ -295,7 +295,7 @@ struct WKAutoCorrectionData {
 - (void)_didChangeDataInteractionCaretRect:(CGRect)previousRect currentRect:(CGRect)rect;
 
 - (void)_simulateDataInteractionEntered:(id)info;
 - (void)_didChangeDataInteractionCaretRect:(CGRect)previousRect currentRect:(CGRect)rect;
 
 - (void)_simulateDataInteractionEntered:(id)info;
-- (void)_simulateDataInteractionUpdated:(id)info;
+- (BOOL)_simulateDataInteractionUpdated:(id)info;
 - (void)_simulateDataInteractionPerformOperation:(id)info;
 - (void)_simulateDataInteractionEnded:(id)info;
 - (void)_simulateDataInteractionSessionDidEnd:(id)session;
 - (void)_simulateDataInteractionPerformOperation:(id)info;
 - (void)_simulateDataInteractionEnded:(id)info;
 - (void)_simulateDataInteractionSessionDidEnd:(id)session;
index 91ab28024b99f7c3beb1ff14ffe5d7fb415942a7..1fed3d214b9c43efeecd7bcf5c0392b0205449a8 100644 (file)
@@ -1,3 +1,56 @@
+2017-04-18  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        [WK2] Add infrastructure and unit tests for file uploads using data interaction
+        https://bugs.webkit.org/show_bug.cgi?id=170903
+        <rdar://problem/31314689>
+
+        Reviewed by Tim Horton.
+
+        Adds 5 new unit tests covering different cases of uploading files through data interaction, as well as
+        infrastructure for simulating UIItemProviders that load file data. Makes a few adjustments to the
+        DataInteractionSimulator along the way, detailed in the per-method annotations below. See
+        <https://bugs.webkit.org/show_bug.cgi?id=170880> for more details about the change this patch is testing.
+
+        New tests:
+        DataInteractionTests.ExternalSourceImageToFileInput
+        DataInteractionTests.ExternalSourceHTMLToUploadArea
+        DataInteractionTests.ExternalSourceImageAndHTMLToSingleFileInput
+        DataInteractionTests.ExternalSourceImageAndHTMLToMultipleFileInput
+        DataInteractionTests.ExternalSourceImageAndHTMLToUploadArea
+
+        * TestWebKitAPI/Tests/ios/DataInteractionTests.mm:
+        (testIconImage):
+        (temporaryURLForDataInteractionFileLoad):
+        (cleanUpDataInteractionTemporaryPath):
+
+        Creates and tears down temporary file directories for testing data interaction.
+
+        (-[UIItemProvider registerFileRepresentationForTypeIdentifier:withData:filename:]):
+        (TestWebKitAPI::TEST):
+        * TestWebKitAPI/ios/DataInteractionSimulator.h:
+        * TestWebKitAPI/ios/DataInteractionSimulator.mm:
+
+        Make necessary changes to be able to test what happens when data interaction ends over an element with no
+        operation. Previously, we would always simulate performing a data interaction operation when ending the
+        simulation, but this causes us to wait indefinitely for a data operation response to arrive in the UI process.
+        Instead, we need to note whether or not the content view is allowing data interaction, and only perform an
+        operation and wait for the -didPerform call if the operation was allowed. Otherwise, we immediately transition
+        the phase to Cancelled and end the run.
+
+        (-[DataInteractionSimulator _resetSimulatedState]):
+        (-[DataInteractionSimulator runFrom:to:]):
+        (-[DataInteractionSimulator _concludeDataInteractionAndPerformOperationIfNecessary]):
+        (-[DataInteractionSimulator _advanceProgress]):
+        (-[DataInteractionSimulator externalItemProviders]):
+        (-[DataInteractionSimulator setExternalItemProviders:]):
+
+        Previously, we hard-coded DataInteractionSimulator to only support a single external item provider. In order to
+        test the scenario where multiple files are being "data interacted" into a file-type input, we generalize this to
+        take multiple item providers.
+
+        (-[DataInteractionSimulator externalItemProvider]): Deleted.
+        (-[DataInteractionSimulator setExternalItemProvider:]): Deleted.
+
 2017-04-18  John Wilander  <wilander@apple.com>
 
         Make WebCore::topPrivatelyControlledDomain() return "localhost" for localhost
 2017-04-18  John Wilander  <wilander@apple.com>
 
         Make WebCore::topPrivatelyControlledDomain() return "localhost" for localhost
index ffc5ad55bd035fa545e5aa0e5e02815bbfd2e6af..0f32b7cd0b3bee18fc8b9c8da4e5cd3e1a25077f 100644 (file)
 #import <WebKit/WKWebViewConfigurationPrivate.h>
 #import <WebKit/_WKProcessPoolConfiguration.h>
 
 #import <WebKit/WKWebViewConfigurationPrivate.h>
 #import <WebKit/_WKProcessPoolConfiguration.h>
 
+typedef void (^FileLoadCompletionBlock)(NSURL *, BOOL, NSError *);
+
+static UIImage *testIconImage()
+{
+    return [UIImage imageNamed:@"TestWebKitAPI.resources/icon.png"];
+}
+
+static NSURL *temporaryURLForDataInteractionFileLoad(NSString *temporaryFileName)
+{
+    NSString *temporaryDirectoryPath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"data-interaction"];
+    if (![[NSFileManager defaultManager] fileExistsAtPath:temporaryDirectoryPath])
+        [[NSFileManager defaultManager] createDirectoryAtPath:temporaryDirectoryPath withIntermediateDirectories:YES attributes:nil error:nil];
+    return [NSURL fileURLWithPath:[temporaryDirectoryPath stringByAppendingPathComponent:temporaryFileName]];
+}
+
+static void cleanUpDataInteractionTemporaryPath()
+{
+    NSArray *temporaryDirectoryContents = [[NSFileManager defaultManager] contentsOfDirectoryAtURL:[NSURL fileURLWithPath:NSTemporaryDirectory()] includingPropertiesForKeys:nil options:0 error:nil];
+    for (NSURL *url in temporaryDirectoryContents) {
+        if ([url.lastPathComponent rangeOfString:@"data-interaction"].location != NSNotFound)
+            [[NSFileManager defaultManager] removeItemAtURL:url error:nil];
+    }
+}
+
+@implementation UIItemProvider (DataInteractionTests)
+
+- (void)registerFileRepresentationForTypeIdentifier:(NSString *)typeIdentifier withData:(NSData *)data filename:(NSString *)filename
+{
+    RetainPtr<NSData> retainedData = data;
+    RetainPtr<NSURL> retainedTemporaryURL = temporaryURLForDataInteractionFileLoad(filename);
+    [self registerFileRepresentationForTypeIdentifier:typeIdentifier fileOptions:0 visibility:NSItemProviderRepresentationVisibilityAll loadHandler: [retainedData, retainedTemporaryURL] (FileLoadCompletionBlock block) -> NSProgress * {
+        [retainedData writeToFile:[retainedTemporaryURL path] atomically:YES];
+        dispatch_async(dispatch_get_main_queue(), [retainedTemporaryURL, capturedBlock = makeBlockPtr(block)] {
+            capturedBlock(retainedTemporaryURL.get(), NO, nil);
+        });
+        return nil;
+    }];
+}
+
+@end
+
 @implementation TestWKWebView (DataInteractionTests)
 
 - (BOOL)editorContainsImageElement
 @implementation TestWKWebView (DataInteractionTests)
 
 - (BOOL)editorContainsImageElement
@@ -273,6 +314,118 @@ TEST(DataInteractionTests, EnterAndLeaveEvents)
     checkSelectionRectsWithLogging(@[ ], [dataInteractionSimulator finalSelectionRects]);
 }
 
     checkSelectionRectsWithLogging(@[ ], [dataInteractionSimulator finalSelectionRects]);
 }
 
+TEST(DataInteractionTests, ExternalSourceImageToFileInput)
+{
+    RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
+    [webView synchronouslyLoadTestPageNamed:@"file-uploading"];
+
+    RetainPtr<UIItemProvider> simulatedImageItemProvider = adoptNS([[UIItemProvider alloc] init]);
+    NSData *imageData = UIImageJPEGRepresentation(testIconImage(), 0.5);
+    [simulatedImageItemProvider registerFileRepresentationForTypeIdentifier:(NSString *)kUTTypeJPEG withData:imageData filename:@"image.png"];
+
+    RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
+    [dataInteractionSimulator setExternalItemProviders:@[ simulatedImageItemProvider.get() ]];
+    [dataInteractionSimulator runFrom:CGPointMake(200, 100) to:CGPointMake(100, 100)];
+
+    NSString *outputValue = [webView stringByEvaluatingJavaScript:@"output.value"];
+    EXPECT_WK_STREQ("image/jpeg", outputValue.UTF8String);
+
+    cleanUpDataInteractionTemporaryPath();
+}
+
+TEST(DataInteractionTests, ExternalSourceHTMLToUploadArea)
+{
+    RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
+    [webView synchronouslyLoadTestPageNamed:@"file-uploading"];
+
+    RetainPtr<UIItemProvider> simulatedHTMLItemProvider = adoptNS([[UIItemProvider alloc] init]);
+    NSData *htmlData = [@"<body contenteditable></body>" dataUsingEncoding:NSUTF8StringEncoding];
+    [simulatedHTMLItemProvider registerFileRepresentationForTypeIdentifier:(NSString *)kUTTypeHTML withData:htmlData filename:@"index.html"];
+
+    RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
+    [dataInteractionSimulator setExternalItemProviders:@[ simulatedHTMLItemProvider.get() ]];
+    [dataInteractionSimulator runFrom:CGPointMake(200, 300) to:CGPointMake(100, 300)];
+
+    NSString *outputValue = [webView stringByEvaluatingJavaScript:@"output.value"];
+    EXPECT_WK_STREQ("text/html", outputValue.UTF8String);
+
+    cleanUpDataInteractionTemporaryPath();
+}
+
+TEST(DataInteractionTests, ExternalSourceImageAndHTMLToSingleFileInput)
+{
+    RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
+    [webView synchronouslyLoadTestPageNamed:@"file-uploading"];
+
+    RetainPtr<UIItemProvider> simulatedImageItemProvider = adoptNS([[UIItemProvider alloc] init]);
+    NSData *imageData = UIImageJPEGRepresentation(testIconImage(), 0.5);
+    [simulatedImageItemProvider registerFileRepresentationForTypeIdentifier:(NSString *)kUTTypeJPEG withData:imageData filename:@"image.png"];
+
+    RetainPtr<UIItemProvider> simulatedHTMLItemProvider = adoptNS([[UIItemProvider alloc] init]);
+    NSData *htmlData = [@"<body contenteditable></body>" dataUsingEncoding:NSUTF8StringEncoding];
+    [simulatedHTMLItemProvider registerFileRepresentationForTypeIdentifier:(NSString *)kUTTypeHTML withData:htmlData filename:@"index.html"];
+
+    RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
+    [dataInteractionSimulator setExternalItemProviders:@[ simulatedHTMLItemProvider.get(), simulatedImageItemProvider.get() ]];
+    [dataInteractionSimulator runFrom:CGPointMake(200, 100) to:CGPointMake(100, 100)];
+
+    NSString *outputValue = [webView stringByEvaluatingJavaScript:@"output.value"];
+    EXPECT_WK_STREQ("", outputValue.UTF8String);
+
+    cleanUpDataInteractionTemporaryPath();
+}
+
+TEST(DataInteractionTests, ExternalSourceImageAndHTMLToMultipleFileInput)
+{
+    RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
+    [webView synchronouslyLoadTestPageNamed:@"file-uploading"];
+    [webView stringByEvaluatingJavaScript:@"input.setAttribute('multiple', '')"];
+
+    RetainPtr<UIItemProvider> simulatedImageItemProvider = adoptNS([[UIItemProvider alloc] init]);
+    NSData *imageData = UIImageJPEGRepresentation(testIconImage(), 0.5);
+    [simulatedImageItemProvider registerFileRepresentationForTypeIdentifier:(NSString *)kUTTypeJPEG withData:imageData filename:@"image.png"];
+
+    RetainPtr<UIItemProvider> simulatedHTMLItemProvider = adoptNS([[UIItemProvider alloc] init]);
+    NSData *htmlData = [@"<body contenteditable></body>" dataUsingEncoding:NSUTF8StringEncoding];
+    [simulatedHTMLItemProvider registerFileRepresentationForTypeIdentifier:(NSString *)kUTTypeHTML withData:htmlData filename:@"index.html"];
+
+    RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
+    [dataInteractionSimulator setExternalItemProviders:@[ simulatedHTMLItemProvider.get(), simulatedImageItemProvider.get() ]];
+    [dataInteractionSimulator runFrom:CGPointMake(200, 100) to:CGPointMake(100, 100)];
+
+    NSString *outputValue = [webView stringByEvaluatingJavaScript:@"output.value"];
+    EXPECT_WK_STREQ("image/jpeg, text/html", outputValue.UTF8String);
+
+    cleanUpDataInteractionTemporaryPath();
+}
+
+TEST(DataInteractionTests, ExternalSourceImageAndHTMLToUploadArea)
+{
+    RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
+    [webView synchronouslyLoadTestPageNamed:@"file-uploading"];
+
+    RetainPtr<UIItemProvider> simulatedImageItemProvider = adoptNS([[UIItemProvider alloc] init]);
+    NSData *imageData = UIImageJPEGRepresentation(testIconImage(), 0.5);
+    [simulatedImageItemProvider registerFileRepresentationForTypeIdentifier:(NSString *)kUTTypeJPEG withData:imageData filename:@"image.png"];
+
+    RetainPtr<UIItemProvider> firstSimulatedHTMLItemProvider = adoptNS([[UIItemProvider alloc] init]);
+    NSData *firstHTMLData = [@"<body contenteditable></body>" dataUsingEncoding:NSUTF8StringEncoding];
+    [firstSimulatedHTMLItemProvider registerFileRepresentationForTypeIdentifier:(NSString *)kUTTypeHTML withData:firstHTMLData filename:@"index.html"];
+
+    RetainPtr<UIItemProvider> secondSimulatedHTMLItemProvider = adoptNS([[UIItemProvider alloc] init]);
+    NSData *secondHTMLData = [@"<html><body>hello world</body></html>" dataUsingEncoding:NSUTF8StringEncoding];
+    [secondSimulatedHTMLItemProvider registerFileRepresentationForTypeIdentifier:(NSString *)kUTTypeHTML withData:secondHTMLData filename:@"index.html"];
+
+    RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
+    [dataInteractionSimulator setExternalItemProviders:@[ simulatedImageItemProvider.get(), firstSimulatedHTMLItemProvider.get(), secondSimulatedHTMLItemProvider.get() ]];
+    [dataInteractionSimulator runFrom:CGPointMake(200, 300) to:CGPointMake(100, 300)];
+
+    NSString *outputValue = [webView stringByEvaluatingJavaScript:@"output.value"];
+    EXPECT_WK_STREQ("image/jpeg, text/html, text/html", outputValue.UTF8String);
+
+    cleanUpDataInteractionTemporaryPath();
+}
+
 TEST(DataInteractionTests, ExternalSourceUTF8PlainTextOnly)
 {
     RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
 TEST(DataInteractionTests, ExternalSourceUTF8PlainTextOnly)
 {
     RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
@@ -286,7 +439,7 @@ TEST(DataInteractionTests, ExternalSourceUTF8PlainTextOnly)
         completionBlock([textPayload dataUsingEncoding:NSUTF8StringEncoding], nil);
         return [NSProgress discreteProgressWithTotalUnitCount:100];
     }];
         completionBlock([textPayload dataUsingEncoding:NSUTF8StringEncoding], nil);
         return [NSProgress discreteProgressWithTotalUnitCount:100];
     }];
-    [dataInteractionSimulator setExternalItemProvider:simulatedItemProvider.get()];
+    [dataInteractionSimulator setExternalItemProviders:@[ simulatedItemProvider.get() ]];
     [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
     EXPECT_WK_STREQ(textPayload.UTF8String, [webView stringByEvaluatingJavaScript:@"editor.textContent"].UTF8String);
     checkSelectionRectsWithLogging(@[ makeCGRectValue(1, 201, 1936, 227) ], [dataInteractionSimulator finalSelectionRects]);
     [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
     EXPECT_WK_STREQ(textPayload.UTF8String, [webView stringByEvaluatingJavaScript:@"editor.textContent"].UTF8String);
     checkSelectionRectsWithLogging(@[ makeCGRectValue(1, 201, 1936, 227) ], [dataInteractionSimulator finalSelectionRects]);
@@ -297,15 +450,14 @@ TEST(DataInteractionTests, ExternalSourceJPEGOnly)
     RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
     [webView synchronouslyLoadTestPageNamed:@"autofocus-contenteditable"];
 
     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)
     {
     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);
+        completionBlock(UIImageJPEGRepresentation(testIconImage(), 0.5), nil);
         return [NSProgress discreteProgressWithTotalUnitCount:100];
     }];
         return [NSProgress discreteProgressWithTotalUnitCount:100];
     }];
-    [dataInteractionSimulator setExternalItemProvider:simulatedItemProvider.get()];
+    [dataInteractionSimulator setExternalItemProviders:@[ simulatedItemProvider.get() ]];
     [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
     EXPECT_TRUE([webView editorContainsImageElement]);
     checkSelectionRectsWithLogging(@[ makeCGRectValue(1, 201, 215, 174) ], [dataInteractionSimulator finalSelectionRects]);
     [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
     EXPECT_TRUE([webView editorContainsImageElement]);
     checkSelectionRectsWithLogging(@[ makeCGRectValue(1, 201, 215, 174) ], [dataInteractionSimulator finalSelectionRects]);
index 336bdfd891556c311768836572bc055b6ec17fef..b2ca47e6d3a8c2d897d24362593f9660ca8b355d 100644 (file)
@@ -54,12 +54,13 @@ typedef NS_ENUM(NSInteger, DataInteractionPhase) {
     RetainPtr<MockDataInteractionSession> _dataInteractionSession;
     RetainPtr<MockDataOperationSession> _dataOperationSession;
     RetainPtr<NSMutableArray> _observedEventNames;
     RetainPtr<MockDataInteractionSession> _dataInteractionSession;
     RetainPtr<MockDataOperationSession> _dataOperationSession;
     RetainPtr<NSMutableArray> _observedEventNames;
-    RetainPtr<UIItemProvider> _externalItemProvider;
+    RetainPtr<NSArray> _externalItemProviders;
     RetainPtr<NSArray *> _sourceItemProviders;
     RetainPtr<NSArray *> _finalSelectionRects;
     CGPoint _startLocation;
     CGPoint _endLocation;
 
     RetainPtr<NSArray *> _sourceItemProviders;
     RetainPtr<NSArray *> _finalSelectionRects;
     CGPoint _startLocation;
     CGPoint _endLocation;
 
+    BOOL _shouldPerformOperation;
     double _currentProgress;
     bool _isDoneWithCurrentRun;
     DataInteractionPhase _phase;
     double _currentProgress;
     bool _isDoneWithCurrentRun;
     DataInteractionPhase _phase;
@@ -71,7 +72,7 @@ typedef NS_ENUM(NSInteger, DataInteractionPhase) {
 @property (nonatomic) BOOL shouldEnsureUIApplication;
 @property (nonatomic) BlockPtr<BOOL(_WKActivatedElementInfo *)> showCustomActionSheetBlock;
 @property (nonatomic) BlockPtr<NSArray *(NSArray *)> convertItemProvidersBlock;
 @property (nonatomic) BOOL shouldEnsureUIApplication;
 @property (nonatomic) BlockPtr<BOOL(_WKActivatedElementInfo *)> showCustomActionSheetBlock;
 @property (nonatomic) BlockPtr<NSArray *(NSArray *)> convertItemProvidersBlock;
-@property (nonatomic, strong) UIItemProvider *externalItemProvider;
+@property (nonatomic, strong) NSArray *externalItemProviders;
 @property (nonatomic, readonly) NSArray *sourceItemProviders;
 @property (nonatomic, readonly) NSArray *observedEventNames;
 @property (nonatomic, readonly) NSArray *finalSelectionRects;
 @property (nonatomic, readonly) NSArray *sourceItemProviders;
 @property (nonatomic, readonly) NSArray *observedEventNames;
 @property (nonatomic, readonly) NSArray *finalSelectionRects;
index ae16c9d8846465bd6a53a0489012860a4070bfb8..a564517ec8af3507cedebc56e6800a35e42d9f04 100644 (file)
@@ -101,6 +101,7 @@ static NSArray *dataInteractionEventNames()
     _finalSelectionRects = @[ ];
     _dataInteractionSession = nil;
     _dataOperationSession = nil;
     _finalSelectionRects = @[ ];
     _dataInteractionSession = nil;
     _dataOperationSession = nil;
+    _shouldPerformOperation = NO;
 }
 
 - (NSArray *)observedEventNames
 }
 
 - (NSArray *)observedEventNames
@@ -139,8 +140,8 @@ static NSArray *dataInteractionEventNames()
     _startLocation = startLocation;
     _endLocation = endLocation;
 
     _startLocation = startLocation;
     _endLocation = endLocation;
 
-    if (self.externalItemProvider) {
-        _dataOperationSession = adoptNS([[MockDataOperationSession alloc] initWithProvider:self.externalItemProvider location:_startLocation window:[_webView window]]);
+    if (self.externalItemProviders.count) {
+        _dataOperationSession = adoptNS([[MockDataOperationSession alloc] initWithProviders:self.externalItemProviders location:_startLocation window:[_webView window]]);
         _phase = DataInteractionBegan;
         [self _advanceProgress];
     } else {
         _phase = DataInteractionBegan;
         [self _advanceProgress];
     } else {
@@ -168,6 +169,22 @@ static NSArray *dataInteractionEventNames()
     return _finalSelectionRects.get();
 }
 
     return _finalSelectionRects.get();
 }
 
+- (void)_concludeDataInteractionAndPerformOperationIfNecessary
+{
+    if (_shouldPerformOperation) {
+        [_webView _simulateDataInteractionPerformOperation:_dataOperationSession.get()];
+        _phase = DataInteractionPerforming;
+    } else {
+        _isDoneWithCurrentRun = YES;
+        _phase = DataInteractionCancelled;
+    }
+
+    [_webView _simulateDataInteractionEnded:_dataOperationSession.get()];
+
+    if (_dataInteractionSession)
+        [_webView _simulateDataInteractionSessionDidEnd:_dataInteractionSession.get()];
+}
+
 - (void)_advanceProgress
 {
     _currentProgress += progressIncrementStep;
 - (void)_advanceProgress
 {
     _currentProgress += progressIncrementStep;
@@ -176,13 +193,8 @@ static NSArray *dataInteractionEventNames()
     [_dataOperationSession setMockLocationInWindow:locationInWindow];
 
     if (_currentProgress >= 1) {
     [_dataOperationSession setMockLocationInWindow:locationInWindow];
 
     if (_currentProgress >= 1) {
-        [_webView _simulateDataInteractionPerformOperation:_dataOperationSession.get()];
-        [_webView _simulateDataInteractionEnded:_dataOperationSession.get()];
-        if (_dataInteractionSession)
-            [_webView _simulateDataInteractionSessionDidEnd:_dataInteractionSession.get()];
-
-        _phase = DataInteractionPerforming;
         _currentProgress = 1;
         _currentProgress = 1;
+        [self _concludeDataInteractionAndPerformOperationIfNecessary];
         return;
     }
 
         return;
     }
 
@@ -200,7 +212,7 @@ static NSArray *dataInteractionEventNames()
         for (WKDataInteractionItem *item in items)
             [itemProviders addObject:item.itemProvider];
 
         for (WKDataInteractionItem *item in items)
             [itemProviders addObject:item.itemProvider];
 
-        _dataOperationSession = adoptNS([[MockDataOperationSession alloc] initWithProvider:itemProviders.firstObject location:self._currentLocation window:[_webView window]]);
+        _dataOperationSession = adoptNS([[MockDataOperationSession alloc] initWithProviders:itemProviders location:self._currentLocation window:[_webView window]]);
         [_dataInteractionSession setItems:items];
         _sourceItemProviders = itemProviders;
         if (self.showCustomActionSheetBlock) {
         [_dataInteractionSession setItems:items];
         _sourceItemProviders = itemProviders;
         if (self.showCustomActionSheetBlock) {
@@ -217,7 +229,7 @@ static NSArray *dataInteractionEventNames()
         _phase = DataInteractionEntered;
         break;
     case DataInteractionEntered:
         _phase = DataInteractionEntered;
         break;
     case DataInteractionEntered:
-        [_webView _simulateDataInteractionUpdated:_dataOperationSession.get()];
+        _shouldPerformOperation = [_webView _simulateDataInteractionUpdated:_dataOperationSession.get()];
         break;
     default:
         break;
         break;
     default:
         break;
@@ -244,14 +256,14 @@ static NSArray *dataInteractionEventNames()
     return _sourceItemProviders.get();
 }
 
     return _sourceItemProviders.get();
 }
 
-- (UIItemProvider *)externalItemProvider
+- (NSArray *)externalItemProviders
 {
 {
-    return _externalItemProvider.get();
+    return _externalItemProviders.get();
 }
 
 }
 
-- (void)setExternalItemProvider:(UIItemProvider *)externalItemProvider
+- (void)setExternalItemProviders:(NSArray *)externalItemProviders
 {
 {
-    _externalItemProvider = externalItemProvider;
+    _externalItemProviders = adoptNS([externalItemProviders copy]);
 }
 
 - (DataInteractionPhase)phase
 }
 
 - (DataInteractionPhase)phase