[iOS WK2] Add a version of DataInteractionTests.ExternalSourceAttributedStringToConte...
[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, DISABLED_ExternalSourceBoldSystemAttributedStringToContentEditable)
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, ExternalSourceColoredAttributedStringToContentEditable)
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     NSDictionary *textAttributes = @{ NSForegroundColorAttributeName: [UIColor redColor] };
712     NSAttributedString *richText = [[NSAttributedString alloc] initWithString:@"This is a test" attributes:textAttributes];
713     auto itemProvider = adoptNS([[UIItemProvider alloc] initWithObject:richText]);
714     [dataInteractionSimulator setExternalItemProviders:@[ itemProvider.get() ]];
715     [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
716
717     EXPECT_WK_STREQ("rgb(255, 0, 0)", [webView stringByEvaluatingJavaScript:@"getComputedStyle(document.querySelector('p')).color"]);
718     EXPECT_WK_STREQ("This is a test", [webView stringByEvaluatingJavaScript:@"editor.textContent"].UTF8String);
719 }
720
721 TEST(DataInteractionTests, ExternalSourceMultipleURLsToContentEditable)
722 {
723     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
724     [webView synchronouslyLoadTestPageNamed:@"autofocus-contenteditable"];
725     [webView stringByEvaluatingJavaScript:@"getSelection().removeAllRanges()"];
726
727     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
728     auto firstItem = adoptNS([[UIItemProvider alloc] init]);
729     [firstItem registerObject:[NSURL URLWithString:@"https://www.apple.com/iphone/"] visibility:UIItemProviderRepresentationOptionsVisibilityAll];
730     auto secondItem = adoptNS([[UIItemProvider alloc] init]);
731     [secondItem registerObject:[NSURL URLWithString:@"https://www.apple.com/mac/"] visibility:UIItemProviderRepresentationOptionsVisibilityAll];
732     auto thirdItem = adoptNS([[UIItemProvider alloc] init]);
733     [thirdItem registerObject:[NSURL URLWithString:@"https://webkit.org/"] visibility:UIItemProviderRepresentationOptionsVisibilityAll];
734     [dataInteractionSimulator setExternalItemProviders:@[ firstItem.get(), secondItem.get(), thirdItem.get() ]];
735     [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
736
737     NSArray *separatedLinks = [[webView stringByEvaluatingJavaScript:@"editor.textContent"] componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
738     EXPECT_EQ(3UL, separatedLinks.count);
739     EXPECT_WK_STREQ("https://www.apple.com/iphone/", separatedLinks[0]);
740     EXPECT_WK_STREQ("https://www.apple.com/mac/", separatedLinks[1]);
741     EXPECT_WK_STREQ("https://webkit.org/", separatedLinks[2]);
742 }
743
744 TEST(DataInteractionTests, RespectsExternalSourceFidelityRankings)
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     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
751
752     // Here, our source item provider vends two representations: plain text, and then an image. If we don't respect the
753     // fidelity order requested by the source, we'll end up assuming that the image is a higher fidelity representation
754     // than the plain text, and erroneously insert the image. If we respect source fidelities, we'll insert text rather
755     // than an image.
756     auto simulatedItemProviderWithTextFirst = adoptNS([[UIItemProvider alloc] init]);
757     [simulatedItemProviderWithTextFirst registerObject:@"Hello world" visibility:UIItemProviderRepresentationOptionsVisibilityAll];
758     [simulatedItemProviderWithTextFirst registerObject:testIconImage() visibility:UIItemProviderRepresentationOptionsVisibilityAll];
759     [dataInteractionSimulator setExternalItemProviders:@[ simulatedItemProviderWithTextFirst.get() ]];
760
761     [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
762     EXPECT_WK_STREQ("Hello world", [webView stringByEvaluatingJavaScript:@"editor.textContent"]);
763     EXPECT_FALSE([webView editorContainsImageElement]);
764     [webView stringByEvaluatingJavaScript:@"editor.innerHTML = ''"];
765
766     // Now we register the item providers in reverse, and expect the image to be inserted instead of text.
767     auto simulatedItemProviderWithImageFirst = adoptNS([[UIItemProvider alloc] init]);
768     [simulatedItemProviderWithImageFirst registerObject:testIconImage() visibility:UIItemProviderRepresentationOptionsVisibilityAll];
769     [simulatedItemProviderWithImageFirst registerObject:@"Hello world" visibility:UIItemProviderRepresentationOptionsVisibilityAll];
770     [dataInteractionSimulator setExternalItemProviders:@[ simulatedItemProviderWithImageFirst.get() ]];
771
772     [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
773     EXPECT_WK_STREQ("", [webView stringByEvaluatingJavaScript:@"editor.textContent"]);
774     EXPECT_TRUE([webView editorContainsImageElement]);
775 }
776
777 TEST(DataInteractionTests, ExternalSourceUTF8PlainTextOnly)
778 {
779     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
780     [webView synchronouslyLoadTestPageNamed:@"autofocus-contenteditable"];
781
782     NSString *textPayload = @"Ceci n'est pas une string";
783     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
784     auto simulatedItemProvider = adoptNS([[UIItemProvider alloc] init]);
785     [simulatedItemProvider registerDataRepresentationForTypeIdentifier:(__bridge NSString *)kUTTypeUTF8PlainText options:nil loadHandler:^NSProgress *(UIItemProviderDataLoadCompletionBlock completionBlock)
786     {
787         completionBlock([textPayload dataUsingEncoding:NSUTF8StringEncoding], nil);
788         return [NSProgress discreteProgressWithTotalUnitCount:100];
789     }];
790     [dataInteractionSimulator setExternalItemProviders:@[ simulatedItemProvider.get() ]];
791     [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
792     EXPECT_WK_STREQ(textPayload.UTF8String, [webView stringByEvaluatingJavaScript:@"editor.textContent"].UTF8String);
793     checkSelectionRectsWithLogging(@[ makeCGRectValue(1, 201, 1936, 227) ], [dataInteractionSimulator finalSelectionRects]);
794 }
795
796 TEST(DataInteractionTests, ExternalSourceJPEGOnly)
797 {
798     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
799     [webView synchronouslyLoadTestPageNamed:@"autofocus-contenteditable"];
800
801     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
802     auto simulatedItemProvider = adoptNS([[UIItemProvider alloc] init]);
803     [simulatedItemProvider registerDataRepresentationForTypeIdentifier:(__bridge NSString *)kUTTypeJPEG options:nil loadHandler:^NSProgress *(UIItemProviderDataLoadCompletionBlock completionBlock)
804     {
805         completionBlock(UIImageJPEGRepresentation(testIconImage(), 0.5), nil);
806         return [NSProgress discreteProgressWithTotalUnitCount:100];
807     }];
808     [dataInteractionSimulator setExternalItemProviders:@[ simulatedItemProvider.get() ]];
809     [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
810     EXPECT_TRUE([webView editorContainsImageElement]);
811     checkSelectionRectsWithLogging(@[ makeCGRectValue(1, 201, 215, 174) ], [dataInteractionSimulator finalSelectionRects]);
812 }
813
814 TEST(DataInteractionTests, ExternalSourceTitledNSURL)
815 {
816     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
817     [webView synchronouslyLoadTestPageNamed:@"autofocus-contenteditable"];
818     [webView stringByEvaluatingJavaScript:@"getSelection().removeAllRanges()"];
819
820     NSURL *titledURL = [NSURL URLWithString:@"https://www.apple.com"];
821     titledURL._title = @"Apple";
822     auto simulatedItemProvider = adoptNS([[UIItemProvider alloc] init]);
823     [simulatedItemProvider registerObject:titledURL visibility:UIItemProviderRepresentationOptionsVisibilityAll];
824
825     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
826     [dataInteractionSimulator setExternalItemProviders:@[ simulatedItemProvider.get() ]];
827     [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
828
829     EXPECT_WK_STREQ("Apple", [webView stringByEvaluatingJavaScript:@"editor.querySelector('a').textContent"]);
830     EXPECT_WK_STREQ("https://www.apple.com/", [webView stringByEvaluatingJavaScript:@"editor.querySelector('a').href"]);
831 }
832
833 TEST(DataInteractionTests, ExternalSourceFileURL)
834 {
835     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
836     [webView synchronouslyLoadTestPageNamed:@"autofocus-contenteditable"];
837     [webView stringByEvaluatingJavaScript:@"getSelection().removeAllRanges()"];
838
839     NSURL *URL = [NSURL URLWithString:@"file:///some/file/that/is/not/real"];
840     UIItemProvider *simulatedItemProvider = [UIItemProvider itemProviderWithURL:URL title:@""];
841
842     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
843     [dataInteractionSimulator setExternalItemProviders:@[ simulatedItemProvider ]];
844     [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
845
846     EXPECT_FALSE([[webView stringByEvaluatingJavaScript:@"!!editor.querySelector('a')"] boolValue]);
847     EXPECT_WK_STREQ("Hello world\nfile:///some/file/that/is/not/real", [webView stringByEvaluatingJavaScript:@"document.body.innerText"]);
848 }
849
850 TEST(DataInteractionTests, ExternalSourceOverrideDropFileUpload)
851 {
852     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
853     [webView synchronouslyLoadTestPageNamed:@"file-uploading"];
854
855     auto simulatedImageItemProvider = adoptNS([[UIItemProvider alloc] init]);
856     NSData *imageData = UIImageJPEGRepresentation(testIconImage(), 0.5);
857     [simulatedImageItemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeJPEG withData:imageData];
858
859     auto simulatedHTMLItemProvider = adoptNS([[UIItemProvider alloc] init]);
860     NSData *firstHTMLData = [@"<body contenteditable></body>" dataUsingEncoding:NSUTF8StringEncoding];
861     [simulatedHTMLItemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeHTML withData:firstHTMLData];
862
863     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
864     [dataInteractionSimulator setOverridePerformDropBlock:^NSArray<UIDragItem *> *(id <UIDropSession> session)
865     {
866         EXPECT_EQ(2UL, session.items.count);
867         UIDragItem *firstItem = session.items[0];
868         UIDragItem *secondItem = session.items[1];
869         EXPECT_TRUE([firstItem.itemProvider.registeredTypeIdentifiers isEqual:@[ (NSString *)kUTTypeJPEG ]]);
870         EXPECT_TRUE([secondItem.itemProvider.registeredTypeIdentifiers isEqual:@[ (NSString *)kUTTypeHTML ]]);
871         return @[ secondItem ];
872     }];
873     [dataInteractionSimulator setExternalItemProviders:@[ simulatedImageItemProvider.get(), simulatedHTMLItemProvider.get() ]];
874     [dataInteractionSimulator runFrom:CGPointMake(200, 300) to:CGPointMake(100, 300)];
875
876     NSString *outputValue = [webView stringByEvaluatingJavaScript:@"output.value"];
877     EXPECT_WK_STREQ("text/html", outputValue.UTF8String);
878 }
879
880 TEST(DataInteractionTests, ExternalSourceOverrideDropInsertURL)
881 {
882     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
883     [webView synchronouslyLoadTestPageNamed:@"autofocus-contenteditable"];
884     [webView stringByEvaluatingJavaScript:@"getSelection().removeAllRanges()"];
885
886     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
887     [dataInteractionSimulator setOverridePerformDropBlock:^NSArray<UIDragItem *> *(id <UIDropSession> session)
888     {
889         NSMutableArray<UIDragItem *> *allowedItems = [NSMutableArray array];
890         for (UIDragItem *item in session.items) {
891             if ([item.itemProvider.registeredTypeIdentifiers containsObject:(NSString *)kUTTypeURL])
892                 [allowedItems addObject:item];
893         }
894         EXPECT_EQ(1UL, allowedItems.count);
895         return allowedItems;
896     }];
897
898     auto firstItemProvider = adoptNS([[UIItemProvider alloc] init]);
899     [firstItemProvider registerObject:@"This is a string." visibility:UIItemProviderRepresentationOptionsVisibilityAll];
900     auto secondItemProvider = adoptNS([[UIItemProvider alloc] init]);
901     [secondItemProvider registerObject:[NSURL URLWithString:@"https://webkit.org/"] visibility:UIItemProviderRepresentationOptionsVisibilityAll];
902     [dataInteractionSimulator setExternalItemProviders:@[ firstItemProvider.get(), secondItemProvider.get() ]];
903     [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
904
905     EXPECT_WK_STREQ("https://webkit.org/", [webView stringByEvaluatingJavaScript:@"editor.textContent"]);
906 }
907
908 TEST(DataInteractionTests, OverrideDataInteractionOperation)
909 {
910     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
911     [webView synchronouslyLoadTestPageNamed:@"simple"];
912
913     auto simulatedItemProvider = adoptNS([[UIItemProvider alloc] init]);
914     [simulatedItemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeHTML withData:[@"<body></body>" dataUsingEncoding:NSUTF8StringEncoding]];
915
916     __block bool finishedLoadingData = false;
917     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
918     [dataInteractionSimulator setExternalItemProviders:@[ simulatedItemProvider.get() ]];
919     [dataInteractionSimulator setOverrideDataInteractionOperationBlock:^NSUInteger(NSUInteger operation, id session)
920     {
921         EXPECT_EQ(0U, operation);
922         return 1;
923     }];
924     [dataInteractionSimulator setDataInteractionOperationCompletionBlock:^(BOOL handled, NSArray *itemProviders) {
925         EXPECT_FALSE(handled);
926         [itemProviders.firstObject loadDataRepresentationForTypeIdentifier:(NSString *)kUTTypeHTML completionHandler:^(NSData *data, NSError *error) {
927             NSString *text = [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease];
928             EXPECT_WK_STREQ("<body></body>", text.UTF8String);
929             EXPECT_FALSE(!!error);
930             finishedLoadingData = true;
931         }];
932     }];
933     [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
934     TestWebKitAPI::Util::run(&finishedLoadingData);
935 }
936
937 TEST(DataInteractionTests, InjectedBundleOverridePerformTwoStepDrop)
938 {
939     WKWebViewConfiguration *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"BundleEditingDelegatePlugIn"];
940     [configuration.processPool _setObject:@YES forBundleParameter:@"BundleOverridePerformTwoStepDrop"];
941
942     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500) configuration:configuration]);
943     [webView loadTestPageNamed:@"autofocus-contenteditable"];
944     [webView stringByEvaluatingJavaScript:@"getSelection().removeAllRanges()"];
945
946     auto simulatedItemProvider = adoptNS([[UIItemProvider alloc] init]);
947     [simulatedItemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeUTF8PlainText options:nil loadHandler:^NSProgress *(UIItemProviderDataLoadCompletionBlock completionBlock)
948     {
949         completionBlock([@"Hello world" dataUsingEncoding:NSUTF8StringEncoding], nil);
950         return [NSProgress discreteProgressWithTotalUnitCount:100];
951     }];
952
953     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
954     [dataInteractionSimulator setExternalItemProviders:@[ simulatedItemProvider.get() ]];
955     [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
956
957     EXPECT_EQ(0UL, [webView stringByEvaluatingJavaScript:@"editor.textContent"].length);
958 }
959
960 TEST(DataInteractionTests, InjectedBundleAllowPerformTwoStepDrop)
961 {
962     WKWebViewConfiguration *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"BundleEditingDelegatePlugIn"];
963     [configuration.processPool _setObject:@NO forBundleParameter:@"BundleOverridePerformTwoStepDrop"];
964
965     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500) configuration:configuration]);
966     [webView loadTestPageNamed:@"autofocus-contenteditable"];
967     [webView stringByEvaluatingJavaScript:@"getSelection().removeAllRanges()"];
968
969     auto simulatedItemProvider = adoptNS([[UIItemProvider alloc] init]);
970     [simulatedItemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeUTF8PlainText options:nil loadHandler:^NSProgress *(UIItemProviderDataLoadCompletionBlock completionBlock)
971     {
972         completionBlock([@"Hello world" dataUsingEncoding:NSUTF8StringEncoding], nil);
973         return [NSProgress discreteProgressWithTotalUnitCount:100];
974     }];
975
976     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
977     [dataInteractionSimulator setExternalItemProviders:@[ simulatedItemProvider.get() ]];
978     [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
979
980     EXPECT_WK_STREQ("Hello world", [webView stringByEvaluatingJavaScript:@"editor.textContent"].UTF8String);
981 }
982
983 TEST(DataInteractionTests, InjectedBundleImageElementData)
984 {
985     WKWebViewConfiguration *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"BundleEditingDelegatePlugIn"];
986     [configuration _setAttachmentElementEnabled:YES];
987     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500) configuration:configuration]);
988     [webView synchronouslyLoadTestPageNamed:@"image-and-contenteditable"];
989
990     __block RetainPtr<NSString> injectedString;
991     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
992     [dataInteractionSimulator setConvertItemProvidersBlock:^NSArray *(UIItemProvider *itemProvider, NSArray *, NSDictionary *data)
993     {
994         injectedString = adoptNS([[NSString alloc] initWithData:data[InjectedBundlePasteboardDataType] encoding:NSUTF8StringEncoding]);
995         return @[ itemProvider ];
996     }];
997
998     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 250)];
999
1000     EXPECT_WK_STREQ("hello", [injectedString UTF8String]);
1001 }
1002
1003 TEST(DataInteractionTests, InjectedBundleAttachmentElementData)
1004 {
1005     WKWebViewConfiguration *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"BundleEditingDelegatePlugIn"];
1006     [configuration _setAttachmentElementEnabled:YES];
1007     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500) configuration:configuration]);
1008     [webView synchronouslyLoadTestPageNamed:@"attachment-element"];
1009
1010     __block RetainPtr<NSString> injectedString;
1011     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
1012     [dataInteractionSimulator setConvertItemProvidersBlock:^NSArray *(UIItemProvider *itemProvider, NSArray *, NSDictionary *data)
1013     {
1014         injectedString = adoptNS([[NSString alloc] initWithData:data[InjectedBundlePasteboardDataType] encoding:NSUTF8StringEncoding]);
1015         return @[ itemProvider ];
1016     }];
1017
1018     [dataInteractionSimulator runFrom:CGPointMake(50, 50) to:CGPointMake(50, 400)];
1019
1020     EXPECT_WK_STREQ("hello", [injectedString UTF8String]);
1021     EXPECT_TRUE([webView stringByEvaluatingJavaScript:@"getSelection().isCollapsed"].boolValue);
1022 }
1023
1024 TEST(DataInteractionTests, LargeImageToTargetDiv)
1025 {
1026     auto testWebViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
1027     [[testWebViewConfiguration preferences] _setLargeImageAsyncDecodingEnabled:NO];
1028
1029     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500) configuration:testWebViewConfiguration.get()]);
1030     [webView synchronouslyLoadTestPageNamed:@"div-and-large-image"];
1031
1032     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
1033     [dataInteractionSimulator runFrom:CGPointMake(200, 400) to:CGPointMake(200, 150)];
1034     EXPECT_WK_STREQ("PASS", [webView stringByEvaluatingJavaScript:@"target.textContent"].UTF8String);
1035     checkTypeIdentifierAndIsNotOtherTypeIdentifier(dataInteractionSimulator.get(), (NSString *)kUTTypePNG, (NSString *)kUTTypeFileURL);
1036     checkEstimatedSize(dataInteractionSimulator.get(), { 2000, 2000 });
1037 }
1038
1039 TEST(DataInteractionTests, LinkWithEmptyHREF)
1040 {
1041     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
1042     [webView synchronouslyLoadTestPageNamed:@"link-and-input"];
1043     [webView stringByEvaluatingJavaScript:@"document.querySelector('a').href = ''"];
1044
1045     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
1046     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
1047
1048     EXPECT_EQ(DataInteractionCancelled, [dataInteractionSimulator phase]);
1049     EXPECT_WK_STREQ("", [webView editorValue].UTF8String);
1050 }
1051
1052 TEST(DataInteractionTests, CancelledLiftDoesNotCauseSubsequentDragsToFail)
1053 {
1054     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
1055     [webView synchronouslyLoadTestPageNamed:@"link-and-target-div"];
1056
1057     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
1058     [dataInteractionSimulator setConvertItemProvidersBlock:^NSArray *(UIItemProvider *, NSArray *, NSDictionary *)
1059     {
1060         return @[ ];
1061     }];
1062     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
1063     EXPECT_EQ(DataInteractionCancelled, [dataInteractionSimulator phase]);
1064     EXPECT_WK_STREQ("", [webView stringByEvaluatingJavaScript:@"target.textContent"]);
1065     NSString *outputText = [webView stringByEvaluatingJavaScript:@"output.textContent"];
1066     checkStringArraysAreEqual(@[@"dragstart", @"dragend"], [outputText componentsSeparatedByString:@" "]);
1067
1068     [webView stringByEvaluatingJavaScript:@"output.innerHTML = ''"];
1069     [dataInteractionSimulator setConvertItemProvidersBlock:^NSArray *(UIItemProvider *itemProvider, NSArray *, NSDictionary *)
1070     {
1071         return @[ itemProvider ];
1072     }];
1073     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
1074     EXPECT_WK_STREQ("PASS", [webView stringByEvaluatingJavaScript:@"target.textContent"]);
1075     [webView stringByEvaluatingJavaScript:@"output.textContent"];
1076     checkStringArraysAreEqual(@[@"dragstart", @"dragend"], [outputText componentsSeparatedByString:@" "]);
1077 }
1078
1079 TEST(DataInteractionTests, DoNotCrashWhenSelectionIsClearedInDragStart)
1080 {
1081     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
1082     [webView synchronouslyLoadTestPageNamed:@"dragstart-clear-selection"];
1083
1084     auto simulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
1085     [simulator runFrom:CGPointMake(100, 100) to:CGPointMake(100, 100)];
1086
1087     EXPECT_WK_STREQ("PASS", [webView stringByEvaluatingJavaScript:@"paragraph.textContent"]);
1088 }
1089
1090 TEST(DataInteractionTests, CustomActionSheetPopover)
1091 {
1092     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
1093     [webView synchronouslyLoadTestPageNamed:@"link-and-target-div"];
1094
1095     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
1096     [dataInteractionSimulator setShouldEnsureUIApplication:YES];
1097
1098     __block BOOL didInvokeCustomActionSheet = NO;
1099     [dataInteractionSimulator setShowCustomActionSheetBlock:^BOOL(_WKActivatedElementInfo *element)
1100     {
1101         EXPECT_EQ(_WKActivatedElementTypeLink, element.type);
1102         EXPECT_WK_STREQ("Hello world", element.title.UTF8String);
1103         didInvokeCustomActionSheet = YES;
1104         return YES;
1105     }];
1106     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
1107     EXPECT_TRUE(didInvokeCustomActionSheet);
1108     EXPECT_WK_STREQ("PASS", [webView stringByEvaluatingJavaScript:@"target.textContent"].UTF8String);
1109 }
1110
1111 TEST(DataInteractionTests, UnresponsivePageDoesNotHangUI)
1112 {
1113     _WKProcessPoolConfiguration *processPoolConfiguration = [[[_WKProcessPoolConfiguration alloc] init] autorelease];
1114     processPoolConfiguration.ignoreSynchronousMessagingTimeoutsForTesting = YES;
1115
1116     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500) configuration:[[[WKWebViewConfiguration alloc] init] autorelease] processPoolConfiguration:processPoolConfiguration]);
1117     [webView synchronouslyLoadTestPageNamed:@"simple"];
1118     [webView evaluateJavaScript:@"while(1);" completionHandler:nil];
1119
1120     // The test passes if we can prepare for data interaction without timing out.
1121     [webView _simulatePrepareForDataInteractionSession:nil completion:^() { }];
1122 }
1123
1124 TEST(DataInteractionTests, WebItemProviderPasteboardLoading)
1125 {
1126     static NSString *fastString = @"This data loads quickly";
1127     static NSString *slowString = @"This data loads slowly";
1128
1129     WebItemProviderPasteboard *pasteboard = [WebItemProviderPasteboard sharedInstance];
1130     auto fastItem = adoptNS([[UIItemProvider alloc] init]);
1131     [fastItem registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeUTF8PlainText options:nil loadHandler:^NSProgress *(UIItemProviderDataLoadCompletionBlock completionBlock)
1132     {
1133         completionBlock([fastString dataUsingEncoding:NSUTF8StringEncoding], nil);
1134         return nil;
1135     }];
1136
1137     auto slowItem = adoptNS([[UIItemProvider alloc] init]);
1138     [slowItem registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeUTF8PlainText options:nil loadHandler:^NSProgress *(UIItemProviderDataLoadCompletionBlock completionBlock)
1139     {
1140         sleep(2);
1141         completionBlock([slowString dataUsingEncoding:NSUTF8StringEncoding], nil);
1142         return nil;
1143     }];
1144
1145     __block bool hasRunFirstCompletionBlock = false;
1146     pasteboard.itemProviders = @[ fastItem.get(), slowItem.get() ];
1147     [pasteboard doAfterLoadingProvidedContentIntoFileURLs:^(NSArray<NSURL *> *urls) {
1148         EXPECT_EQ(2UL, urls.count);
1149         auto firstString = adoptNS([[NSString alloc] initWithContentsOfURL:urls[0] encoding:NSUTF8StringEncoding error:nil]);
1150         auto secondString = adoptNS([[NSString alloc] initWithContentsOfURL:urls[1] encoding:NSUTF8StringEncoding error:nil]);
1151         EXPECT_WK_STREQ(fastString, [firstString UTF8String]);
1152         EXPECT_WK_STREQ(slowString, [secondString UTF8String]);
1153         hasRunFirstCompletionBlock = true;
1154     } synchronousTimeout:600];
1155     EXPECT_TRUE(hasRunFirstCompletionBlock);
1156
1157     __block bool hasRunSecondCompletionBlock = false;
1158     [pasteboard doAfterLoadingProvidedContentIntoFileURLs:^(NSArray<NSURL *> *urls) {
1159         EXPECT_EQ(2UL, urls.count);
1160         auto firstString = adoptNS([[NSString alloc] initWithContentsOfURL:urls[0] encoding:NSUTF8StringEncoding error:nil]);
1161         auto secondString = adoptNS([[NSString alloc] initWithContentsOfURL:urls[1] encoding:NSUTF8StringEncoding error:nil]);
1162         EXPECT_WK_STREQ(fastString, [firstString UTF8String]);
1163         EXPECT_WK_STREQ(slowString, [secondString UTF8String]);
1164         hasRunSecondCompletionBlock = true;
1165     } synchronousTimeout:0];
1166     EXPECT_FALSE(hasRunSecondCompletionBlock);
1167     TestWebKitAPI::Util::run(&hasRunSecondCompletionBlock);
1168 }
1169
1170 TEST(DataInteractionTests, DoNotCrashWhenSelectionMovesOffscreenAfterDragStart)
1171 {
1172     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
1173     [webView synchronouslyLoadTestPageNamed:@"dragstart-change-selection-offscreen"];
1174
1175     auto simulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
1176     [simulator runFrom:CGPointMake(100, 100) to:CGPointMake(100, 100)];
1177
1178     EXPECT_WK_STREQ("FAR OFFSCREEN", [webView stringByEvaluatingJavaScript:@"getSelection().getRangeAt(0).toString()"]);
1179 }
1180
1181 } // namespace TestWebKitAPI
1182
1183 #endif // ENABLE(DATA_INTERACTION)