574e3eb0e48f62a13a5aa199051dc7ab0d4e2ef5
[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 "UIKitSPI.h"
34 #import "WKWebViewConfigurationExtras.h"
35 #import <MobileCoreServices/MobileCoreServices.h>
36 #import <UIKit/NSItemProvider+UIKitAdditions.h>
37 #import <WebKit/WKPreferencesPrivate.h>
38 #import <WebKit/WKPreferencesRefPrivate.h>
39 #import <WebKit/WKProcessPoolPrivate.h>
40 #import <WebKit/WKWebViewConfigurationPrivate.h>
41 #import <WebKit/WebItemProviderPasteboard.h>
42 #import <WebKit/_WKProcessPoolConfiguration.h>
43
44 typedef void (^FileLoadCompletionBlock)(NSURL *, BOOL, NSError *);
45 typedef void (^DataLoadCompletionBlock)(NSData *, NSError *);
46 typedef void (^UIItemProviderDataLoadCompletionBlock)(NSData *, NSError *);
47
48 #if !USE(APPLE_INTERNAL_SDK)
49
50 @interface UIItemProviderRepresentationOptions : NSObject
51 @end
52
53 #endif
54
55 @interface UIItemProvider()
56 + (UIItemProvider *)itemProviderWithURL:(NSURL *)url title:(NSString *)title;
57 - (void) registerDataRepresentationForTypeIdentifier:(NSString *)typeIdentifier options:(UIItemProviderRepresentationOptions*)options loadHandler:(NSProgress * (^)(void (^UIItemProviderDataLoadCompletionBlock)(NSData *item, NSError *error))) loadHandler;
58 @end
59
60 static NSString *InjectedBundlePasteboardDataType = @"org.webkit.data";
61
62 static UIImage *testIconImage()
63 {
64     return [UIImage imageNamed:@"TestWebKitAPI.resources/icon.png"];
65 }
66
67 static NSData *testZIPArchive()
68 {
69     NSURL *zipFileURL = [[NSBundle mainBundle] URLForResource:@"compressed-files" withExtension:@"zip" subdirectory:@"TestWebKitAPI.resources"];
70     return [NSData dataWithContentsOfURL:zipFileURL];
71 }
72
73 @implementation UIItemProvider (DataInteractionTests)
74
75 - (void)registerDataRepresentationForTypeIdentifier:(NSString *)typeIdentifier withData:(NSData *)data
76 {
77     RetainPtr<NSData> retainedData = data;
78     [self registerDataRepresentationForTypeIdentifier:typeIdentifier visibility:UIItemProviderRepresentationOptionsVisibilityAll loadHandler: [retainedData] (DataLoadCompletionBlock block) -> NSProgress * {
79         block(retainedData.get(), nil);
80         return [NSProgress discreteProgressWithTotalUnitCount:100];
81     }];
82 }
83
84 @end
85
86 @implementation TestWKWebView (DataInteractionTests)
87
88 - (BOOL)editorContainsImageElement
89 {
90     return [self stringByEvaluatingJavaScript:@"!!editor.querySelector('img')"].boolValue;
91 }
92
93 - (NSString *)editorValue
94 {
95     return [self stringByEvaluatingJavaScript:@"editor.value"];
96 }
97
98 @end
99
100 static NSValue *makeCGRectValue(CGFloat x, CGFloat y, CGFloat width, CGFloat height)
101 {
102     return [NSValue valueWithCGRect:CGRectMake(x, y, width, height)];
103 }
104
105 static void checkCGRectIsEqualToCGRectWithLogging(CGRect expected, CGRect observed)
106 {
107     BOOL isEqual = CGRectEqualToRect(expected, observed);
108     EXPECT_TRUE(isEqual);
109     if (!isEqual)
110         NSLog(@"Expected: %@ but observed: %@", NSStringFromCGRect(expected), NSStringFromCGRect(observed));
111 }
112
113 static void checkSelectionRectsWithLogging(NSArray *expected, NSArray *observed)
114 {
115     if (![expected isEqualToArray:observed])
116         NSLog(@"Expected selection rects: %@ but observed: %@", expected, observed);
117     EXPECT_TRUE([expected isEqualToArray:observed]);
118 }
119
120 static void checkTypeIdentifierPrecedesOtherTypeIdentifier(DataInteractionSimulator *simulator, NSString *firstType, NSString *secondType)
121 {
122     NSArray *registeredTypes = [simulator.sourceItemProviders.firstObject registeredTypeIdentifiers];
123     EXPECT_TRUE([registeredTypes containsObject:firstType]);
124     EXPECT_TRUE([registeredTypes containsObject:secondType]);
125     EXPECT_TRUE([registeredTypes indexOfObject:firstType] < [registeredTypes indexOfObject:secondType]);
126 }
127
128 static void checkTypeIdentifierAndIsNotOtherTypeIdentifier(DataInteractionSimulator *simulator, NSString *firstType, NSString *secondType)
129 {
130     NSArray *registeredTypes = [simulator.sourceItemProviders.firstObject registeredTypeIdentifiers];
131     EXPECT_TRUE([registeredTypes containsObject:firstType]);
132     EXPECT_FALSE([registeredTypes containsObject:secondType]);
133 }
134
135 static void checkTypeIdentifierIsRegisteredAtIndex(DataInteractionSimulator *simulator, NSString *type, NSUInteger index)
136 {
137     NSArray *registeredTypes = [simulator.sourceItemProviders.firstObject registeredTypeIdentifiers];
138     EXPECT_GT(registeredTypes.count, index);
139     EXPECT_WK_STREQ(type.UTF8String, [registeredTypes[index] UTF8String]);
140 }
141
142 static void checkEstimatedSize(DataInteractionSimulator *simulator, CGSize estimatedSize)
143 {
144     UIItemProvider *sourceItemProvider = [simulator sourceItemProviders].firstObject;
145     EXPECT_EQ(estimatedSize.width, sourceItemProvider.preferredPresentationSize.width);
146     EXPECT_EQ(estimatedSize.height, sourceItemProvider.preferredPresentationSize.height);
147 }
148
149 static void checkSuggestedNameAndEstimatedSize(DataInteractionSimulator *simulator, NSString *suggestedName, CGSize estimatedSize)
150 {
151     UIItemProvider *sourceItemProvider = [simulator sourceItemProviders].firstObject;
152     EXPECT_WK_STREQ(suggestedName.UTF8String, sourceItemProvider.suggestedName.UTF8String);
153     EXPECT_EQ(estimatedSize.width, sourceItemProvider.preferredPresentationSize.width);
154     EXPECT_EQ(estimatedSize.height, sourceItemProvider.preferredPresentationSize.height);
155 }
156
157 static void checkStringArraysAreEqual(NSArray<NSString *> *expected, NSArray<NSString *> *observed)
158 {
159     EXPECT_EQ(expected.count, observed.count);
160     for (NSUInteger index = 0; index < expected.count; ++index) {
161         NSString *expectedString = [expected objectAtIndex:index];
162         NSString *observedString = [observed objectAtIndex:index];
163         EXPECT_WK_STREQ(expectedString, observedString);
164         if (![expectedString isEqualToString:observedString])
165             NSLog(@"Expected observed string: %@ to match expected string: %@ at index: %tu", observedString, expectedString, index);
166     }
167 }
168
169 static void checkDragCaretRectIsContainedInRect(CGRect caretRect, CGRect containerRect)
170 {
171     BOOL contained = CGRectContainsRect(containerRect, caretRect);
172     EXPECT_TRUE(contained);
173     if (!contained)
174         NSLog(@"Expected caret rect: %@ to fit within container rect: %@", NSStringFromCGRect(caretRect), NSStringFromCGRect(containerRect));
175 }
176
177 static void runTestWithTemporaryTextFile(void(^runTest)(NSURL *fileURL))
178 {
179     NSString *fileName = [NSString stringWithFormat:@"drag-drop-text-file-%@.txt", [NSUUID UUID].UUIDString];
180     RetainPtr<NSURL> temporaryFile = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:fileName] isDirectory:NO];
181     [[NSFileManager defaultManager] removeItemAtURL:temporaryFile.get() error:nil];
182
183     NSError *error = nil;
184     [@"This is a tiny blob of text." writeToURL:temporaryFile.get() atomically:YES encoding:NSUTF8StringEncoding error:&error];
185
186     if (error)
187         NSLog(@"Error writing temporary file: %@", error);
188
189     @try {
190         runTest(temporaryFile.get());
191     } @finally {
192         [[NSFileManager defaultManager] removeItemAtURL:temporaryFile.get() error:nil];
193     }
194 }
195
196 static void runTestWithTemporaryFolder(void(^runTest)(NSURL *folderURL))
197 {
198     NSString *folderName = [NSString stringWithFormat:@"some.directory-%@", [NSUUID UUID].UUIDString];
199     RetainPtr<NSURL> temporaryFolder = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:folderName] isDirectory:YES];
200     [[NSFileManager defaultManager] removeItemAtURL:temporaryFolder.get() error:nil];
201
202     NSError *error = nil;
203     NSFileManager *defaultManager = [NSFileManager defaultManager];
204     [defaultManager createDirectoryAtURL:temporaryFolder.get() withIntermediateDirectories:NO attributes:nil error:&error];
205     [UIImagePNGRepresentation(testIconImage()) writeToURL:[temporaryFolder.get() URLByAppendingPathComponent:@"icon.png" isDirectory:NO] atomically:YES];
206     [testZIPArchive() writeToURL:[temporaryFolder.get() URLByAppendingPathComponent:@"archive.zip" isDirectory:NO] atomically:YES];
207
208     NSURL *firstSubdirectory = [temporaryFolder.get() URLByAppendingPathComponent:@"subdirectory1" isDirectory:YES];
209     [defaultManager createDirectoryAtURL:firstSubdirectory withIntermediateDirectories:NO attributes:nil error:&error];
210     [@"I am a text file in the first subdirectory." writeToURL:[firstSubdirectory URLByAppendingPathComponent:@"text-file-1.txt" isDirectory:NO] atomically:YES encoding:NSUTF8StringEncoding error:&error];
211
212     NSURL *secondSubdirectory = [temporaryFolder.get() URLByAppendingPathComponent:@"subdirectory2" isDirectory:YES];
213     [defaultManager createDirectoryAtURL:secondSubdirectory withIntermediateDirectories:NO attributes:nil error:&error];
214     [@"I am a text file in the second subdirectory." writeToURL:[secondSubdirectory URLByAppendingPathComponent:@"text-file-2.txt" isDirectory:NO] atomically:YES encoding:NSUTF8StringEncoding error:&error];
215
216     if (error)
217         NSLog(@"Error writing temporary file: %@", error);
218
219     @try {
220         runTest(temporaryFolder.get());
221     } @finally {
222         [[NSFileManager defaultManager] removeItemAtURL:temporaryFolder.get() error:nil];
223     }
224 }
225
226 namespace TestWebKitAPI {
227
228 TEST(DataInteractionTests, ImageToContentEditable)
229 {
230     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
231     [webView synchronouslyLoadTestPageNamed:@"image-and-contenteditable"];
232
233     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
234     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
235
236     EXPECT_TRUE([webView editorContainsImageElement]);
237
238     NSArray *observedEventNames = [dataInteractionSimulator observedEventNames];
239     EXPECT_TRUE([observedEventNames containsObject:DataInteractionEnterEventName]);
240     EXPECT_TRUE([observedEventNames containsObject:DataInteractionOverEventName]);
241     EXPECT_TRUE([observedEventNames containsObject:DataInteractionPerformOperationEventName]);
242     checkSelectionRectsWithLogging(@[ makeCGRectValue(1, 201, 215, 174) ], [dataInteractionSimulator finalSelectionRects]);
243     checkTypeIdentifierAndIsNotOtherTypeIdentifier(dataInteractionSimulator.get(), (NSString *)kUTTypePNG, (NSString *)kUTTypeFileURL);
244     checkEstimatedSize(dataInteractionSimulator.get(), { 215, 174 });
245 }
246
247 TEST(DataInteractionTests, CanStartDragOnEnormousImage)
248 {
249     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
250     [webView synchronouslyLoadHTMLString:@"<img src='enormous.svg'></img>"];
251
252     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
253     [dataInteractionSimulator runFrom:CGPointMake(100, 100) to:CGPointMake(100, 100)];
254
255     NSArray *registeredTypes = [[dataInteractionSimulator sourceItemProviders].firstObject registeredTypeIdentifiers];
256     EXPECT_WK_STREQ((NSString *)kUTTypeScalableVectorGraphics, [registeredTypes firstObject]);
257 }
258
259 TEST(DataInteractionTests, ImageToTextarea)
260 {
261     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
262     [webView synchronouslyLoadTestPageNamed:@"image-and-textarea"];
263
264     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
265     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
266
267     EXPECT_WK_STREQ("", [webView editorValue]);
268
269     NSArray *observedEventNames = [dataInteractionSimulator observedEventNames];
270     EXPECT_TRUE([observedEventNames containsObject:DataInteractionEnterEventName]);
271     EXPECT_TRUE([observedEventNames containsObject:DataInteractionOverEventName]);
272     EXPECT_TRUE([observedEventNames containsObject:DataInteractionPerformOperationEventName]);
273     checkTypeIdentifierAndIsNotOtherTypeIdentifier(dataInteractionSimulator.get(), (NSString *)kUTTypePNG, (NSString *)kUTTypeFileURL);
274     checkEstimatedSize(dataInteractionSimulator.get(), { 215, 174 });
275 }
276
277 TEST(DataInteractionTests, ImageInLinkToInput)
278 {
279     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
280     [webView synchronouslyLoadTestPageNamed:@"image-in-link-and-input"];
281
282     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
283     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
284
285     EXPECT_WK_STREQ("https://www.apple.com/", [webView editorValue].UTF8String);
286     checkSelectionRectsWithLogging(@[ makeCGRectValue(101, 241, 2057, 232) ], [dataInteractionSimulator finalSelectionRects]);
287     checkSuggestedNameAndEstimatedSize(dataInteractionSimulator.get(), @"icon.png", { 215, 174 });
288     checkTypeIdentifierIsRegisteredAtIndex(dataInteractionSimulator.get(), (NSString *)kUTTypePNG, 0);
289 }
290
291 TEST(DataInteractionTests, ImageInLinkWithoutHREFToInput)
292 {
293     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
294     [webView synchronouslyLoadTestPageNamed:@"image-in-link-and-input"];
295     [webView stringByEvaluatingJavaScript:@"link.href = ''"];
296
297     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
298     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
299
300     EXPECT_WK_STREQ("", [webView editorValue]);
301     checkEstimatedSize(dataInteractionSimulator.get(), { 215, 174 });
302     checkTypeIdentifierIsRegisteredAtIndex(dataInteractionSimulator.get(), (NSString *)kUTTypePNG, 0);
303 }
304
305 TEST(DataInteractionTests, ImageDoesNotUseElementSizeAsEstimatedSize)
306 {
307     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
308     [webView synchronouslyLoadTestPageNamed:@"gif-and-file-input"];
309
310     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
311     [dataInteractionSimulator runFrom: { 100, 100 } to: { 100, 300 }];
312
313     checkTypeIdentifierIsRegisteredAtIndex(dataInteractionSimulator.get(), (NSString *)kUTTypeGIF, 0);
314     checkSuggestedNameAndEstimatedSize(dataInteractionSimulator.get(), @"apple.gif", { 52, 64 });
315     EXPECT_WK_STREQ("apple.gif (image/gif)", [webView stringByEvaluatingJavaScript:@"output.textContent"]);
316 }
317
318 TEST(DataInteractionTests, ContentEditableToContentEditable)
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 loadTestPageNamed:@"autofocus-contenteditable"];
324     [dataInteractionSimulator waitForInputSession];
325     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
326
327     EXPECT_EQ([webView stringByEvaluatingJavaScript:@"source.textContent"].length, 0UL);
328     EXPECT_WK_STREQ("Hello world", [webView stringByEvaluatingJavaScript:@"editor.textContent"].UTF8String);
329
330     NSArray *observedEventNames = [dataInteractionSimulator observedEventNames];
331     EXPECT_TRUE([observedEventNames containsObject:DataInteractionEnterEventName]);
332     EXPECT_TRUE([observedEventNames containsObject:DataInteractionOverEventName]);
333     EXPECT_TRUE([observedEventNames containsObject:DataInteractionPerformOperationEventName]);
334     checkSelectionRectsWithLogging(@[ makeCGRectValue(1, 201, 961, 227) ], [dataInteractionSimulator finalSelectionRects]);
335     checkTypeIdentifierPrecedesOtherTypeIdentifier(dataInteractionSimulator.get(), (NSString *)kUTTypeRTFD, (NSString *)kUTTypeUTF8PlainText);
336 }
337
338 TEST(DataInteractionTests, ContentEditableToTextarea)
339 {
340     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
341     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
342
343     [webView loadTestPageNamed:@"contenteditable-and-textarea"];
344     [dataInteractionSimulator waitForInputSession];
345     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
346
347     EXPECT_EQ([webView stringByEvaluatingJavaScript:@"source.textContent"].length, 0UL);
348     EXPECT_WK_STREQ("Hello world", [webView editorValue].UTF8String);
349
350     NSArray *observedEventNames = [dataInteractionSimulator observedEventNames];
351     EXPECT_TRUE([observedEventNames containsObject:DataInteractionEnterEventName]);
352     EXPECT_TRUE([observedEventNames containsObject:DataInteractionOverEventName]);
353     EXPECT_TRUE([observedEventNames containsObject:DataInteractionPerformOperationEventName]);
354     checkSelectionRectsWithLogging(@[ makeCGRectValue(6, 203, 990, 232) ], [dataInteractionSimulator finalSelectionRects]);
355     checkTypeIdentifierPrecedesOtherTypeIdentifier(dataInteractionSimulator.get(), (NSString *)kUTTypeRTFD, (NSString *)kUTTypeUTF8PlainText);
356 }
357
358 TEST(DataInteractionTests, ContentEditableMoveParagraphs)
359 {
360     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
361     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
362
363     [webView loadTestPageNamed:@"two-paragraph-contenteditable"];
364     [dataInteractionSimulator waitForInputSession];
365     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(250, 450)];
366
367     NSString *finalTextContent = [webView stringByEvaluatingJavaScript:@"editor.textContent"];
368     NSUInteger firstParagraphOffset = [finalTextContent rangeOfString:@"This is the first paragraph"].location;
369     NSUInteger secondParagraphOffset = [finalTextContent rangeOfString:@"This is the second paragraph"].location;
370
371     EXPECT_FALSE(firstParagraphOffset == NSNotFound);
372     EXPECT_FALSE(secondParagraphOffset == NSNotFound);
373     EXPECT_GT(firstParagraphOffset, secondParagraphOffset);
374     checkSelectionRectsWithLogging(@[ makeCGRectValue(190, 100, 130, 20), makeCGRectValue(0, 120, 320, 100), makeCGRectValue(0, 220, 252, 20) ], [dataInteractionSimulator finalSelectionRects]);
375 }
376
377 TEST(DataInteractionTests, DragImageFromContentEditable)
378 {
379     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
380     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
381
382     [webView synchronouslyLoadTestPageNamed:@"contenteditable-and-target"];
383     [dataInteractionSimulator runFrom:CGPointMake(100, 100) to:CGPointMake(100, 300)];
384
385     EXPECT_WK_STREQ("PASS", [webView stringByEvaluatingJavaScript:@"target.textContent"]);
386 }
387
388 TEST(DataInteractionTests, TextAreaToInput)
389 {
390     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
391     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
392
393     [webView loadTestPageNamed:@"textarea-to-input"];
394     [dataInteractionSimulator waitForInputSession];
395     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
396
397     EXPECT_EQ([webView stringByEvaluatingJavaScript:@"source.value"].length, 0UL);
398     EXPECT_WK_STREQ("Hello world", [webView editorValue].UTF8String);
399     checkSelectionRectsWithLogging(@[ makeCGRectValue(101, 241, 990, 232) ], [dataInteractionSimulator finalSelectionRects]);
400 }
401
402 TEST(DataInteractionTests, SinglePlainTextWordTypeIdentifiers)
403 {
404     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
405     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
406
407     [webView loadTestPageNamed:@"textarea-to-input"];
408     [dataInteractionSimulator waitForInputSession];
409     [webView stringByEvaluatingJavaScript:@"source.value = 'pneumonoultramicroscopicsilicovolcanoconiosis'"];
410     [webView stringByEvaluatingJavaScript:@"source.selectionStart = 0"];
411     [webView stringByEvaluatingJavaScript:@"source.selectionEnd = source.value.length"];
412     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
413
414     NSArray *registeredTypes = [[dataInteractionSimulator sourceItemProviders].firstObject registeredTypeIdentifiers];
415     EXPECT_EQ(1UL, registeredTypes.count);
416     EXPECT_WK_STREQ([(NSString *)kUTTypeUTF8PlainText UTF8String], [registeredTypes.firstObject UTF8String]);
417     EXPECT_EQ([webView stringByEvaluatingJavaScript:@"source.value"].length, 0UL);
418     EXPECT_WK_STREQ("pneumonoultramicroscopicsilicovolcanoconiosis", [webView editorValue].UTF8String);
419 }
420
421 TEST(DataInteractionTests, SinglePlainTextURLTypeIdentifiers)
422 {
423     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
424     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
425
426     [webView loadTestPageNamed:@"textarea-to-input"];
427     [dataInteractionSimulator waitForInputSession];
428     [webView stringByEvaluatingJavaScript:@"source.value = 'https://webkit.org/'"];
429     [webView stringByEvaluatingJavaScript:@"source.selectionStart = 0"];
430     [webView stringByEvaluatingJavaScript:@"source.selectionEnd = source.value.length"];
431     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
432
433     NSArray *registeredTypes = [[dataInteractionSimulator sourceItemProviders].firstObject registeredTypeIdentifiers];
434     EXPECT_EQ(2UL, registeredTypes.count);
435     EXPECT_WK_STREQ([(NSString *)kUTTypeURL UTF8String], [registeredTypes.firstObject UTF8String]);
436     EXPECT_WK_STREQ([(NSString *)kUTTypeUTF8PlainText UTF8String], [registeredTypes.lastObject UTF8String]);
437     EXPECT_EQ(0UL, [webView stringByEvaluatingJavaScript:@"source.value"].length);
438     EXPECT_WK_STREQ("https://webkit.org/", [webView editorValue].UTF8String);
439 }
440
441 TEST(DataInteractionTests, LinkToInput)
442 {
443     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
444     [webView synchronouslyLoadTestPageNamed:@"link-and-input"];
445
446     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
447     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
448
449     EXPECT_WK_STREQ("https://www.apple.com/", [webView editorValue].UTF8String);
450
451     __block bool doneLoadingURL = false;
452     UIItemProvider *sourceItemProvider = [dataInteractionSimulator sourceItemProviders].firstObject;
453     [sourceItemProvider loadObjectOfClass:[NSURL class] completionHandler:^(id object, NSError *error) {
454         NSURL *url = object;
455         EXPECT_WK_STREQ("Hello world", url._title.UTF8String ?: "");
456         doneLoadingURL = true;
457     }];
458     TestWebKitAPI::Util::run(&doneLoadingURL);
459
460     NSArray *observedEventNames = [dataInteractionSimulator observedEventNames];
461     EXPECT_TRUE([observedEventNames containsObject:DataInteractionEnterEventName]);
462     EXPECT_TRUE([observedEventNames containsObject:DataInteractionOverEventName]);
463     EXPECT_TRUE([observedEventNames containsObject:DataInteractionPerformOperationEventName]);
464     checkSelectionRectsWithLogging(@[ makeCGRectValue(101, 273, 2057, 232) ], [dataInteractionSimulator finalSelectionRects]);
465     checkTypeIdentifierIsRegisteredAtIndex(dataInteractionSimulator.get(), (NSString *)kUTTypeURL, 0);
466 }
467
468 TEST(DataInteractionTests, BackgroundImageLinkToInput)
469 {
470     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
471     [webView synchronouslyLoadTestPageNamed:@"background-image-link-and-input"];
472
473     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
474     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
475
476     EXPECT_WK_STREQ("https://www.apple.com/", [webView editorValue].UTF8String);
477
478     NSArray *observedEventNames = [dataInteractionSimulator observedEventNames];
479     EXPECT_TRUE([observedEventNames containsObject:DataInteractionEnterEventName]);
480     EXPECT_TRUE([observedEventNames containsObject:DataInteractionOverEventName]);
481     EXPECT_TRUE([observedEventNames containsObject:DataInteractionPerformOperationEventName]);
482     checkSelectionRectsWithLogging(@[ makeCGRectValue(101, 241, 2057, 232) ], [dataInteractionSimulator finalSelectionRects]);
483     checkTypeIdentifierIsRegisteredAtIndex(dataInteractionSimulator.get(), (NSString *)kUTTypeURL, 0);
484 }
485
486 TEST(DataInteractionTests, CanPreventStart)
487 {
488     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
489     [webView synchronouslyLoadTestPageNamed:@"prevent-start"];
490
491     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
492     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
493
494     EXPECT_EQ(DataInteractionCancelled, [dataInteractionSimulator phase]);
495     EXPECT_FALSE([webView editorContainsImageElement]);
496
497     NSArray *observedEventNames = [dataInteractionSimulator observedEventNames];
498     EXPECT_FALSE([observedEventNames containsObject:DataInteractionEnterEventName]);
499     EXPECT_FALSE([observedEventNames containsObject:DataInteractionOverEventName]);
500     checkSelectionRectsWithLogging(@[ ], [dataInteractionSimulator finalSelectionRects]);
501 }
502
503 TEST(DataInteractionTests, CanPreventOperation)
504 {
505     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
506     [webView synchronouslyLoadTestPageNamed:@"prevent-operation"];
507
508     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
509     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
510
511     EXPECT_FALSE([webView editorContainsImageElement]);
512
513     NSArray *observedEventNames = [dataInteractionSimulator observedEventNames];
514     EXPECT_TRUE([observedEventNames containsObject:DataInteractionEnterEventName]);
515     EXPECT_TRUE([observedEventNames containsObject:DataInteractionOverEventName]);
516     checkSelectionRectsWithLogging(@[ ], [dataInteractionSimulator finalSelectionRects]);
517 }
518
519 TEST(DataInteractionTests, EnterAndLeaveEvents)
520 {
521     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
522     [webView synchronouslyLoadTestPageNamed:@"link-and-input"];
523
524     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
525     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 450)];
526
527     EXPECT_WK_STREQ("", [webView editorValue].UTF8String);
528
529     NSArray *observedEventNames = [dataInteractionSimulator observedEventNames];
530     EXPECT_TRUE([observedEventNames containsObject:DataInteractionEnterEventName]);
531     EXPECT_TRUE([observedEventNames containsObject:DataInteractionOverEventName]);
532     EXPECT_TRUE([observedEventNames containsObject:DataInteractionLeaveEventName]);
533     EXPECT_FALSE([observedEventNames containsObject:DataInteractionPerformOperationEventName]);
534     checkSelectionRectsWithLogging(@[ ], [dataInteractionSimulator finalSelectionRects]);
535 }
536
537 TEST(DataInteractionTests, CanStartDragOnDivWithDraggableAttribute)
538 {
539     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
540     [webView synchronouslyLoadTestPageNamed:@"custom-draggable-div"];
541
542     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
543     [dataInteractionSimulator runFrom:CGPointMake(100, 100) to:CGPointMake(250, 100)];
544
545     EXPECT_GT([dataInteractionSimulator sourceItemProviders].count, 0UL);
546 }
547
548 TEST(DataInteractionTests, ExternalSourcePlainTextToIFrame)
549 {
550     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
551     [webView synchronouslyLoadTestPageNamed:@"contenteditable-in-iframe"];
552
553     auto itemProvider = adoptNS([[UIItemProvider alloc] init]);
554     [itemProvider registerObject:@"Hello world" visibility:UIItemProviderRepresentationOptionsVisibilityAll];
555
556     auto simulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
557     [simulator setExternalItemProviders:@[ itemProvider.get() ]];
558     [simulator runFrom:CGPointMake(0, 0) to:CGPointMake(160, 250)];
559
560     auto containerLeft = [webView stringByEvaluatingJavaScript:@"container.getBoundingClientRect().left"].floatValue;
561     auto containerTop = [webView stringByEvaluatingJavaScript:@"container.getBoundingClientRect().top"].floatValue;
562     auto containerWidth = [webView stringByEvaluatingJavaScript:@"container.getBoundingClientRect().width"].floatValue;
563     auto containerHeight = [webView stringByEvaluatingJavaScript:@"container.getBoundingClientRect().height"].floatValue;
564     checkDragCaretRectIsContainedInRect([simulator lastKnownDragCaretRect], CGRectMake(containerLeft, containerTop, containerWidth, containerHeight));
565 }
566
567 TEST(DataInteractionTests, ExternalSourceJSONToFileInput)
568 {
569     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
570     [webView synchronouslyLoadTestPageNamed:@"file-uploading"];
571
572     auto simulatedJSONItemProvider = adoptNS([[UIItemProvider alloc] init]);
573     NSData *jsonData = [@"{ \"foo\": \"bar\",  \"bar\": \"baz\" }" dataUsingEncoding:NSUTF8StringEncoding];
574     [simulatedJSONItemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeJSON withData:jsonData];
575
576     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
577     [dataInteractionSimulator setExternalItemProviders:@[ simulatedJSONItemProvider.get() ]];
578     [dataInteractionSimulator runFrom:CGPointMake(200, 100) to:CGPointMake(100, 100)];
579
580     EXPECT_WK_STREQ("application/json", [webView stringByEvaluatingJavaScript:@"output.value"]);
581 }
582
583 TEST(DataInteractionTests, ExternalSourceImageToFileInput)
584 {
585     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
586     [webView synchronouslyLoadTestPageNamed:@"file-uploading"];
587
588     auto simulatedImageItemProvider = adoptNS([[UIItemProvider alloc] init]);
589     NSData *imageData = UIImageJPEGRepresentation(testIconImage(), 0.5);
590     [simulatedImageItemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeJPEG withData:imageData];
591
592     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
593     [dataInteractionSimulator setExternalItemProviders:@[ simulatedImageItemProvider.get() ]];
594     [dataInteractionSimulator runFrom:CGPointMake(200, 100) to:CGPointMake(100, 100)];
595
596     NSString *outputValue = [webView stringByEvaluatingJavaScript:@"output.value"];
597     EXPECT_WK_STREQ("image/jpeg", outputValue.UTF8String);
598 }
599
600 TEST(DataInteractionTests, ExternalSourceHTMLToUploadArea)
601 {
602     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
603     [webView synchronouslyLoadTestPageNamed:@"file-uploading"];
604
605     auto simulatedHTMLItemProvider = adoptNS([[UIItemProvider alloc] init]);
606     NSData *htmlData = [@"<body contenteditable></body>" dataUsingEncoding:NSUTF8StringEncoding];
607     [simulatedHTMLItemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeHTML withData:htmlData];
608
609     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
610     [dataInteractionSimulator setShouldAllowMoveOperation:NO];
611     [dataInteractionSimulator setExternalItemProviders:@[ simulatedHTMLItemProvider.get() ]];
612     [dataInteractionSimulator runFrom:CGPointMake(200, 300) to:CGPointMake(100, 300)];
613
614     NSString *outputValue = [webView stringByEvaluatingJavaScript:@"output.value"];
615     EXPECT_WK_STREQ("text/html", outputValue.UTF8String);
616 }
617
618 TEST(DataInteractionTests, ExternalSourceMoveOperationNotAllowed)
619 {
620     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
621     [webView synchronouslyLoadTestPageNamed:@"file-uploading"];
622     [webView stringByEvaluatingJavaScript:@"upload.dropEffect = 'move'"];
623
624     auto simulatedHTMLItemProvider = adoptNS([[UIItemProvider alloc] init]);
625     NSData *htmlData = [@"<body contenteditable></body>" dataUsingEncoding:NSUTF8StringEncoding];
626     [simulatedHTMLItemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeHTML withData:htmlData];
627
628     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
629     [dataInteractionSimulator setShouldAllowMoveOperation:NO];
630     [dataInteractionSimulator setExternalItemProviders:@[ simulatedHTMLItemProvider.get() ]];
631     [dataInteractionSimulator runFrom:CGPointMake(200, 300) to:CGPointMake(100, 300)];
632
633     EXPECT_WK_STREQ("", [webView stringByEvaluatingJavaScript:@"output.value"]);
634 }
635
636 TEST(DataInteractionTests, ExternalSourceZIPArchiveAndURLToSingleFileInput)
637 {
638     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
639     [webView synchronouslyLoadTestPageNamed:@"file-uploading"];
640
641     auto archiveProvider = adoptNS([[UIItemProvider alloc] init]);
642     [archiveProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeZipArchive withData:testZIPArchive()];
643
644     auto urlProvider = adoptNS([[UIItemProvider alloc] init]);
645     [urlProvider registerObject:[NSURL URLWithString:@"https://webkit.org"] visibility:UIItemProviderRepresentationOptionsVisibilityAll];
646
647     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
648     [dataInteractionSimulator setExternalItemProviders:@[ archiveProvider.get(), urlProvider.get() ]];
649     [dataInteractionSimulator runFrom:CGPointMake(200, 100) to:CGPointMake(100, 100)];
650
651     NSString *outputValue = [webView stringByEvaluatingJavaScript:@"output.value"];
652     EXPECT_WK_STREQ("application/zip", outputValue.UTF8String);
653 }
654
655 TEST(DataInteractionTests, ExternalSourceZIPArchiveToUploadArea)
656 {
657     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
658     [webView synchronouslyLoadTestPageNamed:@"file-uploading"];
659
660     auto itemProvider = adoptNS([[UIItemProvider alloc] init]);
661     [itemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeZipArchive withData:testZIPArchive()];
662
663     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
664     [dataInteractionSimulator setExternalItemProviders:@[ itemProvider.get() ]];
665     [dataInteractionSimulator runFrom:CGPointMake(200, 300) to:CGPointMake(100, 300)];
666
667     NSString *outputValue = [webView stringByEvaluatingJavaScript:@"output.value"];
668     EXPECT_WK_STREQ("application/zip", outputValue.UTF8String);
669 }
670
671 TEST(DataInteractionTests, ExternalSourceImageAndHTMLToSingleFileInput)
672 {
673     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
674     [webView synchronouslyLoadTestPageNamed:@"file-uploading"];
675
676     auto simulatedImageItemProvider = adoptNS([[UIItemProvider alloc] init]);
677     NSData *imageData = UIImageJPEGRepresentation(testIconImage(), 0.5);
678     [simulatedImageItemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeJPEG withData:imageData];
679
680     auto simulatedHTMLItemProvider = adoptNS([[UIItemProvider alloc] init]);
681     NSData *htmlData = [@"<body contenteditable></body>" dataUsingEncoding:NSUTF8StringEncoding];
682     [simulatedHTMLItemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeHTML withData:htmlData];
683
684     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
685     [dataInteractionSimulator setExternalItemProviders:@[ simulatedHTMLItemProvider.get(), simulatedImageItemProvider.get() ]];
686     [dataInteractionSimulator runFrom:CGPointMake(200, 100) to:CGPointMake(100, 100)];
687
688     NSString *outputValue = [webView stringByEvaluatingJavaScript:@"output.value"];
689     EXPECT_WK_STREQ("", outputValue.UTF8String);
690 }
691
692 TEST(DataInteractionTests, ExternalSourceImageAndHTMLToMultipleFileInput)
693 {
694     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
695     [webView synchronouslyLoadTestPageNamed:@"file-uploading"];
696     [webView stringByEvaluatingJavaScript:@"input.setAttribute('multiple', '')"];
697
698     auto simulatedImageItemProvider = adoptNS([[UIItemProvider alloc] init]);
699     NSData *imageData = UIImageJPEGRepresentation(testIconImage(), 0.5);
700     [simulatedImageItemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeJPEG withData:imageData];
701
702     auto simulatedHTMLItemProvider = adoptNS([[UIItemProvider alloc] init]);
703     NSData *htmlData = [@"<body contenteditable></body>" dataUsingEncoding:NSUTF8StringEncoding];
704     [simulatedHTMLItemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeHTML withData:htmlData];
705
706     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
707     [dataInteractionSimulator setExternalItemProviders:@[ simulatedHTMLItemProvider.get(), simulatedImageItemProvider.get() ]];
708     [dataInteractionSimulator runFrom:CGPointMake(200, 100) to:CGPointMake(100, 100)];
709
710     NSString *outputValue = [webView stringByEvaluatingJavaScript:@"output.value"];
711     EXPECT_WK_STREQ("image/jpeg, text/html", outputValue.UTF8String);
712 }
713
714 TEST(DataInteractionTests, ExternalSourceImageAndHTMLToUploadArea)
715 {
716     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
717     [webView synchronouslyLoadTestPageNamed:@"file-uploading"];
718
719     auto simulatedImageItemProvider = adoptNS([[UIItemProvider alloc] init]);
720     NSData *imageData = UIImageJPEGRepresentation(testIconImage(), 0.5);
721     [simulatedImageItemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeJPEG withData:imageData];
722
723     auto firstSimulatedHTMLItemProvider = adoptNS([[UIItemProvider alloc] init]);
724     NSData *firstHTMLData = [@"<body contenteditable></body>" dataUsingEncoding:NSUTF8StringEncoding];
725     [firstSimulatedHTMLItemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeHTML withData:firstHTMLData];
726
727     auto secondSimulatedHTMLItemProvider = adoptNS([[UIItemProvider alloc] init]);
728     NSData *secondHTMLData = [@"<html><body>hello world</body></html>" dataUsingEncoding:NSUTF8StringEncoding];
729     [secondSimulatedHTMLItemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeHTML withData:secondHTMLData];
730
731     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
732     [dataInteractionSimulator setShouldAllowMoveOperation:NO];
733     [dataInteractionSimulator setExternalItemProviders:@[ simulatedImageItemProvider.get(), firstSimulatedHTMLItemProvider.get(), secondSimulatedHTMLItemProvider.get() ]];
734     [dataInteractionSimulator runFrom:CGPointMake(200, 300) to:CGPointMake(100, 300)];
735
736     NSString *outputValue = [webView stringByEvaluatingJavaScript:@"output.value"];
737     EXPECT_WK_STREQ("image/jpeg, text/html, text/html", outputValue.UTF8String);
738 }
739
740 TEST(DataInteractionTests, ExternalSourceHTMLToContentEditable)
741 {
742     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
743     [webView synchronouslyLoadTestPageNamed:@"autofocus-contenteditable"];
744     [webView stringByEvaluatingJavaScript:@"getSelection().removeAllRanges()"];
745
746     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
747     auto itemProvider = adoptNS([[UIItemProvider alloc] init]);
748     NSData *htmlData = [@"<h1>This is a test</h1>" dataUsingEncoding:NSUTF8StringEncoding];
749     [itemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeHTML withData:htmlData];
750     [dataInteractionSimulator setExternalItemProviders:@[ itemProvider.get() ]];
751     [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
752
753     NSString *textContent = [webView stringByEvaluatingJavaScript:@"editor.textContent"];
754     EXPECT_WK_STREQ("This is a test", textContent.UTF8String);
755     EXPECT_TRUE([webView stringByEvaluatingJavaScript:@"!!editor.querySelector('h1')"].boolValue);
756 }
757
758 TEST(DataInteractionTests, ExternalSourceBoldSystemAttributedStringToContentEditable)
759 {
760     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
761     [webView synchronouslyLoadTestPageNamed:@"autofocus-contenteditable"];
762     [webView stringByEvaluatingJavaScript:@"getSelection().removeAllRanges()"];
763
764     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
765     NSDictionary *textAttributes = @{ NSFontAttributeName: [UIFont boldSystemFontOfSize:20] };
766     NSAttributedString *richText = [[NSAttributedString alloc] initWithString:@"This is a test" attributes:textAttributes];
767     auto itemProvider = adoptNS([[UIItemProvider alloc] initWithObject:richText]);
768     [dataInteractionSimulator setExternalItemProviders:@[ itemProvider.get() ]];
769     [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
770
771     EXPECT_WK_STREQ("This is a test", [webView stringByEvaluatingJavaScript:@"editor.textContent"].UTF8String);
772 }
773
774 TEST(DataInteractionTests, ExternalSourceColoredAttributedStringToContentEditable)
775 {
776     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
777     [webView synchronouslyLoadTestPageNamed:@"autofocus-contenteditable"];
778     [webView stringByEvaluatingJavaScript:@"getSelection().removeAllRanges()"];
779
780     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
781     NSDictionary *textAttributes = @{ NSForegroundColorAttributeName: [UIColor redColor] };
782     NSAttributedString *richText = [[NSAttributedString alloc] initWithString:@"This is a test" attributes:textAttributes];
783     auto itemProvider = adoptNS([[UIItemProvider alloc] initWithObject:richText]);
784     [dataInteractionSimulator setExternalItemProviders:@[ itemProvider.get() ]];
785     [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
786
787     EXPECT_WK_STREQ("rgb(255, 0, 0)", [webView stringByEvaluatingJavaScript:@"getComputedStyle(document.querySelector('p')).color"]);
788     EXPECT_WK_STREQ("This is a test", [webView stringByEvaluatingJavaScript:@"editor.textContent"].UTF8String);
789 }
790
791 TEST(DataInteractionTests, ExternalSourceMultipleURLsToContentEditable)
792 {
793     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
794     [webView synchronouslyLoadTestPageNamed:@"autofocus-contenteditable"];
795     [webView stringByEvaluatingJavaScript:@"getSelection().removeAllRanges()"];
796
797     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
798     auto firstItem = adoptNS([[UIItemProvider alloc] init]);
799     [firstItem registerObject:[NSURL URLWithString:@"https://www.apple.com/iphone/"] visibility:UIItemProviderRepresentationOptionsVisibilityAll];
800     auto secondItem = adoptNS([[UIItemProvider alloc] init]);
801     [secondItem registerObject:[NSURL URLWithString:@"https://www.apple.com/mac/"] visibility:UIItemProviderRepresentationOptionsVisibilityAll];
802     auto thirdItem = adoptNS([[UIItemProvider alloc] init]);
803     [thirdItem registerObject:[NSURL URLWithString:@"https://webkit.org/"] visibility:UIItemProviderRepresentationOptionsVisibilityAll];
804     [dataInteractionSimulator setExternalItemProviders:@[ firstItem.get(), secondItem.get(), thirdItem.get() ]];
805     [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
806
807     NSArray *separatedLinks = [[webView stringByEvaluatingJavaScript:@"editor.textContent"] componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
808     EXPECT_EQ(3UL, separatedLinks.count);
809     EXPECT_WK_STREQ("https://www.apple.com/iphone/", separatedLinks[0]);
810     EXPECT_WK_STREQ("https://www.apple.com/mac/", separatedLinks[1]);
811     EXPECT_WK_STREQ("https://webkit.org/", separatedLinks[2]);
812 }
813
814 TEST(DataInteractionTests, RespectsExternalSourceFidelityRankings)
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     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
821
822     // Here, our source item provider vends two representations: plain text, and then an image. If we don't respect the
823     // fidelity order requested by the source, we'll end up assuming that the image is a higher fidelity representation
824     // than the plain text, and erroneously insert the image. If we respect source fidelities, we'll insert text rather
825     // than an image.
826     auto simulatedItemProviderWithTextFirst = adoptNS([[UIItemProvider alloc] init]);
827     [simulatedItemProviderWithTextFirst registerObject:@"Hello world" visibility:UIItemProviderRepresentationOptionsVisibilityAll];
828     [simulatedItemProviderWithTextFirst registerObject:testIconImage() visibility:UIItemProviderRepresentationOptionsVisibilityAll];
829     [dataInteractionSimulator setExternalItemProviders:@[ simulatedItemProviderWithTextFirst.get() ]];
830
831     [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
832     EXPECT_WK_STREQ("Hello world", [webView stringByEvaluatingJavaScript:@"editor.textContent"]);
833     EXPECT_FALSE([webView editorContainsImageElement]);
834     [webView stringByEvaluatingJavaScript:@"editor.innerHTML = ''"];
835
836     // Now we register the item providers in reverse, and expect the image to be inserted instead of text.
837     auto simulatedItemProviderWithImageFirst = adoptNS([[UIItemProvider alloc] init]);
838     [simulatedItemProviderWithImageFirst registerObject:testIconImage() visibility:UIItemProviderRepresentationOptionsVisibilityAll];
839     [simulatedItemProviderWithImageFirst registerObject:@"Hello world" visibility:UIItemProviderRepresentationOptionsVisibilityAll];
840     [dataInteractionSimulator setExternalItemProviders:@[ simulatedItemProviderWithImageFirst.get() ]];
841
842     [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
843     EXPECT_WK_STREQ("", [webView stringByEvaluatingJavaScript:@"editor.textContent"]);
844     EXPECT_TRUE([webView editorContainsImageElement]);
845 }
846
847 TEST(DataInteractionTests, ExternalSourceUTF8PlainTextOnly)
848 {
849     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
850     [webView synchronouslyLoadTestPageNamed:@"autofocus-contenteditable"];
851
852     NSString *textPayload = @"Ceci n'est pas une string";
853     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
854     auto simulatedItemProvider = adoptNS([[UIItemProvider alloc] init]);
855     [simulatedItemProvider registerDataRepresentationForTypeIdentifier:(__bridge NSString *)kUTTypeUTF8PlainText options:nil loadHandler:^NSProgress *(UIItemProviderDataLoadCompletionBlock completionBlock)
856     {
857         completionBlock([textPayload dataUsingEncoding:NSUTF8StringEncoding], nil);
858         return [NSProgress discreteProgressWithTotalUnitCount:100];
859     }];
860     [dataInteractionSimulator setExternalItemProviders:@[ simulatedItemProvider.get() ]];
861     [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
862     EXPECT_WK_STREQ(textPayload.UTF8String, [webView stringByEvaluatingJavaScript:@"editor.textContent"].UTF8String);
863     checkSelectionRectsWithLogging(@[ makeCGRectValue(1, 201, 1936, 227) ], [dataInteractionSimulator finalSelectionRects]);
864 }
865
866 TEST(DataInteractionTests, ExternalSourceJPEGOnly)
867 {
868     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
869     [webView synchronouslyLoadTestPageNamed:@"autofocus-contenteditable"];
870
871     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
872     auto simulatedItemProvider = adoptNS([[UIItemProvider alloc] init]);
873     [simulatedItemProvider registerDataRepresentationForTypeIdentifier:(__bridge NSString *)kUTTypeJPEG options:nil loadHandler:^NSProgress *(UIItemProviderDataLoadCompletionBlock completionBlock)
874     {
875         completionBlock(UIImageJPEGRepresentation(testIconImage(), 0.5), nil);
876         return [NSProgress discreteProgressWithTotalUnitCount:100];
877     }];
878     [dataInteractionSimulator setExternalItemProviders:@[ simulatedItemProvider.get() ]];
879     [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
880     EXPECT_TRUE([webView editorContainsImageElement]);
881     checkSelectionRectsWithLogging(@[ makeCGRectValue(1, 201, 215, 174) ], [dataInteractionSimulator finalSelectionRects]);
882 }
883
884 TEST(DataInteractionTests, ExternalSourceTitledNSURL)
885 {
886     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
887     [webView synchronouslyLoadTestPageNamed:@"autofocus-contenteditable"];
888     [webView stringByEvaluatingJavaScript:@"getSelection().removeAllRanges()"];
889
890     NSURL *titledURL = [NSURL URLWithString:@"https://www.apple.com"];
891     titledURL._title = @"Apple";
892     auto simulatedItemProvider = adoptNS([[UIItemProvider alloc] init]);
893     [simulatedItemProvider registerObject:titledURL visibility:UIItemProviderRepresentationOptionsVisibilityAll];
894
895     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
896     [dataInteractionSimulator setExternalItemProviders:@[ simulatedItemProvider.get() ]];
897     [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
898
899     EXPECT_WK_STREQ("Apple", [webView stringByEvaluatingJavaScript:@"editor.querySelector('a').textContent"]);
900     EXPECT_WK_STREQ("https://www.apple.com/", [webView stringByEvaluatingJavaScript:@"editor.querySelector('a').href"]);
901 }
902
903 TEST(DataInteractionTests, ExternalSourceFileURL)
904 {
905     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
906     [webView synchronouslyLoadTestPageNamed:@"autofocus-contenteditable"];
907     [webView stringByEvaluatingJavaScript:@"getSelection().removeAllRanges()"];
908
909     NSURL *URL = [NSURL URLWithString:@"file:///some/file/that/is/not/real"];
910     UIItemProvider *simulatedItemProvider = [UIItemProvider itemProviderWithURL:URL title:@""];
911
912     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
913     [dataInteractionSimulator setExternalItemProviders:@[ simulatedItemProvider ]];
914     [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
915
916     EXPECT_FALSE([[webView stringByEvaluatingJavaScript:@"!!editor.querySelector('a')"] boolValue]);
917     EXPECT_WK_STREQ("Hello world\nfile:///some/file/that/is/not/real", [webView stringByEvaluatingJavaScript:@"document.body.innerText"]);
918 }
919
920 TEST(DataInteractionTests, ExternalSourceOverrideDropFileUpload)
921 {
922     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
923     [webView synchronouslyLoadTestPageNamed:@"file-uploading"];
924
925     auto simulatedImageItemProvider = adoptNS([[UIItemProvider alloc] init]);
926     NSData *imageData = UIImageJPEGRepresentation(testIconImage(), 0.5);
927     [simulatedImageItemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeJPEG withData:imageData];
928
929     auto simulatedHTMLItemProvider = adoptNS([[UIItemProvider alloc] init]);
930     NSData *firstHTMLData = [@"<body contenteditable></body>" dataUsingEncoding:NSUTF8StringEncoding];
931     [simulatedHTMLItemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeHTML withData:firstHTMLData];
932
933     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
934     [dataInteractionSimulator setOverridePerformDropBlock:^NSArray<UIDragItem *> *(id <UIDropSession> session)
935     {
936         EXPECT_EQ(2UL, session.items.count);
937         UIDragItem *firstItem = session.items[0];
938         UIDragItem *secondItem = session.items[1];
939         EXPECT_TRUE([firstItem.itemProvider.registeredTypeIdentifiers isEqual:@[ (NSString *)kUTTypeJPEG ]]);
940         EXPECT_TRUE([secondItem.itemProvider.registeredTypeIdentifiers isEqual:@[ (NSString *)kUTTypeHTML ]]);
941         return @[ secondItem ];
942     }];
943     [dataInteractionSimulator setExternalItemProviders:@[ simulatedImageItemProvider.get(), simulatedHTMLItemProvider.get() ]];
944     [dataInteractionSimulator runFrom:CGPointMake(200, 300) to:CGPointMake(100, 300)];
945
946     NSString *outputValue = [webView stringByEvaluatingJavaScript:@"output.value"];
947     EXPECT_WK_STREQ("text/html", outputValue.UTF8String);
948 }
949
950 static RetainPtr<TestWKWebView> setUpTestWebViewForDataTransferItems()
951 {
952     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
953     [webView synchronouslyLoadTestPageNamed:@"DataTransferItem-getAsEntry"];
954
955     auto preferences = (WKPreferencesRef)[[webView configuration] preferences];
956     WKPreferencesSetDataTransferItemsEnabled(preferences, true);
957     WKPreferencesSetDirectoryUploadEnabled(preferences, true);
958
959     return webView;
960 }
961
962 TEST(DataInteractionTests, ExternalSourceDataTransferItemGetFolderAsEntry)
963 {
964     // The expected output is sorted by alphabetical order here for consistent behavior across different test environments.
965     // See DataTransferItem-getAsEntry.html for more details.
966     NSArray<NSString *> *expectedOutput = @[
967         @"Found data transfer item (kind: 'string', type: 'text/plain')",
968         @"Found data transfer item (kind: 'file', type: '')",
969         @"DIR: /somedirectory",
970         @"DIR: /somedirectory/subdirectory1",
971         @"DIR: /somedirectory/subdirectory2",
972         @"FILE: /somedirectory/archive.zip ('application/zip', 988 bytes)",
973         @"FILE: /somedirectory/icon.png ('image/png', 42130 bytes)",
974         @"FILE: /somedirectory/subdirectory1/text-file-1.txt ('text/plain', 43 bytes)",
975         @"FILE: /somedirectory/subdirectory2/text-file-2.txt ('text/plain', 44 bytes)"
976     ];
977
978     auto webView = setUpTestWebViewForDataTransferItems();
979     __block bool done = false;
980     [webView performAfterReceivingMessage:@"dropped" action:^() {
981         done = true;
982     }];
983
984     runTestWithTemporaryFolder(^(NSURL *folderURL) {
985         auto itemProvider = adoptNS([[NSItemProvider alloc] init]);
986         [itemProvider setSuggestedName:@"somedirectory"];
987         [itemProvider registerFileRepresentationForTypeIdentifier:(NSString *)kUTTypeFolder fileOptions:0 visibility:NSItemProviderRepresentationVisibilityAll loadHandler:[capturedFolderURL = retainPtr(folderURL)] (FileLoadCompletionBlock completionHandler) -> NSProgress * {
988             completionHandler(capturedFolderURL.get(), NO, nil);
989             return nil;
990         }];
991
992         auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
993         [dataInteractionSimulator setExternalItemProviders:@[ itemProvider.get() ]];
994         [dataInteractionSimulator runFrom:CGPointMake(50, 50) to:CGPointMake(150, 50)];
995     });
996
997     TestWebKitAPI::Util::run(&done);
998     EXPECT_WK_STREQ([expectedOutput componentsJoinedByString:@"\n"], [webView stringByEvaluatingJavaScript:@"output.value"]);
999 }
1000
1001 TEST(DataInteractionTests, ExternalSourceDataTransferItemGetPlainTextFileAsEntry)
1002 {
1003     NSArray<NSString *> *expectedOutput = @[
1004         @"Found data transfer item (kind: 'string', type: 'text/plain')",
1005         @"Found data transfer item (kind: 'file', type: 'text/plain')",
1006         @"FILE: /foo.txt ('text/plain', 28 bytes)"
1007     ];
1008
1009     auto webView = setUpTestWebViewForDataTransferItems();
1010     __block bool done = false;
1011     [webView performAfterReceivingMessage:@"dropped" action:^() {
1012         done = true;
1013     }];
1014
1015     runTestWithTemporaryTextFile(^(NSURL *fileURL) {
1016         auto itemProvider = adoptNS([[NSItemProvider alloc] init]);
1017         [itemProvider setSuggestedName:@"foo"];
1018         [itemProvider registerFileRepresentationForTypeIdentifier:(NSString *)kUTTypeUTF8PlainText fileOptions:0 visibility:NSItemProviderRepresentationVisibilityAll loadHandler:[capturedFileURL = retainPtr(fileURL)](FileLoadCompletionBlock completionHandler) -> NSProgress * {
1019             completionHandler(capturedFileURL.get(), NO, nil);
1020             return nil;
1021         }];
1022
1023         auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
1024         [dataInteractionSimulator setExternalItemProviders:@[ itemProvider.get() ]];
1025         [dataInteractionSimulator runFrom:CGPointMake(50, 50) to:CGPointMake(150, 50)];
1026     });
1027
1028     TestWebKitAPI::Util::run(&done);
1029     EXPECT_WK_STREQ([expectedOutput componentsJoinedByString:@"\n"], [webView stringByEvaluatingJavaScript:@"output.value"]);
1030 }
1031
1032 TEST(DataInteractionTests, ExternalSourceOverrideDropInsertURL)
1033 {
1034     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
1035     [webView synchronouslyLoadTestPageNamed:@"autofocus-contenteditable"];
1036     [webView stringByEvaluatingJavaScript:@"getSelection().removeAllRanges()"];
1037
1038     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
1039     [dataInteractionSimulator setOverridePerformDropBlock:^NSArray<UIDragItem *> *(id <UIDropSession> session)
1040     {
1041         NSMutableArray<UIDragItem *> *allowedItems = [NSMutableArray array];
1042         for (UIDragItem *item in session.items) {
1043             if ([item.itemProvider.registeredTypeIdentifiers containsObject:(NSString *)kUTTypeURL])
1044                 [allowedItems addObject:item];
1045         }
1046         EXPECT_EQ(1UL, allowedItems.count);
1047         return allowedItems;
1048     }];
1049
1050     auto firstItemProvider = adoptNS([[UIItemProvider alloc] init]);
1051     [firstItemProvider registerObject:@"This is a string." visibility:UIItemProviderRepresentationOptionsVisibilityAll];
1052     auto secondItemProvider = adoptNS([[UIItemProvider alloc] init]);
1053     [secondItemProvider registerObject:[NSURL URLWithString:@"https://webkit.org/"] visibility:UIItemProviderRepresentationOptionsVisibilityAll];
1054     [dataInteractionSimulator setExternalItemProviders:@[ firstItemProvider.get(), secondItemProvider.get() ]];
1055     [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
1056
1057     EXPECT_WK_STREQ("https://webkit.org/", [webView stringByEvaluatingJavaScript:@"editor.textContent"]);
1058 }
1059
1060 TEST(DataInteractionTests, OverrideDataInteractionOperation)
1061 {
1062     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
1063     [webView synchronouslyLoadTestPageNamed:@"simple"];
1064
1065     auto simulatedItemProvider = adoptNS([[UIItemProvider alloc] init]);
1066     [simulatedItemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeHTML withData:[@"<body></body>" dataUsingEncoding:NSUTF8StringEncoding]];
1067
1068     __block bool finishedLoadingData = false;
1069     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
1070     [dataInteractionSimulator setExternalItemProviders:@[ simulatedItemProvider.get() ]];
1071     [dataInteractionSimulator setOverrideDataInteractionOperationBlock:^NSUInteger(NSUInteger operation, id session)
1072     {
1073         EXPECT_EQ(0U, operation);
1074         return 1;
1075     }];
1076     [dataInteractionSimulator setDataInteractionOperationCompletionBlock:^(BOOL handled, NSArray *itemProviders) {
1077         EXPECT_FALSE(handled);
1078         [itemProviders.firstObject loadDataRepresentationForTypeIdentifier:(NSString *)kUTTypeHTML completionHandler:^(NSData *data, NSError *error) {
1079             NSString *text = [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease];
1080             EXPECT_WK_STREQ("<body></body>", text.UTF8String);
1081             EXPECT_FALSE(!!error);
1082             finishedLoadingData = true;
1083         }];
1084     }];
1085     [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
1086     TestWebKitAPI::Util::run(&finishedLoadingData);
1087 }
1088
1089 TEST(DataInteractionTests, InjectedBundleOverridePerformTwoStepDrop)
1090 {
1091     WKWebViewConfiguration *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"BundleEditingDelegatePlugIn"];
1092     [configuration.processPool _setObject:@YES forBundleParameter:@"BundleOverridePerformTwoStepDrop"];
1093
1094     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500) configuration:configuration]);
1095     [webView loadTestPageNamed:@"autofocus-contenteditable"];
1096     [webView stringByEvaluatingJavaScript:@"getSelection().removeAllRanges()"];
1097
1098     auto simulatedItemProvider = adoptNS([[UIItemProvider alloc] init]);
1099     [simulatedItemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeUTF8PlainText options:nil loadHandler:^NSProgress *(UIItemProviderDataLoadCompletionBlock completionBlock)
1100     {
1101         completionBlock([@"Hello world" dataUsingEncoding:NSUTF8StringEncoding], nil);
1102         return [NSProgress discreteProgressWithTotalUnitCount:100];
1103     }];
1104
1105     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
1106     [dataInteractionSimulator setExternalItemProviders:@[ simulatedItemProvider.get() ]];
1107     [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
1108
1109     EXPECT_EQ(0UL, [webView stringByEvaluatingJavaScript:@"editor.textContent"].length);
1110 }
1111
1112 TEST(DataInteractionTests, InjectedBundleAllowPerformTwoStepDrop)
1113 {
1114     WKWebViewConfiguration *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"BundleEditingDelegatePlugIn"];
1115     [configuration.processPool _setObject:@NO forBundleParameter:@"BundleOverridePerformTwoStepDrop"];
1116
1117     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500) configuration:configuration]);
1118     [webView loadTestPageNamed:@"autofocus-contenteditable"];
1119     [webView stringByEvaluatingJavaScript:@"getSelection().removeAllRanges()"];
1120
1121     auto simulatedItemProvider = adoptNS([[UIItemProvider alloc] init]);
1122     [simulatedItemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeUTF8PlainText options:nil loadHandler:^NSProgress *(UIItemProviderDataLoadCompletionBlock completionBlock)
1123     {
1124         completionBlock([@"Hello world" dataUsingEncoding:NSUTF8StringEncoding], nil);
1125         return [NSProgress discreteProgressWithTotalUnitCount:100];
1126     }];
1127
1128     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
1129     [dataInteractionSimulator setExternalItemProviders:@[ simulatedItemProvider.get() ]];
1130     [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
1131
1132     EXPECT_WK_STREQ("Hello world", [webView stringByEvaluatingJavaScript:@"editor.textContent"].UTF8String);
1133 }
1134
1135 TEST(DataInteractionTests, InjectedBundleImageElementData)
1136 {
1137     WKWebViewConfiguration *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"BundleEditingDelegatePlugIn"];
1138     [configuration _setAttachmentElementEnabled:YES];
1139     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500) configuration:configuration]);
1140     [webView synchronouslyLoadTestPageNamed:@"image-and-contenteditable"];
1141
1142     __block RetainPtr<NSString> injectedString;
1143     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
1144     [dataInteractionSimulator setConvertItemProvidersBlock:^NSArray *(UIItemProvider *itemProvider, NSArray *, NSDictionary *data)
1145     {
1146         injectedString = adoptNS([[NSString alloc] initWithData:data[InjectedBundlePasteboardDataType] encoding:NSUTF8StringEncoding]);
1147         return @[ itemProvider ];
1148     }];
1149
1150     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 250)];
1151
1152     EXPECT_WK_STREQ("hello", [injectedString UTF8String]);
1153 }
1154
1155 TEST(DataInteractionTests, InjectedBundleAttachmentElementData)
1156 {
1157     WKWebViewConfiguration *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"BundleEditingDelegatePlugIn"];
1158     [configuration _setAttachmentElementEnabled:YES];
1159     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500) configuration:configuration]);
1160     [webView synchronouslyLoadTestPageNamed:@"attachment-element"];
1161
1162     __block RetainPtr<NSString> injectedString;
1163     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
1164     [dataInteractionSimulator setConvertItemProvidersBlock:^NSArray *(UIItemProvider *itemProvider, NSArray *, NSDictionary *data)
1165     {
1166         injectedString = adoptNS([[NSString alloc] initWithData:data[InjectedBundlePasteboardDataType] encoding:NSUTF8StringEncoding]);
1167         return @[ itemProvider ];
1168     }];
1169
1170     [dataInteractionSimulator runFrom:CGPointMake(50, 50) to:CGPointMake(50, 400)];
1171
1172     EXPECT_WK_STREQ("hello", [injectedString UTF8String]);
1173     EXPECT_TRUE([webView stringByEvaluatingJavaScript:@"getSelection().isCollapsed"].boolValue);
1174 }
1175
1176 TEST(DataInteractionTests, LargeImageToTargetDiv)
1177 {
1178     auto testWebViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
1179     [[testWebViewConfiguration preferences] _setLargeImageAsyncDecodingEnabled:NO];
1180
1181     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500) configuration:testWebViewConfiguration.get()]);
1182     [webView synchronouslyLoadTestPageNamed:@"div-and-large-image"];
1183
1184     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
1185     [dataInteractionSimulator runFrom:CGPointMake(200, 400) to:CGPointMake(200, 150)];
1186     EXPECT_WK_STREQ("PASS", [webView stringByEvaluatingJavaScript:@"target.textContent"].UTF8String);
1187     checkTypeIdentifierAndIsNotOtherTypeIdentifier(dataInteractionSimulator.get(), (NSString *)kUTTypePNG, (NSString *)kUTTypeFileURL);
1188     checkEstimatedSize(dataInteractionSimulator.get(), { 2000, 2000 });
1189 }
1190
1191 TEST(DataInteractionTests, LinkWithEmptyHREF)
1192 {
1193     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
1194     [webView synchronouslyLoadTestPageNamed:@"link-and-input"];
1195     [webView stringByEvaluatingJavaScript:@"document.querySelector('a').href = ''"];
1196
1197     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
1198     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
1199
1200     EXPECT_EQ(DataInteractionCancelled, [dataInteractionSimulator phase]);
1201     EXPECT_WK_STREQ("", [webView editorValue].UTF8String);
1202 }
1203
1204 TEST(DataInteractionTests, CancelledLiftDoesNotCauseSubsequentDragsToFail)
1205 {
1206     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
1207     [webView synchronouslyLoadTestPageNamed:@"link-and-target-div"];
1208
1209     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
1210     [dataInteractionSimulator setConvertItemProvidersBlock:^NSArray *(UIItemProvider *, NSArray *, NSDictionary *)
1211     {
1212         return @[ ];
1213     }];
1214     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
1215     EXPECT_EQ(DataInteractionCancelled, [dataInteractionSimulator phase]);
1216     EXPECT_WK_STREQ("", [webView stringByEvaluatingJavaScript:@"target.textContent"]);
1217     NSString *outputText = [webView stringByEvaluatingJavaScript:@"output.textContent"];
1218     checkStringArraysAreEqual(@[@"dragstart", @"dragend"], [outputText componentsSeparatedByString:@" "]);
1219
1220     [webView stringByEvaluatingJavaScript:@"output.innerHTML = ''"];
1221     [dataInteractionSimulator setConvertItemProvidersBlock:^NSArray *(UIItemProvider *itemProvider, NSArray *, NSDictionary *)
1222     {
1223         return @[ itemProvider ];
1224     }];
1225     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
1226     EXPECT_WK_STREQ("PASS", [webView stringByEvaluatingJavaScript:@"target.textContent"]);
1227     [webView stringByEvaluatingJavaScript:@"output.textContent"];
1228     checkStringArraysAreEqual(@[@"dragstart", @"dragend"], [outputText componentsSeparatedByString:@" "]);
1229 }
1230
1231 static void testDragAndDropOntoTargetElements(TestWKWebView *webView)
1232 {
1233     auto simulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView]);
1234     [simulator runFrom:CGPointMake(50, 50) to:CGPointMake(50, 250)];
1235     EXPECT_WK_STREQ("rgb(0, 128, 0)", [webView stringByEvaluatingJavaScript:@"getComputedStyle(target1).backgroundColor"]);
1236     EXPECT_WK_STREQ("PASS", [webView stringByEvaluatingJavaScript:@"target1.textContent"]);
1237
1238     [simulator runFrom:CGPointMake(50, 50) to:CGPointMake(250, 50)];
1239     EXPECT_WK_STREQ("rgb(0, 128, 0)", [webView stringByEvaluatingJavaScript:@"getComputedStyle(target2).backgroundColor"]);
1240     EXPECT_WK_STREQ("PASS", [webView stringByEvaluatingJavaScript:@"target2.textContent"]);
1241
1242     [simulator runFrom:CGPointMake(50, 50) to:CGPointMake(250, 250)];
1243     EXPECT_WK_STREQ("rgb(0, 128, 0)", [webView stringByEvaluatingJavaScript:@"getComputedStyle(target3).backgroundColor"]);
1244     EXPECT_WK_STREQ("PASS", [webView stringByEvaluatingJavaScript:@"target3.textContent"]);
1245 }
1246
1247 TEST(DataInteractionTests, DragEventClientCoordinatesBasic)
1248 {
1249     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
1250     [webView synchronouslyLoadTestPageNamed:@"drop-targets"];
1251
1252     testDragAndDropOntoTargetElements(webView.get());
1253 }
1254
1255 TEST(DataInteractionTests, DragEventClientCoordinatesWithScrollOffset)
1256 {
1257     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
1258     [webView synchronouslyLoadTestPageNamed:@"drop-targets"];
1259     [webView stringByEvaluatingJavaScript:@"document.body.style.margin = '1000px 0'"];
1260     [webView stringByEvaluatingJavaScript:@"document.scrollingElement.scrollTop = 1000"];
1261     [webView waitForNextPresentationUpdate];
1262
1263     testDragAndDropOntoTargetElements(webView.get());
1264 }
1265
1266 TEST(DataInteractionTests, DragEventPageCoordinatesBasic)
1267 {
1268     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
1269     [webView synchronouslyLoadTestPageNamed:@"drop-targets"];
1270     [webView stringByEvaluatingJavaScript:@"window.usePageCoordinates = true"];
1271
1272     testDragAndDropOntoTargetElements(webView.get());
1273 }
1274
1275 TEST(DataInteractionTests, DragEventPageCoordinatesWithScrollOffset)
1276 {
1277     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
1278     [webView synchronouslyLoadTestPageNamed:@"drop-targets"];
1279     [webView stringByEvaluatingJavaScript:@"document.body.style.margin = '1000px 0'"];
1280     [webView stringByEvaluatingJavaScript:@"document.scrollingElement.scrollTop = 1000"];
1281     [webView stringByEvaluatingJavaScript:@"window.usePageCoordinates = true"];
1282     [webView waitForNextPresentationUpdate];
1283
1284     testDragAndDropOntoTargetElements(webView.get());
1285 }
1286
1287 TEST(DataInteractionTests, DoNotCrashWhenSelectionIsClearedInDragStart)
1288 {
1289     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
1290     [webView synchronouslyLoadTestPageNamed:@"dragstart-clear-selection"];
1291
1292     auto simulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
1293     [simulator runFrom:CGPointMake(100, 100) to:CGPointMake(100, 100)];
1294
1295     EXPECT_WK_STREQ("PASS", [webView stringByEvaluatingJavaScript:@"paragraph.textContent"]);
1296 }
1297
1298 TEST(DataInteractionTests, CustomActionSheetPopover)
1299 {
1300     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
1301     [webView synchronouslyLoadTestPageNamed:@"link-and-target-div"];
1302
1303     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
1304     [dataInteractionSimulator setShouldEnsureUIApplication:YES];
1305
1306     __block BOOL didInvokeCustomActionSheet = NO;
1307     [dataInteractionSimulator setShowCustomActionSheetBlock:^BOOL(_WKActivatedElementInfo *element)
1308     {
1309         EXPECT_EQ(_WKActivatedElementTypeLink, element.type);
1310         EXPECT_WK_STREQ("Hello world", element.title.UTF8String);
1311         didInvokeCustomActionSheet = YES;
1312         return YES;
1313     }];
1314     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
1315     EXPECT_TRUE(didInvokeCustomActionSheet);
1316     EXPECT_WK_STREQ("PASS", [webView stringByEvaluatingJavaScript:@"target.textContent"].UTF8String);
1317 }
1318
1319 TEST(DataInteractionTests, UnresponsivePageDoesNotHangUI)
1320 {
1321     _WKProcessPoolConfiguration *processPoolConfiguration = [[[_WKProcessPoolConfiguration alloc] init] autorelease];
1322     processPoolConfiguration.ignoreSynchronousMessagingTimeoutsForTesting = YES;
1323
1324     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500) configuration:[[[WKWebViewConfiguration alloc] init] autorelease] processPoolConfiguration:processPoolConfiguration]);
1325     [webView synchronouslyLoadTestPageNamed:@"simple"];
1326     [webView evaluateJavaScript:@"while(1);" completionHandler:nil];
1327
1328     // The test passes if we can prepare for data interaction without timing out.
1329     auto dragSession = adoptNS([[MockDragSession alloc] init]);
1330     [(id <UIDragInteractionDelegate_ForWebKitOnly>)[webView dragInteractionDelegate] _dragInteraction:[webView dragInteraction] prepareForSession:dragSession.get() completion:^() { }];
1331 }
1332
1333 TEST(DataInteractionTests, WebItemProviderPasteboardLoading)
1334 {
1335     static NSString *fastString = @"This data loads quickly";
1336     static NSString *slowString = @"This data loads slowly";
1337
1338     WebItemProviderPasteboard *pasteboard = [WebItemProviderPasteboard sharedInstance];
1339     auto fastItem = adoptNS([[UIItemProvider alloc] init]);
1340     [fastItem registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeUTF8PlainText options:nil loadHandler:^NSProgress *(UIItemProviderDataLoadCompletionBlock completionBlock)
1341     {
1342         completionBlock([fastString dataUsingEncoding:NSUTF8StringEncoding], nil);
1343         return nil;
1344     }];
1345
1346     auto slowItem = adoptNS([[UIItemProvider alloc] init]);
1347     [slowItem registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeUTF8PlainText options:nil loadHandler:^NSProgress *(UIItemProviderDataLoadCompletionBlock completionBlock)
1348     {
1349         sleep(2);
1350         completionBlock([slowString dataUsingEncoding:NSUTF8StringEncoding], nil);
1351         return nil;
1352     }];
1353
1354     __block bool hasRunFirstCompletionBlock = false;
1355     pasteboard.itemProviders = @[ fastItem.get(), slowItem.get() ];
1356     [pasteboard doAfterLoadingProvidedContentIntoFileURLs:^(NSArray<NSURL *> *urls) {
1357         EXPECT_EQ(2UL, urls.count);
1358         auto firstString = adoptNS([[NSString alloc] initWithContentsOfURL:urls[0] encoding:NSUTF8StringEncoding error:nil]);
1359         auto secondString = adoptNS([[NSString alloc] initWithContentsOfURL:urls[1] encoding:NSUTF8StringEncoding error:nil]);
1360         EXPECT_WK_STREQ(fastString, [firstString UTF8String]);
1361         EXPECT_WK_STREQ(slowString, [secondString UTF8String]);
1362         hasRunFirstCompletionBlock = true;
1363     } synchronousTimeout:600];
1364     EXPECT_TRUE(hasRunFirstCompletionBlock);
1365
1366     __block bool hasRunSecondCompletionBlock = false;
1367     [pasteboard doAfterLoadingProvidedContentIntoFileURLs:^(NSArray<NSURL *> *urls) {
1368         EXPECT_EQ(2UL, urls.count);
1369         auto firstString = adoptNS([[NSString alloc] initWithContentsOfURL:urls[0] encoding:NSUTF8StringEncoding error:nil]);
1370         auto secondString = adoptNS([[NSString alloc] initWithContentsOfURL:urls[1] encoding:NSUTF8StringEncoding error:nil]);
1371         EXPECT_WK_STREQ(fastString, [firstString UTF8String]);
1372         EXPECT_WK_STREQ(slowString, [secondString UTF8String]);
1373         hasRunSecondCompletionBlock = true;
1374     } synchronousTimeout:0];
1375     EXPECT_FALSE(hasRunSecondCompletionBlock);
1376     TestWebKitAPI::Util::run(&hasRunSecondCompletionBlock);
1377 }
1378
1379 TEST(DataInteractionTests, DoNotCrashWhenSelectionMovesOffscreenAfterDragStart)
1380 {
1381     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
1382     [webView synchronouslyLoadTestPageNamed:@"dragstart-change-selection-offscreen"];
1383
1384     auto simulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
1385     [simulator runFrom:CGPointMake(100, 100) to:CGPointMake(100, 100)];
1386
1387     EXPECT_WK_STREQ("FAR OFFSCREEN", [webView stringByEvaluatingJavaScript:@"getSelection().getRangeAt(0).toString()"]);
1388 }
1389
1390 TEST(DataInteractionTests, AdditionalItemsCanBePreventedOnDragStart)
1391 {
1392     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
1393     [webView synchronouslyLoadTestPageNamed:@"selected-text-image-link-and-editable"];
1394     [webView stringByEvaluatingJavaScript:@"link.addEventListener('dragstart', e => e.preventDefault())"];
1395     [webView stringByEvaluatingJavaScript:@"image.addEventListener('dragstart', e => e.preventDefault())"];
1396
1397     auto simulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
1398     [simulator runFrom:CGPointMake(50, 50) to:CGPointMake(50, 400) additionalItemRequestLocations:@{
1399         @0.33: [NSValue valueWithCGPoint:CGPointMake(50, 150)],
1400         @0.66: [NSValue valueWithCGPoint:CGPointMake(50, 250)]
1401     }];
1402     EXPECT_WK_STREQ("ABCD", [webView stringByEvaluatingJavaScript:@"editor.textContent"]);
1403 }
1404
1405 TEST(DataInteractionTests, AdditionalLinkAndImageIntoContentEditable)
1406 {
1407     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
1408     [webView synchronouslyLoadTestPageNamed:@"selected-text-image-link-and-editable"];
1409
1410     auto simulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
1411     [simulator runFrom:CGPointMake(50, 50) to:CGPointMake(50, 400) additionalItemRequestLocations:@{
1412         @0.33: [NSValue valueWithCGPoint:CGPointMake(50, 150)],
1413         @0.66: [NSValue valueWithCGPoint:CGPointMake(50, 250)]
1414     }];
1415     EXPECT_WK_STREQ("ABCD A link", [webView stringByEvaluatingJavaScript:@"editor.textContent"]);
1416     EXPECT_TRUE([webView stringByEvaluatingJavaScript:@"!!editor.querySelector('img')"]);
1417     EXPECT_WK_STREQ("https://www.apple.com/", [webView stringByEvaluatingJavaScript:@"editor.querySelector('a').href"]);
1418 }
1419
1420 TEST(DataInteractionTests, DragLiftPreviewDataTransferSetDragImage)
1421 {
1422     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
1423     [webView synchronouslyLoadTestPageNamed:@"DataTransfer-setDragImage"];
1424     auto simulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
1425
1426     // Use DataTransfer.setDragImage to specify an existing image element in the DOM.
1427     [simulator runFrom:CGPointMake(100, 50) to:CGPointMake(250, 50)];
1428     checkCGRectIsEqualToCGRectWithLogging({{100, 50}, {215, 174}}, [simulator liftPreviews][0].view.frame);
1429
1430     // Use DataTransfer.setDragImage to specify an existing image element in the DOM, with x and y offsets.
1431     [simulator runFrom:CGPointMake(10, 150) to:CGPointMake(250, 150)];
1432     checkCGRectIsEqualToCGRectWithLogging({{-90, 50}, {215, 174}}, [simulator liftPreviews][0].view.frame);
1433
1434     // Use DataTransfer.setDragImage to specify a newly created Image, disconnected from the DOM.
1435     [simulator runFrom:CGPointMake(100, 250) to:CGPointMake(250, 250)];
1436     checkCGRectIsEqualToCGRectWithLogging({{100, 250}, {215, 174}}, [simulator liftPreviews][0].view.frame);
1437
1438     // Don't use DataTransfer.setDragImage and fall back to snapshotting the dragged element.
1439     [simulator runFrom:CGPointMake(50, 350) to:CGPointMake(250, 350)];
1440     checkCGRectIsEqualToCGRectWithLogging({{0, 300}, {300, 100}}, [simulator liftPreviews][0].view.frame);
1441
1442     // Perform a normal drag on an image.
1443     [simulator runFrom:CGPointMake(50, 450) to:CGPointMake(250, 450)];
1444     checkCGRectIsEqualToCGRectWithLogging({{0, 400}, {215, 174}}, [simulator liftPreviews][0].view.frame);
1445 }
1446
1447 } // namespace TestWebKitAPI
1448
1449 #endif // ENABLE(DATA_INTERACTION)