Unreviewed test gardening for iOS API tests.
[WebKit-https.git] / Tools / TestWebKitAPI / Tests / WebKitCocoa / ContextMenus.mm
1 /*
2  * Copyright (C) 2019 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 #import "config.h"
27
28 #if PLATFORM(IOS) && USE(UICONTEXTMENU)
29
30 #import "TestContextMenuDriver.h"
31 #import "TestWKWebView.h"
32 #import "TestWKWebViewController.h"
33 #import "Utilities.h"
34 #import <WebKit/WKWebViewConfigurationPrivate.h>
35 #import <WebKit/WebKit.h>
36
37 static bool contextMenuRequested;
38 static bool contextMenuSPIRequested;
39 static bool willPresentCalled;
40 static bool willCommitCalled;
41 static bool previewingViewControllerCalled;
42 static bool previewActionItemsCalled;
43 static bool didEndCalled;
44 static bool alternateURLRequested;
45 static RetainPtr<NSURL> linkURL;
46
47 static RetainPtr<TestContextMenuDriver> contextMenuWebViewDriver(Class delegateClass, NSString *customHTMLString = nil)
48 {
49     static auto window = adoptNS([[UIWindow alloc] initWithFrame:NSMakeRect(0, 0, 800, 600)]);
50     static auto driver = adoptNS([TestContextMenuDriver new]);
51     static auto uiDelegate = adoptNS((NSObject<WKUIDelegate> *)[delegateClass new]);
52     static auto configuration = adoptNS([WKWebViewConfiguration new]);
53     [configuration _setClickInteractionDriverForTesting:driver.get()];
54     static auto webViewController = adoptNS([[TestWKWebViewController alloc] initWithFrame:CGRectMake(0, 0, 200, 200) configuration:configuration.get()]);
55     TestWKWebView *webView = [webViewController webView];
56     [window addSubview:webView];
57     [webView setUIDelegate:uiDelegate.get()];
58     if (!customHTMLString) {
59         linkURL = [NSURL URLWithString:@"http://127.0.0.1/"];
60         [webView synchronouslyLoadHTMLString:[NSString stringWithFormat:@"<a href='%@'>This is a link</a>", linkURL.get()]];
61     } else
62         [webView synchronouslyLoadHTMLString:customHTMLString];
63     return driver;
64 }
65
66 @interface TestContextMenuUIDelegate : NSObject <WKUIDelegate>
67 @end
68
69 @implementation TestContextMenuUIDelegate
70
71 - (void)webView:(WKWebView *)webView contextMenuConfigurationForElement:(WKContextMenuElementInfo *)elementInfo completionHandler:(void(^)(UIContextMenuConfiguration * _Nullable))completionHandler
72 {
73     EXPECT_TRUE([elementInfo.linkURL.absoluteString isEqualToString:[linkURL absoluteString]]);
74     contextMenuRequested = true;
75     UIContextMenuContentPreviewProvider previewProvider = ^UIViewController * ()
76     {
77         return [[[UIViewController alloc] init] autorelease];
78     };
79     UIContextMenuActionProvider actionProvider = ^UIMenu *(NSArray<UIMenuElement *> *suggestedActions)
80     {
81         return [UIMenu menuWithTitle:@"" children:suggestedActions];
82     };
83     completionHandler([UIContextMenuConfiguration configurationWithIdentifier:nil previewProvider:previewProvider actionProvider:actionProvider]);
84 }
85
86 - (void)webView:(WKWebView *)webView contextMenuWillPresentForElement:(WKContextMenuElementInfo *)elementInfo
87 {
88     willPresentCalled = true;
89 }
90
91 - (void)webView:(WKWebView *)webView contextMenuForElement:(WKContextMenuElementInfo *)elementInfo willCommitWithAnimator:(id<UIContextMenuInteractionCommitAnimating>)animator
92 {
93     willCommitCalled = true;
94 }
95
96 - (void)webView:(WKWebView *)webView contextMenuDidEndForElement:(WKContextMenuElementInfo *)elementInfo
97 {
98     didEndCalled = true;
99 }
100
101 @end
102
103 // FIXME: Re-enable this test once rdar://59610140 is resolved
104 TEST(ContextMenu, DISABLED_Click)
105 {
106     auto driver = contextMenuWebViewDriver([TestContextMenuUIDelegate class]);
107     [driver begin:^(BOOL result) {
108         EXPECT_TRUE(result);
109         [driver clickDown];
110         [driver clickUp];
111     }];
112     TestWebKitAPI::Util::run(&willPresentCalled);
113     EXPECT_TRUE(contextMenuRequested);
114     EXPECT_TRUE(willPresentCalled);
115     EXPECT_FALSE(willCommitCalled);
116     EXPECT_FALSE(didEndCalled);
117 }
118
119 // FIXME: Re-enable this test once rdar://59610140 is resolved
120 TEST(ContextMenu, DISABLED_End)
121 {
122     auto driver = contextMenuWebViewDriver([TestContextMenuUIDelegate class]);
123     [driver begin:^(BOOL result) {
124         EXPECT_TRUE(result);
125         [driver end];
126     }];
127     TestWebKitAPI::Util::run(&didEndCalled);
128     EXPECT_TRUE(contextMenuRequested);
129     EXPECT_FALSE(willPresentCalled);
130     EXPECT_FALSE(willCommitCalled);
131     EXPECT_TRUE(didEndCalled);
132 }
133
134 @interface TestContextMenuAPIBeforeSPIUIDelegate : NSObject <WKUIDelegate>
135 @end
136
137 @implementation TestContextMenuAPIBeforeSPIUIDelegate
138
139 - (void)webView:(WKWebView *)webView contextMenuConfigurationForElement:(WKContextMenuElementInfo *)elementInfo completionHandler:(void(^)(UIContextMenuConfiguration * _Nullable))completionHandler
140 {
141     contextMenuRequested = true;
142     UIContextMenuContentPreviewProvider previewProvider = ^UIViewController * ()
143     {
144         return [[[UIViewController alloc] init] autorelease];
145     };
146     UIContextMenuActionProvider actionProvider = ^UIMenu *(NSArray<UIMenuElement *> *suggestedActions)
147     {
148         return [UIMenu menuWithTitle:@"" children:suggestedActions];
149     };
150     completionHandler([UIContextMenuConfiguration configurationWithIdentifier:nil previewProvider:previewProvider actionProvider:actionProvider]);
151 }
152
153 - (void)_webView:(WKWebView *)webView contextMenuConfigurationForElement:(WKContextMenuElementInfo *)elementInfo completionHandler:(void(^)(UIContextMenuConfiguration * _Nullable))completionHandler
154 {
155     contextMenuSPIRequested = true;
156     completionHandler(nil);
157 }
158
159 - (void)webView:(WKWebView *)webView contextMenuWillPresentForElement:(WKContextMenuElementInfo *)elementInfo
160 {
161     willPresentCalled = true;
162 }
163
164 @end
165
166 // FIXME: Re-enable this test once rdar://59610140 is resolved
167 TEST(ContextMenu, DISABLED_APIBeforeSPI)
168 {
169     auto driver = contextMenuWebViewDriver([TestContextMenuAPIBeforeSPIUIDelegate class]);
170     [driver begin:^(BOOL result) {
171         EXPECT_TRUE(result);
172         [driver clickDown];
173         [driver clickUp];
174     }];
175     TestWebKitAPI::Util::run(&willPresentCalled);
176     EXPECT_TRUE(contextMenuRequested);
177     EXPECT_FALSE(contextMenuSPIRequested);
178 }
179
180 @interface TestContextMenuImageUIDelegate : NSObject <WKUIDelegate>
181 @end
182
183 @implementation TestContextMenuImageUIDelegate
184
185 - (void)_webView:(WKWebView *)webView contextMenuConfigurationForElement:(WKContextMenuElementInfo *)elementInfo completionHandler:(void(^)(UIContextMenuConfiguration * _Nullable))completionHandler
186 {
187     contextMenuRequested = true;
188     completionHandler(nil);
189 }
190
191 - (NSURL *)_webView:(WKWebView *)webView alternateURLFromImage:(UIImage *)image userInfo:(NSDictionary **)userInfo
192 {
193     alternateURLRequested = true;
194     return linkURL.get();
195 }
196
197 - (void)webView:(WKWebView *)webView contextMenuWillPresentForElement:(WKContextMenuElementInfo *)elementInfo
198 {
199     willPresentCalled = true;
200     EXPECT_TRUE([elementInfo.linkURL.absoluteString isEqualToString:[linkURL absoluteString]]);
201 }
202
203 - (void)webView:(WKWebView *)webView contextMenuForElement:(WKContextMenuElementInfo *)elementInfo willCommitWithAnimator:(id<UIContextMenuInteractionCommitAnimating>)animator
204 {
205     willCommitCalled = true;
206 }
207
208 - (void)webView:(WKWebView *)webView contextMenuDidEndForElement:(WKContextMenuElementInfo *)elementInfo
209 {
210     didEndCalled = true;
211 }
212
213 @end
214
215 // FIXME: Re-enable this test once rdar://59610140 is resolved
216 TEST(ContextMenu, DISABLED_Image)
217 {
218     linkURL = [NSURL URLWithString:@"http://127.0.0.1/image"];
219     auto driver = contextMenuWebViewDriver([TestContextMenuImageUIDelegate class], @"<img style='width:400px;height:400px' src='data:image/png;base64,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'>");
220     [driver begin:^(BOOL result) {
221         EXPECT_TRUE(result);
222         [driver clickDown];
223         [driver clickUp];
224     }];
225     TestWebKitAPI::Util::run(&willPresentCalled);
226     EXPECT_TRUE(contextMenuRequested);
227     EXPECT_TRUE(alternateURLRequested);
228     EXPECT_TRUE(willPresentCalled);
229     EXPECT_FALSE(willCommitCalled);
230     EXPECT_FALSE(didEndCalled);
231 }
232
233 #pragma clang diagnostic push
234 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
235 #pragma clang diagnostic ignored "-Wdeprecated-implementations"
236
237 @interface LegacyPreviewViewController : UIViewController
238 @end
239
240 @implementation LegacyPreviewViewController
241
242 - (NSArray<UIPreviewAction *> *)previewActionItems
243 {
244     previewActionItemsCalled = true;
245     return @[
246         [UIPreviewAction actionWithTitle:@"Action" style:UIPreviewActionStyleDefault handler:^(UIPreviewAction *, UIViewController *) { }]
247     ];
248 }
249
250 @end
251
252 @interface LegacyContextMenuUIDelegate : NSObject <WKUIDelegate>
253 @end
254
255 @implementation LegacyContextMenuUIDelegate
256
257 - (BOOL)webView:(WKWebView *)webView shouldPreviewElement:(WKPreviewElementInfo *)elementInfo
258 {
259     EXPECT_TRUE([elementInfo.linkURL.absoluteString isEqualToString:[linkURL absoluteString]]);
260     contextMenuRequested = true;
261     return YES;
262 }
263
264 - (UIViewController *)webView:(WKWebView *)webView previewingViewControllerForElement:(WKPreviewElementInfo *)elementInfo defaultActions:(NSArray<id <WKPreviewActionItem>> *)previewActions
265 {
266     EXPECT_TRUE(previewActions.count);
267     previewingViewControllerCalled = true;
268     return [LegacyPreviewViewController new];
269 }
270
271 /* Even though this is non-legacy API, it should not be enough to trigger the non-legacy flow. */
272 - (void)webView:(WKWebView *)webView contextMenuWillPresentForElement:(WKContextMenuElementInfo *)elementInfo
273 {
274     willPresentCalled = true;
275 }
276
277 /* Even though this is non-legacy API, it should not be enough to trigger the non-legacy flow. */
278 - (void)_webView:(WKWebView *)webView contextMenuDidEndForElement:(WKContextMenuElementInfo *)elementInfo
279 {
280 }
281
282 @end
283
284 // FIXME: Re-enable this test once rdar://59610140 is resolved
285 TEST(ContextMenu, DISABLED_Legacy)
286 {
287     auto driver = contextMenuWebViewDriver([LegacyContextMenuUIDelegate class]);
288     [driver begin:^(BOOL result) {
289         EXPECT_TRUE(result);
290         [driver clickDown];
291         [driver clickUp];
292     }];
293     TestWebKitAPI::Util::run(&previewActionItemsCalled);
294     EXPECT_TRUE(contextMenuRequested);
295     EXPECT_TRUE(previewingViewControllerCalled);
296     EXPECT_TRUE(willPresentCalled);
297 }
298
299 #pragma clang diagnostic pop
300
301 @interface TestContextMenuSuggestedActionsUIDelegate : NSObject <WKUIDelegate>
302 @end
303
304 @implementation TestContextMenuSuggestedActionsUIDelegate
305
306 - (void)webView:(WKWebView *)webView contextMenuConfigurationForElement:(WKContextMenuElementInfo *)elementInfo completionHandler:(void(^)(UIContextMenuConfiguration * _Nullable))completionHandler
307 {
308     EXPECT_TRUE([elementInfo.linkURL.absoluteString isEqualToString:[linkURL absoluteString]]);
309     contextMenuRequested = true;
310     UIContextMenuContentPreviewProvider previewProvider = ^UIViewController * ()
311     {
312         return [[[UIViewController alloc] init] autorelease];
313     };
314     UIContextMenuActionProvider actionProvider = ^UIMenu *(NSArray<UIMenuElement *> *suggestedActions)
315     {
316         NSArray<NSString *> *expectedIdentifiers = @[
317             @"WKElementActionTypeOpen",
318             @"WKElementActionTypeAddToReadingList",
319             @"WKElementActionTypeCopy",
320             @"WKElementActionTypeShare"
321         ];
322         EXPECT_TRUE(expectedIdentifiers.count == suggestedActions.count);
323
324         [suggestedActions enumerateObjectsUsingBlock:^(UIMenuElement *menuElement, NSUInteger index, BOOL *) {
325             EXPECT_TRUE([menuElement isKindOfClass:[UIAction class]]);
326             EXPECT_TRUE([[(UIAction *)menuElement identifier] isEqualToString:expectedIdentifiers[index]]);
327         }];
328         return [UIMenu menuWithTitle:@"" children:suggestedActions];
329     };
330     completionHandler([UIContextMenuConfiguration configurationWithIdentifier:nil previewProvider:previewProvider actionProvider:actionProvider]);
331 }
332
333 - (void)webView:(WKWebView *)webView contextMenuWillPresentForElement:(WKContextMenuElementInfo *)elementInfo
334 {
335     willPresentCalled = true;
336 }
337
338 @end
339
340
341 // FIXME: Re-enable this test once rdar://59610140 is resolved
342 TEST(ContextMenu, DISABLED_SuggestedActions)
343 {
344     auto driver = contextMenuWebViewDriver([TestContextMenuSuggestedActionsUIDelegate class]);
345     [driver begin:^(BOOL result) {
346         EXPECT_TRUE(result);
347         [driver clickDown];
348         [driver clickUp];
349     }];
350     TestWebKitAPI::Util::run(&willPresentCalled);
351     EXPECT_TRUE(contextMenuRequested);
352     EXPECT_TRUE(willPresentCalled);
353 }
354
355 #endif // PLATFORM(IOS) && USE(UICONTEXTMENU)