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