Unreviewed, guard iOS 11-dependent UIPasteboardTests to be iOS 11+ only
[WebKit-https.git] / Tools / TestWebKitAPI / Tests / ios / DataInteractionTests.mm
1 /*
2  * Copyright (C) 2017 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27
28 #if ENABLE(DATA_INTERACTION)
29
30 #import "DataInteractionSimulator.h"
31 #import "PlatformUtilities.h"
32 #import "TestWKWebView.h"
33 #import "WKWebViewConfigurationExtras.h"
34 #import <MobileCoreServices/MobileCoreServices.h>
35 #import <UIKit/NSString+UIItemProvider.h>
36 #import <UIKit/NSURL+UIItemProvider.h>
37 #import <UIKit/UIImage+UIItemProvider.h>
38 #import <UIKit/UIItemProvider_Private.h>
39 #import <WebKit/WKPreferencesPrivate.h>
40 #import <WebKit/WKProcessPoolPrivate.h>
41 #import <WebKit/WKWebViewConfigurationPrivate.h>
42 #import <WebKit/WebItemProviderPasteboard.h>
43 #import <WebKit/_WKProcessPoolConfiguration.h>
44
45 typedef void (^FileLoadCompletionBlock)(NSURL *, BOOL, NSError *);
46 typedef void (^DataLoadCompletionBlock)(NSData *, NSError *);
47
48 static NSString *InjectedBundlePasteboardDataType = @"org.webkit.data";
49
50 static UIImage *testIconImage()
51 {
52     return [UIImage imageNamed:@"TestWebKitAPI.resources/icon.png"];
53 }
54
55 static NSData *testZIPArchive()
56 {
57     NSURL *zipFileURL = [[NSBundle mainBundle] URLForResource:@"compressed-files" withExtension:@"zip" subdirectory:@"TestWebKitAPI.resources"];
58     return [NSData dataWithContentsOfURL:zipFileURL];
59 }
60
61 @implementation UIItemProvider (DataInteractionTests)
62
63 - (void)registerDataRepresentationForTypeIdentifier:(NSString *)typeIdentifier withData:(NSData *)data
64 {
65     RetainPtr<NSData> retainedData = data;
66     [self registerDataRepresentationForTypeIdentifier:typeIdentifier visibility:UIItemProviderRepresentationOptionsVisibilityAll loadHandler: [retainedData] (DataLoadCompletionBlock block) -> NSProgress * {
67         block(retainedData.get(), nil);
68         return [NSProgress discreteProgressWithTotalUnitCount:100];
69     }];
70 }
71
72 @end
73
74 @implementation TestWKWebView (DataInteractionTests)
75
76 - (BOOL)editorContainsImageElement
77 {
78     return [self stringByEvaluatingJavaScript:@"!!editor.querySelector('img')"].boolValue;
79 }
80
81 - (NSString *)editorValue
82 {
83     return [self stringByEvaluatingJavaScript:@"editor.value"];
84 }
85
86 @end
87
88 static NSValue *makeCGRectValue(CGFloat x, CGFloat y, CGFloat width, CGFloat height)
89 {
90     return [NSValue valueWithCGRect:CGRectMake(x, y, width, height)];
91 }
92
93 static void checkSelectionRectsWithLogging(NSArray *expected, NSArray *observed)
94 {
95     if (![expected isEqualToArray:observed])
96         NSLog(@"Expected selection rects: %@ but observed: %@", expected, observed);
97     EXPECT_TRUE([expected isEqualToArray:observed]);
98 }
99
100 static void checkTypeIdentifierPrecedesOtherTypeIdentifier(DataInteractionSimulator *simulator, NSString *firstType, NSString *secondType)
101 {
102     NSArray *registeredTypes = [simulator.sourceItemProviders.firstObject registeredTypeIdentifiers];
103     EXPECT_TRUE([registeredTypes containsObject:firstType]);
104     EXPECT_TRUE([registeredTypes containsObject:secondType]);
105     EXPECT_TRUE([registeredTypes indexOfObject:firstType] < [registeredTypes indexOfObject:secondType]);
106 }
107
108 static void checkTypeIdentifierIsRegisteredAtIndex(DataInteractionSimulator *simulator, NSString *type, NSUInteger index)
109 {
110     NSArray *registeredTypes = [simulator.sourceItemProviders.firstObject registeredTypeIdentifiers];
111     EXPECT_GT(registeredTypes.count, index);
112     EXPECT_WK_STREQ(type.UTF8String, [registeredTypes[index] UTF8String]);
113 }
114
115 static void checkSuggestedNameAndEstimatedSize(DataInteractionSimulator *simulator, NSString *suggestedName, CGSize estimatedSize)
116 {
117     UIItemProvider *sourceItemProvider = [simulator sourceItemProviders].firstObject;
118     EXPECT_WK_STREQ(suggestedName.UTF8String, sourceItemProvider.suggestedName.UTF8String);
119     EXPECT_EQ(estimatedSize.width, sourceItemProvider.estimatedDisplayedSize.width);
120     EXPECT_EQ(estimatedSize.height, sourceItemProvider.estimatedDisplayedSize.height);
121 }
122
123 static void checkStringArraysAreEqual(NSArray<NSString *> *expected, NSArray<NSString *> *observed)
124 {
125     EXPECT_EQ(expected.count, observed.count);
126     for (NSUInteger index = 0; index < expected.count; ++index) {
127         NSString *expectedString = [expected objectAtIndex:index];
128         NSString *observedString = [observed objectAtIndex:index];
129         EXPECT_WK_STREQ(expectedString, observedString);
130         if (![expectedString isEqualToString:observedString])
131             NSLog(@"Expected observed string: %@ to match expected string: %@ at index: %tu", observedString, expectedString, index);
132     }
133 }
134
135 static void checkDragCaretRectIsContainedInRect(CGRect caretRect, CGRect containerRect)
136 {
137     BOOL contained = CGRectContainsRect(containerRect, caretRect);
138     EXPECT_TRUE(contained);
139     if (!contained)
140         NSLog(@"Expected caret rect: %@ to fit within container rect: %@", NSStringFromCGRect(caretRect), NSStringFromCGRect(containerRect));
141 }
142
143 namespace TestWebKitAPI {
144
145 TEST(DataInteractionTests, ImageToContentEditable)
146 {
147     RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
148     [webView synchronouslyLoadTestPageNamed:@"image-and-contenteditable"];
149
150     RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
151     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
152
153     EXPECT_TRUE([webView editorContainsImageElement]);
154
155     NSArray *observedEventNames = [dataInteractionSimulator observedEventNames];
156     EXPECT_TRUE([observedEventNames containsObject:DataInteractionEnterEventName]);
157     EXPECT_TRUE([observedEventNames containsObject:DataInteractionOverEventName]);
158     EXPECT_TRUE([observedEventNames containsObject:DataInteractionPerformOperationEventName]);
159     checkSelectionRectsWithLogging(@[ makeCGRectValue(1, 201, 215, 174) ], [dataInteractionSimulator finalSelectionRects]);
160     checkTypeIdentifierPrecedesOtherTypeIdentifier(dataInteractionSimulator.get(), (NSString *)kUTTypePNG, (NSString *)kUTTypeFileURL);
161     checkSuggestedNameAndEstimatedSize(dataInteractionSimulator.get(), @"icon.png", { 215, 174 });
162 }
163
164 TEST(DataInteractionTests, ImageToTextarea)
165 {
166     RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
167     [webView synchronouslyLoadTestPageNamed:@"image-and-textarea"];
168
169     RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
170     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
171
172     NSURL *imageURL = [NSURL fileURLWithPath:[webView editorValue]];
173     EXPECT_WK_STREQ("icon.png", imageURL.lastPathComponent);
174
175     NSArray *observedEventNames = [dataInteractionSimulator observedEventNames];
176     EXPECT_TRUE([observedEventNames containsObject:DataInteractionEnterEventName]);
177     EXPECT_TRUE([observedEventNames containsObject:DataInteractionOverEventName]);
178     EXPECT_TRUE([observedEventNames containsObject:DataInteractionPerformOperationEventName]);
179
180     checkTypeIdentifierPrecedesOtherTypeIdentifier(dataInteractionSimulator.get(), (NSString *)kUTTypePNG, (NSString *)kUTTypeFileURL);
181     checkSuggestedNameAndEstimatedSize(dataInteractionSimulator.get(), @"icon.png", { 215, 174 });
182 }
183
184 TEST(DataInteractionTests, ImageInLinkToInput)
185 {
186     RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
187     [webView synchronouslyLoadTestPageNamed:@"image-in-link-and-input"];
188
189     RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
190     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
191
192     EXPECT_WK_STREQ("https://www.apple.com/", [webView editorValue].UTF8String);
193     checkSelectionRectsWithLogging(@[ makeCGRectValue(101, 241, 2057, 232) ], [dataInteractionSimulator finalSelectionRects]);
194     checkSuggestedNameAndEstimatedSize(dataInteractionSimulator.get(), @"icon.png", { 215, 174 });
195     checkTypeIdentifierIsRegisteredAtIndex(dataInteractionSimulator.get(), (NSString *)kUTTypePNG, 0);
196 }
197
198 TEST(DataInteractionTests, ImageInLinkWithoutHREFToInput)
199 {
200     RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
201     [webView synchronouslyLoadTestPageNamed:@"image-in-link-and-input"];
202     [webView stringByEvaluatingJavaScript:@"link.href = ''"];
203
204     RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
205     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
206
207     NSURL *imageURL = [NSURL fileURLWithPath:[webView editorValue]];
208     EXPECT_WK_STREQ("icon.png", imageURL.lastPathComponent);
209     checkSuggestedNameAndEstimatedSize(dataInteractionSimulator.get(), @"icon.png", { 215, 174 });
210     checkTypeIdentifierIsRegisteredAtIndex(dataInteractionSimulator.get(), (NSString *)kUTTypePNG, 0);
211 }
212
213 TEST(DataInteractionTests, ImageDoesNotUseElementSizeAsEstimatedSize)
214 {
215     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
216     [webView synchronouslyLoadTestPageNamed:@"gif-and-file-input"];
217
218     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
219     [dataInteractionSimulator runFrom: { 100, 100 } to: { 100, 300 }];
220
221     checkTypeIdentifierIsRegisteredAtIndex(dataInteractionSimulator.get(), (NSString *)kUTTypeGIF, 0);
222     checkSuggestedNameAndEstimatedSize(dataInteractionSimulator.get(), @"apple.gif", { 52, 64 });
223     EXPECT_WK_STREQ("apple.gif (image/gif)", [webView stringByEvaluatingJavaScript:@"output.textContent"]);
224 }
225
226 TEST(DataInteractionTests, ContentEditableToContentEditable)
227 {
228     RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
229     RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
230
231     [webView loadTestPageNamed:@"autofocus-contenteditable"];
232     [dataInteractionSimulator waitForInputSession];
233     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
234
235     EXPECT_EQ([webView stringByEvaluatingJavaScript:@"source.textContent"].length, 0UL);
236     EXPECT_WK_STREQ("Hello world", [webView stringByEvaluatingJavaScript:@"editor.textContent"].UTF8String);
237
238     NSArray *observedEventNames = [dataInteractionSimulator observedEventNames];
239     EXPECT_TRUE([observedEventNames containsObject:DataInteractionEnterEventName]);
240     EXPECT_TRUE([observedEventNames containsObject:DataInteractionOverEventName]);
241     EXPECT_TRUE([observedEventNames containsObject:DataInteractionPerformOperationEventName]);
242     checkSelectionRectsWithLogging(@[ makeCGRectValue(1, 201, 961, 227) ], [dataInteractionSimulator finalSelectionRects]);
243     checkTypeIdentifierPrecedesOtherTypeIdentifier(dataInteractionSimulator.get(), (NSString *)kUTTypeRTFD, (NSString *)kUTTypeUTF8PlainText);
244 }
245
246 TEST(DataInteractionTests, ContentEditableToTextarea)
247 {
248     RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
249     RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
250
251     [webView loadTestPageNamed:@"contenteditable-and-textarea"];
252     [dataInteractionSimulator waitForInputSession];
253     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
254
255     EXPECT_EQ([webView stringByEvaluatingJavaScript:@"source.textContent"].length, 0UL);
256     EXPECT_WK_STREQ("Hello world", [webView editorValue].UTF8String);
257
258     NSArray *observedEventNames = [dataInteractionSimulator observedEventNames];
259     EXPECT_TRUE([observedEventNames containsObject:DataInteractionEnterEventName]);
260     EXPECT_TRUE([observedEventNames containsObject:DataInteractionOverEventName]);
261     EXPECT_TRUE([observedEventNames containsObject:DataInteractionPerformOperationEventName]);
262     checkSelectionRectsWithLogging(@[ makeCGRectValue(6, 203, 990, 232) ], [dataInteractionSimulator finalSelectionRects]);
263     checkTypeIdentifierPrecedesOtherTypeIdentifier(dataInteractionSimulator.get(), (NSString *)kUTTypeRTFD, (NSString *)kUTTypeUTF8PlainText);
264 }
265
266 TEST(DataInteractionTests, ContentEditableMoveParagraphs)
267 {
268     RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
269     RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
270
271     [webView loadTestPageNamed:@"two-paragraph-contenteditable"];
272     [dataInteractionSimulator waitForInputSession];
273     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(250, 450)];
274
275     NSString *finalTextContent = [webView stringByEvaluatingJavaScript:@"editor.textContent"];
276     NSUInteger firstParagraphOffset = [finalTextContent rangeOfString:@"This is the first paragraph"].location;
277     NSUInteger secondParagraphOffset = [finalTextContent rangeOfString:@"This is the second paragraph"].location;
278
279     EXPECT_FALSE(firstParagraphOffset == NSNotFound);
280     EXPECT_FALSE(secondParagraphOffset == NSNotFound);
281     EXPECT_GT(firstParagraphOffset, secondParagraphOffset);
282     checkSelectionRectsWithLogging(@[ makeCGRectValue(190, 100, 130, 20), makeCGRectValue(0, 120, 320, 100), makeCGRectValue(0, 220, 252, 20) ], [dataInteractionSimulator finalSelectionRects]);
283 }
284
285 TEST(DataInteractionTests, DragImageFromContentEditable)
286 {
287     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
288     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
289
290     [webView synchronouslyLoadTestPageNamed:@"contenteditable-and-target"];
291     [dataInteractionSimulator runFrom:CGPointMake(100, 100) to:CGPointMake(100, 300)];
292
293     EXPECT_WK_STREQ("PASS", [webView stringByEvaluatingJavaScript:@"target.textContent"]);
294 }
295
296 TEST(DataInteractionTests, TextAreaToInput)
297 {
298     RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
299     RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
300
301     [webView loadTestPageNamed:@"textarea-to-input"];
302     [dataInteractionSimulator waitForInputSession];
303     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
304
305     EXPECT_EQ([webView stringByEvaluatingJavaScript:@"source.value"].length, 0UL);
306     EXPECT_WK_STREQ("Hello world", [webView editorValue].UTF8String);
307     checkSelectionRectsWithLogging(@[ makeCGRectValue(101, 241, 990, 232) ], [dataInteractionSimulator finalSelectionRects]);
308 }
309
310 TEST(DataInteractionTests, SinglePlainTextWordTypeIdentifiers)
311 {
312     RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
313     RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
314
315     [webView loadTestPageNamed:@"textarea-to-input"];
316     [dataInteractionSimulator waitForInputSession];
317     [webView stringByEvaluatingJavaScript:@"source.value = 'pneumonoultramicroscopicsilicovolcanoconiosis'"];
318     [webView stringByEvaluatingJavaScript:@"source.selectionStart = 0"];
319     [webView stringByEvaluatingJavaScript:@"source.selectionEnd = source.value.length"];
320     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
321
322     NSArray *registeredTypes = [[dataInteractionSimulator sourceItemProviders].firstObject registeredTypeIdentifiers];
323     EXPECT_EQ(1UL, registeredTypes.count);
324     EXPECT_WK_STREQ([(NSString *)kUTTypeUTF8PlainText UTF8String], [registeredTypes.firstObject UTF8String]);
325     EXPECT_EQ([webView stringByEvaluatingJavaScript:@"source.value"].length, 0UL);
326     EXPECT_WK_STREQ("pneumonoultramicroscopicsilicovolcanoconiosis", [webView editorValue].UTF8String);
327 }
328
329 TEST(DataInteractionTests, SinglePlainTextURLTypeIdentifiers)
330 {
331     RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
332     RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
333
334     [webView loadTestPageNamed:@"textarea-to-input"];
335     [dataInteractionSimulator waitForInputSession];
336     [webView stringByEvaluatingJavaScript:@"source.value = 'https://webkit.org/'"];
337     [webView stringByEvaluatingJavaScript:@"source.selectionStart = 0"];
338     [webView stringByEvaluatingJavaScript:@"source.selectionEnd = source.value.length"];
339     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
340
341     NSArray *registeredTypes = [[dataInteractionSimulator sourceItemProviders].firstObject registeredTypeIdentifiers];
342     EXPECT_EQ(2UL, registeredTypes.count);
343     EXPECT_WK_STREQ([(NSString *)kUTTypeURL UTF8String], [registeredTypes.firstObject UTF8String]);
344     EXPECT_WK_STREQ([(NSString *)kUTTypeUTF8PlainText UTF8String], [registeredTypes.lastObject UTF8String]);
345     EXPECT_EQ(0UL, [webView stringByEvaluatingJavaScript:@"source.value"].length);
346     EXPECT_WK_STREQ("https://webkit.org/", [webView editorValue].UTF8String);
347 }
348
349 TEST(DataInteractionTests, LinkToInput)
350 {
351     RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
352     [webView synchronouslyLoadTestPageNamed:@"link-and-input"];
353
354     RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
355     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
356
357     EXPECT_WK_STREQ("https://www.apple.com/", [webView editorValue].UTF8String);
358
359     __block bool doneLoadingURL = false;
360     UIItemProvider *sourceItemProvider = [dataInteractionSimulator sourceItemProviders].firstObject;
361     [sourceItemProvider loadObjectOfClass:[NSURL class] completionHandler:^(id object, NSError *error) {
362         NSURL *url = object;
363         EXPECT_WK_STREQ("Hello world", url._title.UTF8String ?: "");
364         doneLoadingURL = true;
365     }];
366     TestWebKitAPI::Util::run(&doneLoadingURL);
367
368     NSArray *observedEventNames = [dataInteractionSimulator observedEventNames];
369     EXPECT_TRUE([observedEventNames containsObject:DataInteractionEnterEventName]);
370     EXPECT_TRUE([observedEventNames containsObject:DataInteractionOverEventName]);
371     EXPECT_TRUE([observedEventNames containsObject:DataInteractionPerformOperationEventName]);
372     checkSelectionRectsWithLogging(@[ makeCGRectValue(101, 273, 2057, 232) ], [dataInteractionSimulator finalSelectionRects]);
373     checkTypeIdentifierIsRegisteredAtIndex(dataInteractionSimulator.get(), (NSString *)kUTTypeURL, 0);
374 }
375
376 TEST(DataInteractionTests, BackgroundImageLinkToInput)
377 {
378     RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
379     [webView synchronouslyLoadTestPageNamed:@"background-image-link-and-input"];
380
381     RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
382     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
383
384     EXPECT_WK_STREQ("https://www.apple.com/", [webView editorValue].UTF8String);
385
386     NSArray *observedEventNames = [dataInteractionSimulator observedEventNames];
387     EXPECT_TRUE([observedEventNames containsObject:DataInteractionEnterEventName]);
388     EXPECT_TRUE([observedEventNames containsObject:DataInteractionOverEventName]);
389     EXPECT_TRUE([observedEventNames containsObject:DataInteractionPerformOperationEventName]);
390     checkSelectionRectsWithLogging(@[ makeCGRectValue(101, 241, 2057, 232) ], [dataInteractionSimulator finalSelectionRects]);
391     checkTypeIdentifierIsRegisteredAtIndex(dataInteractionSimulator.get(), (NSString *)kUTTypeURL, 0);
392 }
393
394 TEST(DataInteractionTests, CanPreventStart)
395 {
396     RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
397     [webView synchronouslyLoadTestPageNamed:@"prevent-start"];
398
399     RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
400     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
401
402     EXPECT_EQ(DataInteractionCancelled, [dataInteractionSimulator phase]);
403     EXPECT_FALSE([webView editorContainsImageElement]);
404
405     NSArray *observedEventNames = [dataInteractionSimulator observedEventNames];
406     EXPECT_FALSE([observedEventNames containsObject:DataInteractionEnterEventName]);
407     EXPECT_FALSE([observedEventNames containsObject:DataInteractionOverEventName]);
408     checkSelectionRectsWithLogging(@[ ], [dataInteractionSimulator finalSelectionRects]);
409 }
410
411 TEST(DataInteractionTests, CanPreventOperation)
412 {
413     RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
414     [webView synchronouslyLoadTestPageNamed:@"prevent-operation"];
415
416     RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
417     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
418
419     EXPECT_FALSE([webView editorContainsImageElement]);
420
421     NSArray *observedEventNames = [dataInteractionSimulator observedEventNames];
422     EXPECT_TRUE([observedEventNames containsObject:DataInteractionEnterEventName]);
423     EXPECT_TRUE([observedEventNames containsObject:DataInteractionOverEventName]);
424     checkSelectionRectsWithLogging(@[ ], [dataInteractionSimulator finalSelectionRects]);
425 }
426
427 TEST(DataInteractionTests, EnterAndLeaveEvents)
428 {
429     RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
430     [webView synchronouslyLoadTestPageNamed:@"link-and-input"];
431
432     RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
433     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 450)];
434
435     EXPECT_WK_STREQ("", [webView editorValue].UTF8String);
436
437     NSArray *observedEventNames = [dataInteractionSimulator observedEventNames];
438     EXPECT_TRUE([observedEventNames containsObject:DataInteractionEnterEventName]);
439     EXPECT_TRUE([observedEventNames containsObject:DataInteractionOverEventName]);
440     EXPECT_TRUE([observedEventNames containsObject:DataInteractionLeaveEventName]);
441     EXPECT_FALSE([observedEventNames containsObject:DataInteractionPerformOperationEventName]);
442     checkSelectionRectsWithLogging(@[ ], [dataInteractionSimulator finalSelectionRects]);
443 }
444
445 TEST(DataInteractionTests, ExternalSourcePlainTextToIFrame)
446 {
447     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
448     [webView synchronouslyLoadTestPageNamed:@"contenteditable-in-iframe"];
449
450     auto itemProvider = adoptNS([[UIItemProvider alloc] init]);
451     [itemProvider registerObject:@"Hello world" visibility:UIItemProviderRepresentationOptionsVisibilityAll];
452
453     auto simulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
454     [simulator setExternalItemProviders:@[ itemProvider.get() ]];
455     [simulator runFrom:CGPointMake(0, 0) to:CGPointMake(160, 250)];
456
457     auto containerLeft = [webView stringByEvaluatingJavaScript:@"container.getBoundingClientRect().left"].floatValue;
458     auto containerTop = [webView stringByEvaluatingJavaScript:@"container.getBoundingClientRect().top"].floatValue;
459     auto containerWidth = [webView stringByEvaluatingJavaScript:@"container.getBoundingClientRect().width"].floatValue;
460     auto containerHeight = [webView stringByEvaluatingJavaScript:@"container.getBoundingClientRect().height"].floatValue;
461     checkDragCaretRectIsContainedInRect([simulator lastKnownDragCaretRect], CGRectMake(containerLeft, containerTop, containerWidth, containerHeight));
462 }
463
464 TEST(DataInteractionTests, ExternalSourceJSONToFileInput)
465 {
466     RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
467     [webView synchronouslyLoadTestPageNamed:@"file-uploading"];
468
469     RetainPtr<UIItemProvider> simulatedJSONItemProvider = adoptNS([[UIItemProvider alloc] init]);
470     NSData *jsonData = [@"{ \"foo\": \"bar\",  \"bar\": \"baz\" }" dataUsingEncoding:NSUTF8StringEncoding];
471     [simulatedJSONItemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeJSON withData:jsonData];
472
473     RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
474     [dataInteractionSimulator setExternalItemProviders:@[ simulatedJSONItemProvider.get() ]];
475     [dataInteractionSimulator runFrom:CGPointMake(200, 100) to:CGPointMake(100, 100)];
476
477     EXPECT_WK_STREQ("application/json", [webView stringByEvaluatingJavaScript:@"output.value"]);
478 }
479
480 TEST(DataInteractionTests, ExternalSourceImageToFileInput)
481 {
482     RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
483     [webView synchronouslyLoadTestPageNamed:@"file-uploading"];
484
485     RetainPtr<UIItemProvider> simulatedImageItemProvider = adoptNS([[UIItemProvider alloc] init]);
486     NSData *imageData = UIImageJPEGRepresentation(testIconImage(), 0.5);
487     [simulatedImageItemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeJPEG withData:imageData];
488
489     RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
490     [dataInteractionSimulator setExternalItemProviders:@[ simulatedImageItemProvider.get() ]];
491     [dataInteractionSimulator runFrom:CGPointMake(200, 100) to:CGPointMake(100, 100)];
492
493     NSString *outputValue = [webView stringByEvaluatingJavaScript:@"output.value"];
494     EXPECT_WK_STREQ("image/jpeg", outputValue.UTF8String);
495 }
496
497 TEST(DataInteractionTests, ExternalSourceHTMLToUploadArea)
498 {
499     RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
500     [webView synchronouslyLoadTestPageNamed:@"file-uploading"];
501
502     RetainPtr<UIItemProvider> simulatedHTMLItemProvider = adoptNS([[UIItemProvider alloc] init]);
503     NSData *htmlData = [@"<body contenteditable></body>" dataUsingEncoding:NSUTF8StringEncoding];
504     [simulatedHTMLItemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeHTML withData:htmlData];
505
506     RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
507     [dataInteractionSimulator setExternalItemProviders:@[ simulatedHTMLItemProvider.get() ]];
508     [dataInteractionSimulator runFrom:CGPointMake(200, 300) to:CGPointMake(100, 300)];
509
510     NSString *outputValue = [webView stringByEvaluatingJavaScript:@"output.value"];
511     EXPECT_WK_STREQ("text/html", outputValue.UTF8String);
512 }
513
514 TEST(DataInteractionTests, ExternalSourceZIPArchiveAndURLToSingleFileInput)
515 {
516     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
517     [webView synchronouslyLoadTestPageNamed:@"file-uploading"];
518
519     auto archiveProvider = adoptNS([[UIItemProvider alloc] init]);
520     [archiveProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeZipArchive withData:testZIPArchive()];
521
522     auto urlProvider = adoptNS([[UIItemProvider alloc] init]);
523     [urlProvider registerObject:[NSURL URLWithString:@"https://webkit.org"] visibility:UIItemProviderRepresentationOptionsVisibilityAll];
524
525     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
526     [dataInteractionSimulator setExternalItemProviders:@[ archiveProvider.get(), urlProvider.get() ]];
527     [dataInteractionSimulator runFrom:CGPointMake(200, 100) to:CGPointMake(100, 100)];
528
529     NSString *outputValue = [webView stringByEvaluatingJavaScript:@"output.value"];
530     EXPECT_WK_STREQ("application/zip", outputValue.UTF8String);
531 }
532
533 TEST(DataInteractionTests, ExternalSourceZIPArchiveToUploadArea)
534 {
535     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
536     [webView synchronouslyLoadTestPageNamed:@"file-uploading"];
537
538     auto itemProvider = adoptNS([[UIItemProvider alloc] init]);
539     [itemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeZipArchive withData:testZIPArchive()];
540
541     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
542     [dataInteractionSimulator setExternalItemProviders:@[ itemProvider.get() ]];
543     [dataInteractionSimulator runFrom:CGPointMake(200, 300) to:CGPointMake(100, 300)];
544
545     NSString *outputValue = [webView stringByEvaluatingJavaScript:@"output.value"];
546     EXPECT_WK_STREQ("application/zip", outputValue.UTF8String);
547 }
548
549 TEST(DataInteractionTests, ExternalSourceImageAndHTMLToSingleFileInput)
550 {
551     RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
552     [webView synchronouslyLoadTestPageNamed:@"file-uploading"];
553
554     RetainPtr<UIItemProvider> simulatedImageItemProvider = adoptNS([[UIItemProvider alloc] init]);
555     NSData *imageData = UIImageJPEGRepresentation(testIconImage(), 0.5);
556     [simulatedImageItemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeJPEG withData:imageData];
557
558     RetainPtr<UIItemProvider> simulatedHTMLItemProvider = adoptNS([[UIItemProvider alloc] init]);
559     NSData *htmlData = [@"<body contenteditable></body>" dataUsingEncoding:NSUTF8StringEncoding];
560     [simulatedHTMLItemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeHTML withData:htmlData];
561
562     RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
563     [dataInteractionSimulator setExternalItemProviders:@[ simulatedHTMLItemProvider.get(), simulatedImageItemProvider.get() ]];
564     [dataInteractionSimulator runFrom:CGPointMake(200, 100) to:CGPointMake(100, 100)];
565
566     NSString *outputValue = [webView stringByEvaluatingJavaScript:@"output.value"];
567     EXPECT_WK_STREQ("", outputValue.UTF8String);
568 }
569
570 TEST(DataInteractionTests, ExternalSourceImageAndHTMLToMultipleFileInput)
571 {
572     RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
573     [webView synchronouslyLoadTestPageNamed:@"file-uploading"];
574     [webView stringByEvaluatingJavaScript:@"input.setAttribute('multiple', '')"];
575
576     RetainPtr<UIItemProvider> simulatedImageItemProvider = adoptNS([[UIItemProvider alloc] init]);
577     NSData *imageData = UIImageJPEGRepresentation(testIconImage(), 0.5);
578     [simulatedImageItemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeJPEG withData:imageData];
579
580     RetainPtr<UIItemProvider> simulatedHTMLItemProvider = adoptNS([[UIItemProvider alloc] init]);
581     NSData *htmlData = [@"<body contenteditable></body>" dataUsingEncoding:NSUTF8StringEncoding];
582     [simulatedHTMLItemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeHTML withData:htmlData];
583
584     RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
585     [dataInteractionSimulator setExternalItemProviders:@[ simulatedHTMLItemProvider.get(), simulatedImageItemProvider.get() ]];
586     [dataInteractionSimulator runFrom:CGPointMake(200, 100) to:CGPointMake(100, 100)];
587
588     NSString *outputValue = [webView stringByEvaluatingJavaScript:@"output.value"];
589     EXPECT_WK_STREQ("image/jpeg, text/html", outputValue.UTF8String);
590 }
591
592 TEST(DataInteractionTests, ExternalSourceImageAndHTMLToUploadArea)
593 {
594     RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
595     [webView synchronouslyLoadTestPageNamed:@"file-uploading"];
596
597     RetainPtr<UIItemProvider> simulatedImageItemProvider = adoptNS([[UIItemProvider alloc] init]);
598     NSData *imageData = UIImageJPEGRepresentation(testIconImage(), 0.5);
599     [simulatedImageItemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeJPEG withData:imageData];
600
601     RetainPtr<UIItemProvider> firstSimulatedHTMLItemProvider = adoptNS([[UIItemProvider alloc] init]);
602     NSData *firstHTMLData = [@"<body contenteditable></body>" dataUsingEncoding:NSUTF8StringEncoding];
603     [firstSimulatedHTMLItemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeHTML withData:firstHTMLData];
604
605     RetainPtr<UIItemProvider> secondSimulatedHTMLItemProvider = adoptNS([[UIItemProvider alloc] init]);
606     NSData *secondHTMLData = [@"<html><body>hello world</body></html>" dataUsingEncoding:NSUTF8StringEncoding];
607     [secondSimulatedHTMLItemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeHTML withData:secondHTMLData];
608
609     RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
610     [dataInteractionSimulator setExternalItemProviders:@[ simulatedImageItemProvider.get(), firstSimulatedHTMLItemProvider.get(), secondSimulatedHTMLItemProvider.get() ]];
611     [dataInteractionSimulator runFrom:CGPointMake(200, 300) to:CGPointMake(100, 300)];
612
613     NSString *outputValue = [webView stringByEvaluatingJavaScript:@"output.value"];
614     EXPECT_WK_STREQ("image/jpeg, text/html, text/html", outputValue.UTF8String);
615 }
616
617 TEST(DataInteractionTests, ExternalSourceHTMLToContentEditable)
618 {
619     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
620     [webView synchronouslyLoadTestPageNamed:@"autofocus-contenteditable"];
621     [webView stringByEvaluatingJavaScript:@"getSelection().removeAllRanges()"];
622
623     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
624     auto itemProvider = adoptNS([[UIItemProvider alloc] init]);
625     NSData *htmlData = [@"<h1>This is a test</h1>" dataUsingEncoding:NSUTF8StringEncoding];
626     [itemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeHTML withData:htmlData];
627     [dataInteractionSimulator setExternalItemProviders:@[ itemProvider.get() ]];
628     [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
629
630     NSString *textContent = [webView stringByEvaluatingJavaScript:@"editor.textContent"];
631     EXPECT_WK_STREQ("This is a test", textContent.UTF8String);
632     EXPECT_TRUE([webView stringByEvaluatingJavaScript:@"!!editor.querySelector('h1')"].boolValue);
633 }
634
635 TEST(DataInteractionTests, ExternalSourceAttributedStringToContentEditable)
636 {
637     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
638     [webView synchronouslyLoadTestPageNamed:@"autofocus-contenteditable"];
639     [webView stringByEvaluatingJavaScript:@"getSelection().removeAllRanges()"];
640
641     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
642     NSDictionary *textAttributes = @{ NSFontAttributeName: [UIFont boldSystemFontOfSize:20] };
643     NSAttributedString *richText = [[NSAttributedString alloc] initWithString:@"This is a test" attributes:textAttributes];
644     auto itemProvider = adoptNS([[UIItemProvider alloc] initWithObject:richText]);
645     [dataInteractionSimulator setExternalItemProviders:@[ itemProvider.get() ]];
646     [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
647
648     EXPECT_WK_STREQ("This is a test", [webView stringByEvaluatingJavaScript:@"editor.textContent"].UTF8String);
649 }
650
651 TEST(DataInteractionTests, ExternalSourceMultipleURLsToContentEditable)
652 {
653     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
654     [webView synchronouslyLoadTestPageNamed:@"autofocus-contenteditable"];
655     [webView stringByEvaluatingJavaScript:@"getSelection().removeAllRanges()"];
656
657     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
658     auto firstItem = adoptNS([[UIItemProvider alloc] init]);
659     [firstItem registerObject:[NSURL URLWithString:@"https://www.apple.com/iphone/"] visibility:UIItemProviderRepresentationOptionsVisibilityAll];
660     auto secondItem = adoptNS([[UIItemProvider alloc] init]);
661     [secondItem registerObject:[NSURL URLWithString:@"https://www.apple.com/mac/"] visibility:UIItemProviderRepresentationOptionsVisibilityAll];
662     auto thirdItem = adoptNS([[UIItemProvider alloc] init]);
663     [thirdItem registerObject:[NSURL URLWithString:@"https://webkit.org/"] visibility:UIItemProviderRepresentationOptionsVisibilityAll];
664     [dataInteractionSimulator setExternalItemProviders:@[ firstItem.get(), secondItem.get(), thirdItem.get() ]];
665     [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
666
667     NSArray *separatedLinks = [[webView stringByEvaluatingJavaScript:@"editor.textContent"] componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
668     EXPECT_EQ(3UL, separatedLinks.count);
669     EXPECT_WK_STREQ("https://www.apple.com/iphone/", separatedLinks[0]);
670     EXPECT_WK_STREQ("https://www.apple.com/mac/", separatedLinks[1]);
671     EXPECT_WK_STREQ("https://webkit.org/", separatedLinks[2]);
672 }
673
674 TEST(DataInteractionTests, RespectsExternalSourceFidelityRankings)
675 {
676     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
677     [webView synchronouslyLoadTestPageNamed:@"autofocus-contenteditable"];
678     [webView stringByEvaluatingJavaScript:@"getSelection().removeAllRanges()"];
679
680     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
681
682     // Here, our source item provider vends two representations: plain text, and then an image. If we don't respect the
683     // fidelity order requested by the source, we'll end up assuming that the image is a higher fidelity representation
684     // than the plain text, and erroneously insert the image. If we respect source fidelities, we'll insert text rather
685     // than an image.
686     auto simulatedItemProviderWithTextFirst = adoptNS([[UIItemProvider alloc] init]);
687     [simulatedItemProviderWithTextFirst registerObject:@"Hello world" visibility:UIItemProviderRepresentationOptionsVisibilityAll];
688     [simulatedItemProviderWithTextFirst registerObject:testIconImage() visibility:UIItemProviderRepresentationOptionsVisibilityAll];
689     [dataInteractionSimulator setExternalItemProviders:@[ simulatedItemProviderWithTextFirst.get() ]];
690
691     [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
692     EXPECT_WK_STREQ("Hello world", [webView stringByEvaluatingJavaScript:@"editor.textContent"]);
693     EXPECT_FALSE([webView editorContainsImageElement]);
694     [webView stringByEvaluatingJavaScript:@"editor.innerHTML = ''"];
695
696     // Now we register the item providers in reverse, and expect the image to be inserted instead of text.
697     auto simulatedItemProviderWithImageFirst = adoptNS([[UIItemProvider alloc] init]);
698     [simulatedItemProviderWithImageFirst registerObject:testIconImage() visibility:UIItemProviderRepresentationOptionsVisibilityAll];
699     [simulatedItemProviderWithImageFirst registerObject:@"Hello world" visibility:UIItemProviderRepresentationOptionsVisibilityAll];
700     [dataInteractionSimulator setExternalItemProviders:@[ simulatedItemProviderWithImageFirst.get() ]];
701
702     [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
703     EXPECT_WK_STREQ("", [webView stringByEvaluatingJavaScript:@"editor.textContent"]);
704     EXPECT_TRUE([webView editorContainsImageElement]);
705 }
706
707 TEST(DataInteractionTests, ExternalSourceUTF8PlainTextOnly)
708 {
709     RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
710     [webView synchronouslyLoadTestPageNamed:@"autofocus-contenteditable"];
711
712     NSString *textPayload = @"Ceci n'est pas une string";
713     RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
714     RetainPtr<UIItemProvider> simulatedItemProvider = adoptNS([[UIItemProvider alloc] init]);
715     [simulatedItemProvider registerDataRepresentationForTypeIdentifier:(__bridge NSString *)kUTTypeUTF8PlainText options:nil loadHandler:^NSProgress *(UIItemProviderDataLoadCompletionBlock completionBlock)
716     {
717         completionBlock([textPayload dataUsingEncoding:NSUTF8StringEncoding], nil);
718         return [NSProgress discreteProgressWithTotalUnitCount:100];
719     }];
720     [dataInteractionSimulator setExternalItemProviders:@[ simulatedItemProvider.get() ]];
721     [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
722     EXPECT_WK_STREQ(textPayload.UTF8String, [webView stringByEvaluatingJavaScript:@"editor.textContent"].UTF8String);
723     checkSelectionRectsWithLogging(@[ makeCGRectValue(1, 201, 1936, 227) ], [dataInteractionSimulator finalSelectionRects]);
724 }
725
726 TEST(DataInteractionTests, ExternalSourceJPEGOnly)
727 {
728     RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
729     [webView synchronouslyLoadTestPageNamed:@"autofocus-contenteditable"];
730
731     RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
732     RetainPtr<UIItemProvider> simulatedItemProvider = adoptNS([[UIItemProvider alloc] init]);
733     [simulatedItemProvider registerDataRepresentationForTypeIdentifier:(__bridge NSString *)kUTTypeJPEG options:nil loadHandler:^NSProgress *(UIItemProviderDataLoadCompletionBlock completionBlock)
734     {
735         completionBlock(UIImageJPEGRepresentation(testIconImage(), 0.5), nil);
736         return [NSProgress discreteProgressWithTotalUnitCount:100];
737     }];
738     [dataInteractionSimulator setExternalItemProviders:@[ simulatedItemProvider.get() ]];
739     [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
740     EXPECT_TRUE([webView editorContainsImageElement]);
741     checkSelectionRectsWithLogging(@[ makeCGRectValue(1, 201, 215, 174) ], [dataInteractionSimulator finalSelectionRects]);
742 }
743
744 TEST(DataInteractionTests, ExternalSourceTitledNSURL)
745 {
746     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
747     [webView synchronouslyLoadTestPageNamed:@"autofocus-contenteditable"];
748     [webView stringByEvaluatingJavaScript:@"getSelection().removeAllRanges()"];
749
750     NSURL *titledURL = [NSURL URLWithString:@"https://www.apple.com"];
751     titledURL._title = @"Apple";
752     auto simulatedItemProvider = adoptNS([[UIItemProvider alloc] init]);
753     [simulatedItemProvider registerObject:titledURL visibility:UIItemProviderRepresentationOptionsVisibilityAll];
754
755     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
756     [dataInteractionSimulator setExternalItemProviders:@[ simulatedItemProvider.get() ]];
757     [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
758
759     EXPECT_WK_STREQ("Apple", [webView stringByEvaluatingJavaScript:@"editor.querySelector('a').textContent"]);
760     EXPECT_WK_STREQ("https://www.apple.com/", [webView stringByEvaluatingJavaScript:@"editor.querySelector('a').href"]);
761 }
762
763 TEST(DataInteractionTests, ExternalSourceFileURL)
764 {
765     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
766     [webView synchronouslyLoadTestPageNamed:@"autofocus-contenteditable"];
767     [webView stringByEvaluatingJavaScript:@"getSelection().removeAllRanges()"];
768
769     NSURL *URL = [NSURL URLWithString:@"file:///some/file/that/is/not/real"];
770     UIItemProvider *simulatedItemProvider = [UIItemProvider itemProviderWithURL:URL title:@""];
771
772     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
773     [dataInteractionSimulator setExternalItemProviders:@[ simulatedItemProvider ]];
774     [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
775
776     EXPECT_FALSE([[webView stringByEvaluatingJavaScript:@"!!editor.querySelector('a')"] boolValue]);
777     EXPECT_WK_STREQ("Hello world\nfile:///some/file/that/is/not/real", [webView stringByEvaluatingJavaScript:@"document.body.innerText"]);
778 }
779
780 TEST(DataInteractionTests, ExternalSourceOverrideDropFileUpload)
781 {
782     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
783     [webView synchronouslyLoadTestPageNamed:@"file-uploading"];
784
785     auto simulatedImageItemProvider = adoptNS([[UIItemProvider alloc] init]);
786     NSData *imageData = UIImageJPEGRepresentation(testIconImage(), 0.5);
787     [simulatedImageItemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeJPEG withData:imageData];
788
789     auto simulatedHTMLItemProvider = adoptNS([[UIItemProvider alloc] init]);
790     NSData *firstHTMLData = [@"<body contenteditable></body>" dataUsingEncoding:NSUTF8StringEncoding];
791     [simulatedHTMLItemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeHTML withData:firstHTMLData];
792
793     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
794     [dataInteractionSimulator setOverridePerformDropBlock:^NSArray<UIDragItem *> *(id <UIDropSession> session)
795     {
796         EXPECT_EQ(2UL, session.items.count);
797         UIDragItem *firstItem = session.items[0];
798         UIDragItem *secondItem = session.items[1];
799         EXPECT_TRUE([firstItem.itemProvider.registeredTypeIdentifiers isEqual:@[ (NSString *)kUTTypeJPEG ]]);
800         EXPECT_TRUE([secondItem.itemProvider.registeredTypeIdentifiers isEqual:@[ (NSString *)kUTTypeHTML ]]);
801         return @[ secondItem ];
802     }];
803     [dataInteractionSimulator setExternalItemProviders:@[ simulatedImageItemProvider.get(), simulatedHTMLItemProvider.get() ]];
804     [dataInteractionSimulator runFrom:CGPointMake(200, 300) to:CGPointMake(100, 300)];
805
806     NSString *outputValue = [webView stringByEvaluatingJavaScript:@"output.value"];
807     EXPECT_WK_STREQ("text/html", outputValue.UTF8String);
808 }
809
810 TEST(DataInteractionTests, ExternalSourceOverrideDropInsertURL)
811 {
812     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
813     [webView synchronouslyLoadTestPageNamed:@"autofocus-contenteditable"];
814     [webView stringByEvaluatingJavaScript:@"getSelection().removeAllRanges()"];
815
816     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
817     [dataInteractionSimulator setOverridePerformDropBlock:^NSArray<UIDragItem *> *(id <UIDropSession> session)
818     {
819         NSMutableArray<UIDragItem *> *allowedItems = [NSMutableArray array];
820         for (UIDragItem *item in session.items) {
821             if ([item.itemProvider.registeredTypeIdentifiers containsObject:(NSString *)kUTTypeURL])
822                 [allowedItems addObject:item];
823         }
824         EXPECT_EQ(1UL, allowedItems.count);
825         return allowedItems;
826     }];
827
828     auto firstItemProvider = adoptNS([[UIItemProvider alloc] init]);
829     [firstItemProvider registerObject:@"This is a string." visibility:UIItemProviderRepresentationOptionsVisibilityAll];
830     auto secondItemProvider = adoptNS([[UIItemProvider alloc] init]);
831     [secondItemProvider registerObject:[NSURL URLWithString:@"https://webkit.org/"] visibility:UIItemProviderRepresentationOptionsVisibilityAll];
832     [dataInteractionSimulator setExternalItemProviders:@[ firstItemProvider.get(), secondItemProvider.get() ]];
833     [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
834
835     EXPECT_WK_STREQ("https://webkit.org/", [webView stringByEvaluatingJavaScript:@"editor.textContent"]);
836 }
837
838 TEST(DataInteractionTests, OverrideDataInteractionOperation)
839 {
840     RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
841     [webView synchronouslyLoadTestPageNamed:@"simple"];
842
843     RetainPtr<UIItemProvider> simulatedItemProvider = adoptNS([[UIItemProvider alloc] init]);
844     [simulatedItemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeHTML withData:[@"<body></body>" dataUsingEncoding:NSUTF8StringEncoding]];
845
846     __block bool finishedLoadingData = false;
847     RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
848     [dataInteractionSimulator setExternalItemProviders:@[ simulatedItemProvider.get() ]];
849     [dataInteractionSimulator setOverrideDataInteractionOperationBlock:^NSUInteger(NSUInteger operation, id session)
850     {
851         EXPECT_EQ(0U, operation);
852         return 1;
853     }];
854     [dataInteractionSimulator setDataInteractionOperationCompletionBlock:^(BOOL handled, NSArray *itemProviders) {
855         EXPECT_FALSE(handled);
856         [itemProviders.firstObject loadDataRepresentationForTypeIdentifier:(NSString *)kUTTypeHTML completionHandler:^(NSData *data, NSError *error) {
857             NSString *text = [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease];
858             EXPECT_WK_STREQ("<body></body>", text.UTF8String);
859             EXPECT_FALSE(!!error);
860             finishedLoadingData = true;
861         }];
862     }];
863     [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
864     TestWebKitAPI::Util::run(&finishedLoadingData);
865 }
866
867 TEST(DataInteractionTests, InjectedBundleOverridePerformTwoStepDrop)
868 {
869     WKWebViewConfiguration *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"BundleEditingDelegatePlugIn"];
870     [configuration.processPool _setObject:@YES forBundleParameter:@"BundleOverridePerformTwoStepDrop"];
871
872     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500) configuration:configuration]);
873     [webView loadTestPageNamed:@"autofocus-contenteditable"];
874     [webView stringByEvaluatingJavaScript:@"getSelection().removeAllRanges()"];
875
876     auto simulatedItemProvider = adoptNS([[UIItemProvider alloc] init]);
877     [simulatedItemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeUTF8PlainText options:nil loadHandler:^NSProgress *(UIItemProviderDataLoadCompletionBlock completionBlock)
878     {
879         completionBlock([@"Hello world" dataUsingEncoding:NSUTF8StringEncoding], nil);
880         return [NSProgress discreteProgressWithTotalUnitCount:100];
881     }];
882
883     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
884     [dataInteractionSimulator setExternalItemProviders:@[ simulatedItemProvider.get() ]];
885     [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
886
887     EXPECT_EQ(0UL, [webView stringByEvaluatingJavaScript:@"editor.textContent"].length);
888 }
889
890 TEST(DataInteractionTests, InjectedBundleAllowPerformTwoStepDrop)
891 {
892     WKWebViewConfiguration *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"BundleEditingDelegatePlugIn"];
893     [configuration.processPool _setObject:@NO forBundleParameter:@"BundleOverridePerformTwoStepDrop"];
894
895     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500) configuration:configuration]);
896     [webView loadTestPageNamed:@"autofocus-contenteditable"];
897     [webView stringByEvaluatingJavaScript:@"getSelection().removeAllRanges()"];
898
899     auto simulatedItemProvider = adoptNS([[UIItemProvider alloc] init]);
900     [simulatedItemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeUTF8PlainText options:nil loadHandler:^NSProgress *(UIItemProviderDataLoadCompletionBlock completionBlock)
901     {
902         completionBlock([@"Hello world" dataUsingEncoding:NSUTF8StringEncoding], nil);
903         return [NSProgress discreteProgressWithTotalUnitCount:100];
904     }];
905
906     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
907     [dataInteractionSimulator setExternalItemProviders:@[ simulatedItemProvider.get() ]];
908     [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
909
910     EXPECT_WK_STREQ("Hello world", [webView stringByEvaluatingJavaScript:@"editor.textContent"].UTF8String);
911 }
912
913 TEST(DataInteractionTests, InjectedBundleImageElementData)
914 {
915     WKWebViewConfiguration *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"BundleEditingDelegatePlugIn"];
916     [configuration _setAttachmentElementEnabled:YES];
917     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500) configuration:configuration]);
918     [webView synchronouslyLoadTestPageNamed:@"image-and-contenteditable"];
919
920     __block RetainPtr<NSString> injectedString;
921     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
922     [dataInteractionSimulator setConvertItemProvidersBlock:^NSArray *(UIItemProvider *itemProvider, NSArray *, NSDictionary *data)
923     {
924         injectedString = adoptNS([[NSString alloc] initWithData:data[InjectedBundlePasteboardDataType] encoding:NSUTF8StringEncoding]);
925         return @[ itemProvider ];
926     }];
927
928     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 250)];
929
930     EXPECT_WK_STREQ("hello", [injectedString UTF8String]);
931 }
932
933 TEST(DataInteractionTests, InjectedBundleAttachmentElementData)
934 {
935     WKWebViewConfiguration *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"BundleEditingDelegatePlugIn"];
936     [configuration _setAttachmentElementEnabled:YES];
937     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500) configuration:configuration]);
938     [webView synchronouslyLoadTestPageNamed:@"attachment-element"];
939
940     __block RetainPtr<NSString> injectedString;
941     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
942     [dataInteractionSimulator setConvertItemProvidersBlock:^NSArray *(UIItemProvider *itemProvider, NSArray *, NSDictionary *data)
943     {
944         injectedString = adoptNS([[NSString alloc] initWithData:data[InjectedBundlePasteboardDataType] encoding:NSUTF8StringEncoding]);
945         return @[ itemProvider ];
946     }];
947
948     [dataInteractionSimulator runFrom:CGPointMake(50, 50) to:CGPointMake(50, 400)];
949
950     EXPECT_WK_STREQ("hello", [injectedString UTF8String]);
951     EXPECT_TRUE([webView stringByEvaluatingJavaScript:@"getSelection().isCollapsed"].boolValue);
952 }
953
954 TEST(DataInteractionTests, LargeImageToTargetDiv)
955 {
956     auto testWebViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
957     [[testWebViewConfiguration preferences] _setLargeImageAsyncDecodingEnabled:NO];
958
959     RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500) configuration:testWebViewConfiguration.get()]);
960     [webView synchronouslyLoadTestPageNamed:@"div-and-large-image"];
961
962     RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
963     [dataInteractionSimulator runFrom:CGPointMake(200, 400) to:CGPointMake(200, 150)];
964     EXPECT_WK_STREQ("PASS", [webView stringByEvaluatingJavaScript:@"target.textContent"].UTF8String);
965     checkTypeIdentifierPrecedesOtherTypeIdentifier(dataInteractionSimulator.get(), (NSString *)kUTTypePNG, (NSString *)kUTTypeFileURL);
966     checkSuggestedNameAndEstimatedSize(dataInteractionSimulator.get(), @"large-red-square.png", { 2000, 2000 });
967 }
968
969 TEST(DataInteractionTests, LinkWithEmptyHREF)
970 {
971     RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
972     [webView synchronouslyLoadTestPageNamed:@"link-and-input"];
973     [webView stringByEvaluatingJavaScript:@"document.querySelector('a').href = ''"];
974
975     RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
976     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
977
978     EXPECT_EQ(DataInteractionCancelled, [dataInteractionSimulator phase]);
979     EXPECT_WK_STREQ("", [webView editorValue].UTF8String);
980 }
981
982 TEST(DataInteractionTests, CancelledLiftDoesNotCauseSubsequentDragsToFail)
983 {
984     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
985     [webView synchronouslyLoadTestPageNamed:@"link-and-target-div"];
986
987     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
988     [dataInteractionSimulator setConvertItemProvidersBlock:^NSArray *(UIItemProvider *, NSArray *, NSDictionary *)
989     {
990         return @[ ];
991     }];
992     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
993     EXPECT_EQ(DataInteractionCancelled, [dataInteractionSimulator phase]);
994     EXPECT_WK_STREQ("", [webView stringByEvaluatingJavaScript:@"target.textContent"]);
995     NSString *outputText = [webView stringByEvaluatingJavaScript:@"output.textContent"];
996     checkStringArraysAreEqual(@[@"dragstart", @"dragend"], [outputText componentsSeparatedByString:@" "]);
997
998     [webView stringByEvaluatingJavaScript:@"output.innerHTML = ''"];
999     [dataInteractionSimulator setConvertItemProvidersBlock:^NSArray *(UIItemProvider *itemProvider, NSArray *, NSDictionary *)
1000     {
1001         return @[ itemProvider ];
1002     }];
1003     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
1004     EXPECT_WK_STREQ("PASS", [webView stringByEvaluatingJavaScript:@"target.textContent"]);
1005     [webView stringByEvaluatingJavaScript:@"output.textContent"];
1006     checkStringArraysAreEqual(@[@"dragstart", @"dragend"], [outputText componentsSeparatedByString:@" "]);
1007 }
1008
1009 TEST(DataInteractionTests, CustomActionSheetPopover)
1010 {
1011     RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
1012     [webView synchronouslyLoadTestPageNamed:@"link-and-target-div"];
1013
1014     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
1015     [dataInteractionSimulator setShouldEnsureUIApplication:YES];
1016
1017     __block BOOL didInvokeCustomActionSheet = NO;
1018     [dataInteractionSimulator setShowCustomActionSheetBlock:^BOOL(_WKActivatedElementInfo *element)
1019     {
1020         EXPECT_EQ(_WKActivatedElementTypeLink, element.type);
1021         EXPECT_WK_STREQ("Hello world", element.title.UTF8String);
1022         didInvokeCustomActionSheet = YES;
1023         return YES;
1024     }];
1025     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
1026     EXPECT_TRUE(didInvokeCustomActionSheet);
1027     EXPECT_WK_STREQ("PASS", [webView stringByEvaluatingJavaScript:@"target.textContent"].UTF8String);
1028 }
1029
1030 TEST(DataInteractionTests, UnresponsivePageDoesNotHangUI)
1031 {
1032     _WKProcessPoolConfiguration *processPoolConfiguration = [[[_WKProcessPoolConfiguration alloc] init] autorelease];
1033     processPoolConfiguration.ignoreSynchronousMessagingTimeoutsForTesting = YES;
1034
1035     RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500) configuration:[[[WKWebViewConfiguration alloc] init] autorelease] processPoolConfiguration:processPoolConfiguration]);
1036     [webView synchronouslyLoadTestPageNamed:@"simple"];
1037     [webView evaluateJavaScript:@"while(1);" completionHandler:nil];
1038
1039     // The test passes if we can prepare for data interaction without timing out.
1040     [webView _simulatePrepareForDataInteractionSession:nil completion:^() { }];
1041 }
1042
1043 TEST(DataInteractionTests, WebItemProviderPasteboardLoading)
1044 {
1045     static NSString *fastString = @"This data loads quickly";
1046     static NSString *slowString = @"This data loads slowly";
1047
1048     WebItemProviderPasteboard *pasteboard = [WebItemProviderPasteboard sharedInstance];
1049     auto fastItem = adoptNS([[UIItemProvider alloc] init]);
1050     [fastItem registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeUTF8PlainText options:nil loadHandler:^NSProgress *(UIItemProviderDataLoadCompletionBlock completionBlock)
1051     {
1052         completionBlock([fastString dataUsingEncoding:NSUTF8StringEncoding], nil);
1053         return nil;
1054     }];
1055
1056     auto slowItem = adoptNS([[UIItemProvider alloc] init]);
1057     [slowItem registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeUTF8PlainText options:nil loadHandler:^NSProgress *(UIItemProviderDataLoadCompletionBlock completionBlock)
1058     {
1059         sleep(2);
1060         completionBlock([slowString dataUsingEncoding:NSUTF8StringEncoding], nil);
1061         return nil;
1062     }];
1063
1064     __block bool hasRunFirstCompletionBlock = false;
1065     pasteboard.itemProviders = @[ fastItem.get(), slowItem.get() ];
1066     [pasteboard doAfterLoadingProvidedContentIntoFileURLs:^(NSArray<NSURL *> *urls) {
1067         EXPECT_EQ(2UL, urls.count);
1068         auto firstString = adoptNS([[NSString alloc] initWithContentsOfURL:urls[0] encoding:NSUTF8StringEncoding error:nil]);
1069         auto secondString = adoptNS([[NSString alloc] initWithContentsOfURL:urls[1] encoding:NSUTF8StringEncoding error:nil]);
1070         EXPECT_WK_STREQ(fastString, [firstString UTF8String]);
1071         EXPECT_WK_STREQ(slowString, [secondString UTF8String]);
1072         hasRunFirstCompletionBlock = true;
1073     } synchronousTimeout:600];
1074     EXPECT_TRUE(hasRunFirstCompletionBlock);
1075
1076     __block bool hasRunSecondCompletionBlock = false;
1077     [pasteboard doAfterLoadingProvidedContentIntoFileURLs:^(NSArray<NSURL *> *urls) {
1078         EXPECT_EQ(2UL, urls.count);
1079         auto firstString = adoptNS([[NSString alloc] initWithContentsOfURL:urls[0] encoding:NSUTF8StringEncoding error:nil]);
1080         auto secondString = adoptNS([[NSString alloc] initWithContentsOfURL:urls[1] encoding:NSUTF8StringEncoding error:nil]);
1081         EXPECT_WK_STREQ(fastString, [firstString UTF8String]);
1082         EXPECT_WK_STREQ(slowString, [secondString UTF8String]);
1083         hasRunSecondCompletionBlock = true;
1084     } synchronousTimeout:0];
1085     EXPECT_FALSE(hasRunSecondCompletionBlock);
1086     TestWebKitAPI::Util::run(&hasRunSecondCompletionBlock);
1087 }
1088
1089 TEST(DataInteractionTests, DoNotCrashWhenSelectionMovesOffscreenAfterDragStart)
1090 {
1091     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
1092     [webView synchronouslyLoadTestPageNamed:@"dragstart-change-selection-offscreen"];
1093
1094     auto simulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
1095     [simulator runFrom:CGPointMake(100, 100) to:CGPointMake(100, 100)];
1096
1097     EXPECT_WK_STREQ("FAR OFFSCREEN", [webView stringByEvaluatingJavaScript:@"getSelection().getRangeAt(0).toString()"]);
1098 }
1099
1100 } // namespace TestWebKitAPI
1101
1102 #endif // ENABLE(DATA_INTERACTION)