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