| /* |
| * Copyright (C) 2017-2018 Apple Inc. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' |
| * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
| * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS |
| * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
| * THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #import "config.h" |
| |
| #import "PlatformUtilities.h" |
| #import "TestWKWebView.h" |
| #import "Utilities.h" |
| #import "WKWebViewConfigurationExtras.h" |
| #import <WebKit/WKContext.h> |
| #import <WebKit/WKContextPrivateMac.h> |
| #import <WebKit/WKGeolocationManager.h> |
| #import <WebKit/WKGeolocationPosition.h> |
| #import <WebKit/WKPreferencesPrivate.h> |
| #import <WebKit/WKRetainPtr.h> |
| #import <WebKit/WKUIDelegatePrivate.h> |
| #import <WebKit/WKWebViewPrivate.h> |
| #import <WebKit/_WKHitTestResult.h> |
| #import <wtf/RetainPtr.h> |
| #import <wtf/Vector.h> |
| |
| #if PLATFORM(MAC) |
| #import <Carbon/Carbon.h> |
| #import <wtf/mac/AppKitCompatibilityDeclarations.h> |
| #endif |
| |
| static bool done; |
| |
| @interface AudioObserver : NSObject |
| @end |
| |
| @implementation AudioObserver |
| |
| - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *, id> *)change context:(void *)context |
| { |
| EXPECT_TRUE([keyPath isEqualToString:NSStringFromSelector(@selector(_isPlayingAudio))]); |
| EXPECT_TRUE([[object class] isEqual:[TestWKWebView class]]); |
| EXPECT_FALSE([[change objectForKey:NSKeyValueChangeOldKey] boolValue]); |
| EXPECT_TRUE([[change objectForKey:NSKeyValueChangeNewKey] boolValue]); |
| EXPECT_TRUE(context == nullptr); |
| done = true; |
| } |
| |
| @end |
| |
| TEST(WebKit, WKWebViewIsPlayingAudio) |
| { |
| auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 800, 600) configuration:[[[WKWebViewConfiguration alloc] init] autorelease]]); |
| auto observer = adoptNS([[AudioObserver alloc] init]); |
| [webView addObserver:observer.get() forKeyPath:@"_isPlayingAudio" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil]; |
| [webView synchronouslyLoadTestPageNamed:@"file-with-video"]; |
| [webView evaluateJavaScript:@"playVideo()" completionHandler:nil]; |
| TestWebKitAPI::Util::run(&done); |
| } |
| |
| @interface NoUIDelegate : NSObject <WKNavigationDelegate> |
| @end |
| |
| @implementation NoUIDelegate |
| |
| - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler |
| { |
| if ([navigationAction.request.URL.absoluteString isEqualToString:[[[NSBundle mainBundle] URLForResource:@"simple" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"] absoluteString]]) |
| done = true; |
| decisionHandler(WKNavigationActionPolicyAllow); |
| } |
| |
| @end |
| |
| TEST(WebKit, WindowOpenWithoutUIDelegate) |
| { |
| done = false; |
| auto webView = adoptNS([[WKWebView alloc] init]); |
| auto delegate = adoptNS([[NoUIDelegate alloc] init]); |
| [webView setNavigationDelegate:delegate.get()]; |
| [webView loadHTMLString:@"<script>window.open('simple2.html');window.location='simple.html'</script>" baseURL:[[NSBundle mainBundle] URLForResource:@"simple2" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]]; |
| TestWebKitAPI::Util::run(&done); |
| } |
| |
| @interface GeolocationDelegate : NSObject <WKUIDelegatePrivate> { |
| bool _allowGeolocation; |
| } |
| |
| - (id)initWithAllowGeolocation:(bool)allowGeolocation; |
| |
| @end |
| |
| @implementation GeolocationDelegate |
| |
| - (id)initWithAllowGeolocation:(bool)allowGeolocation |
| { |
| if (!(self = [super init])) |
| return nil; |
| _allowGeolocation = allowGeolocation; |
| return self; |
| } |
| |
| - (void)_webView:(WKWebView *)webView requestGeolocationPermissionForFrame:(WKFrameInfo *)frame decisionHandler:(void (^)(BOOL allowed))decisionHandler |
| { |
| EXPECT_TRUE(frame.isMainFrame); |
| EXPECT_STREQ(frame.request.URL.absoluteString.UTF8String, _allowGeolocation ? "https://example.org/" : "https://example.com/"); |
| EXPECT_EQ(frame.securityOrigin.port, 0); |
| EXPECT_STREQ(frame.securityOrigin.protocol.UTF8String, "https"); |
| EXPECT_STREQ(frame.securityOrigin.host.UTF8String, _allowGeolocation ? "example.org" : "example.com"); |
| decisionHandler(_allowGeolocation); |
| } |
| |
| - (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler |
| { |
| if (_allowGeolocation) |
| EXPECT_STREQ(message.UTF8String, "position 50.644358 3.345453"); |
| else |
| EXPECT_STREQ(message.UTF8String, "error 1 User denied Geolocation"); |
| completionHandler(); |
| done = true; |
| } |
| |
| @end |
| |
| TEST(WebKit, GeolocationPermission) |
| { |
| NSString *html = @"<script>navigator.geolocation.watchPosition(" |
| "function(p) { alert('position ' + p.coords.latitude + ' ' + p.coords.longitude) }," |
| "function(e) { alert('error ' + e.code + ' ' + e.message) })" |
| "</script>"; |
| |
| auto pool = adoptNS([[WKProcessPool alloc] init]); |
| |
| WKGeolocationProviderV1 providerCallback; |
| memset(&providerCallback, 0, sizeof(WKGeolocationProviderV1)); |
| providerCallback.base.version = 1; |
| providerCallback.startUpdating = [] (WKGeolocationManagerRef manager, const void*) { |
| WKGeolocationManagerProviderDidChangePosition(manager, adoptWK(WKGeolocationPositionCreate(0, 50.644358, 3.345453, 2.53)).get()); |
| }; |
| WKGeolocationManagerSetProvider(WKContextGetGeolocationManager((WKContextRef)pool.get()), &providerCallback.base); |
| |
| auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| configuration.get().processPool = pool.get(); |
| auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 800, 600) configuration:configuration.get()]); |
| auto delegate1 = adoptNS([[GeolocationDelegate alloc] initWithAllowGeolocation:false]); |
| [webView setUIDelegate:delegate1.get()]; |
| [webView loadHTMLString:html baseURL:[NSURL URLWithString:@"https://example.com/"]]; |
| TestWebKitAPI::Util::run(&done); |
| |
| done = false; |
| auto delegate2 = adoptNS([[GeolocationDelegate alloc] initWithAllowGeolocation:true]); |
| [webView setUIDelegate:delegate2.get()]; |
| [webView loadHTMLString:html baseURL:[NSURL URLWithString:@"https://example.org/"]]; |
| TestWebKitAPI::Util::run(&done); |
| } |
| |
| @interface InjectedBundleNodeHandleIsSelectElementDelegate : NSObject <WKUIDelegatePrivate> |
| @end |
| |
| @implementation InjectedBundleNodeHandleIsSelectElementDelegate |
| |
| - (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)())completionHandler |
| { |
| completionHandler(); |
| done = true; |
| ASSERT_STREQ(message.UTF8String, "isSelectElement success"); |
| } |
| |
| @end |
| |
| TEST(WebKit, InjectedBundleNodeHandleIsSelectElement) |
| { |
| WKWebViewConfiguration *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"InjectedBundleNodeHandleIsSelectElement"]; |
| |
| auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 800, 600) configuration:configuration]); |
| auto delegate = adoptNS([[InjectedBundleNodeHandleIsSelectElementDelegate alloc] init]); |
| [webView setUIDelegate:delegate.get()]; |
| [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"about:blank"]]]; |
| TestWebKitAPI::Util::run(&done); |
| } |
| |
| #if PLATFORM(MAC) |
| |
| @class UITestDelegate; |
| |
| static RetainPtr<WKWebView> webViewFromDelegateCallback; |
| static RetainPtr<WKWebView> createdWebView; |
| static RetainPtr<UITestDelegate> delegate; |
| |
| @interface UITestDelegate : NSObject <WKUIDelegatePrivate, WKURLSchemeHandler> |
| @end |
| |
| @implementation UITestDelegate |
| |
| - (nullable WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures |
| { |
| createdWebView = adoptNS([[WKWebView alloc] initWithFrame:CGRectMake(0, 0, 800, 600) configuration:configuration]); |
| [createdWebView setUIDelegate:delegate.get()]; |
| return createdWebView.get(); |
| } |
| |
| - (void)_showWebView:(WKWebView *)webView |
| { |
| webViewFromDelegateCallback = webView; |
| done = true; |
| } |
| |
| - (void)webView:(WKWebView *)webView startURLSchemeTask:(id <WKURLSchemeTask>)urlSchemeTask |
| { |
| NSString *data = @"<script>window.open('other.html');</script>"; |
| [urlSchemeTask didReceiveResponse:[[[NSURLResponse alloc] initWithURL:urlSchemeTask.request.URL MIMEType:@"text/html" expectedContentLength:data.length textEncodingName:nil] autorelease]]; |
| [urlSchemeTask didReceiveData:[data dataUsingEncoding:NSUTF8StringEncoding]]; |
| [urlSchemeTask didFinish]; |
| } |
| |
| - (void)webView:(WKWebView *)webView stopURLSchemeTask:(id <WKURLSchemeTask>)urlSchemeTask |
| { |
| } |
| |
| @end |
| |
| TEST(WebKit, ShowWebView) |
| { |
| delegate = adoptNS([[UITestDelegate alloc] init]); |
| auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [configuration setURLSchemeHandler:delegate.get() forURLScheme:@"test"]; |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:CGRectMake(0, 0, 800, 600) configuration:configuration.get()]); |
| [webView setUIDelegate:delegate.get()]; |
| [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"test:///first"]]]; |
| TestWebKitAPI::Util::run(&done); |
| |
| ASSERT_EQ(webViewFromDelegateCallback, createdWebView); |
| } |
| |
| @interface PointerLockDelegate : NSObject <WKUIDelegatePrivate> |
| @end |
| |
| @implementation PointerLockDelegate |
| |
| - (void)_webViewDidRequestPointerLock:(WKWebView *)webView completionHandler:(void (^)(BOOL))completionHandler |
| { |
| completionHandler(YES); |
| done = true; |
| } |
| |
| @end |
| |
| TEST(WebKit, PointerLock) |
| { |
| auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 800, 600)]); |
| auto delegate = adoptNS([[PointerLockDelegate alloc] init]); |
| [webView setUIDelegate:delegate.get()]; |
| [webView synchronouslyLoadHTMLString: |
| @"<canvas width='800' height='600'></canvas><script>" |
| @"var canvas = document.querySelector('canvas');" |
| @"canvas.onclick = ()=>{canvas.requestPointerLock()};" |
| @"</script>" |
| ]; |
| [webView sendClicksAtPoint:NSMakePoint(200, 200) numberOfClicks:1]; |
| TestWebKitAPI::Util::run(&done); |
| } |
| |
| static bool resizableSet; |
| |
| @interface ModalDelegate : NSObject <WKUIDelegatePrivate> |
| @end |
| |
| @implementation ModalDelegate |
| |
| - (void)_webViewRunModal:(WKWebView *)webView |
| { |
| EXPECT_TRUE(resizableSet); |
| EXPECT_EQ(webView, createdWebView.get()); |
| done = true; |
| } |
| |
| - (void)_webView:(WKWebView *)webView setResizable:(BOOL)isResizable |
| { |
| EXPECT_FALSE(isResizable); |
| resizableSet = true; |
| } |
| |
| - (nullable WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures |
| { |
| createdWebView = [[[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration] autorelease]; |
| [createdWebView setUIDelegate:self]; |
| return createdWebView.get(); |
| } |
| |
| @end |
| |
| TEST(WebKit, RunModal) |
| { |
| auto delegate = adoptNS([[ModalDelegate alloc] init]); |
| auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 800, 600)]); |
| [webView setUIDelegate:delegate.get()]; |
| NSURL *url = [[NSBundle mainBundle] URLForResource:@"simple" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]; |
| NSString *html = [NSString stringWithFormat:@"%@%@%@", @"<script> function openModal() { window.showModalDialog('", url, @"'); } </script> <input type='button' value='Click to open modal' onclick='openModal();'>"]; |
| [webView synchronouslyLoadHTMLString:html]; |
| [webView sendClicksAtPoint:NSMakePoint(20, 600 - 20) numberOfClicks:1]; |
| TestWebKitAPI::Util::run(&done); |
| } |
| |
| static bool receivedWindowFrame; |
| |
| @interface WindowFrameDelegate : NSObject <WKUIDelegatePrivate> |
| @end |
| |
| @implementation WindowFrameDelegate |
| |
| - (void)_webView:(WKWebView *)webView setWindowFrame:(CGRect)frame |
| { |
| EXPECT_EQ(frame.origin.x, 160); |
| EXPECT_EQ(frame.origin.y, 230); |
| EXPECT_EQ(frame.size.width, 350); |
| EXPECT_EQ(frame.size.height, 450); |
| receivedWindowFrame = true; |
| } |
| |
| - (void)_webView:(WKWebView *)webView getWindowFrameWithCompletionHandler:(void (^)(CGRect))completionHandler |
| { |
| completionHandler(CGRectMake(150, 250, 350, 450)); |
| } |
| |
| - (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler |
| { |
| EXPECT_STREQ("350", message.UTF8String); |
| completionHandler(); |
| done = true; |
| } |
| |
| @end |
| |
| TEST(WebKit, WindowFrame) |
| { |
| auto delegate = adoptNS([[WindowFrameDelegate alloc] init]); |
| auto webView = adoptNS([[WKWebView alloc] init]); |
| [webView setUIDelegate:delegate.get()]; |
| [webView loadHTMLString:@"<script>moveBy(10,20);alert(outerWidth);</script>" baseURL:nil]; |
| TestWebKitAPI::Util::run(&receivedWindowFrame); |
| TestWebKitAPI::Util::run(&done); |
| } |
| |
| static bool headerHeightCalled; |
| static bool footerHeightCalled; |
| static bool drawHeaderCalled; |
| static bool drawFooterCalled; |
| |
| @interface PrintDelegate : NSObject <WKUIDelegatePrivate> |
| @end |
| |
| @implementation PrintDelegate |
| |
| - (void)_webView:(WKWebView *)webView printFrame:(_WKFrameHandle *)frame |
| { |
| done = true; |
| } |
| |
| - (CGFloat)_webViewHeaderHeight:(WKWebView *)webView |
| { |
| headerHeightCalled = true; |
| return 3.14159; |
| } |
| |
| - (CGFloat)_webViewFooterHeight:(WKWebView *)webView |
| { |
| footerHeightCalled = true; |
| return 2.71828; |
| } |
| |
| - (void)_webView:(WKWebView *)webView drawHeaderInRect:(CGRect)rect forPageWithTitle:(NSString *)title URL:(NSURL *)url |
| { |
| EXPECT_EQ(rect.origin.x, 72); |
| EXPECT_TRUE(fabs(rect.origin.y - 698.858398) < .00001); |
| EXPECT_TRUE(fabs(rect.size.height - 3.141590) < .00001); |
| EXPECT_EQ(rect.size.width, 468.000000); |
| EXPECT_STREQ(title.UTF8String, "test_title"); |
| EXPECT_STREQ(url.absoluteString.UTF8String, "http://example.com/"); |
| drawHeaderCalled = true; |
| } |
| |
| - (void)_webView:(WKWebView *)webView drawFooterInRect:(CGRect)rect forPageWithTitle:(NSString *)title URL:(NSURL *)url |
| { |
| EXPECT_EQ(rect.origin.x, 72); |
| EXPECT_EQ(rect.origin.y, 90); |
| EXPECT_TRUE(fabs(rect.size.height - 2.718280) < .00001); |
| EXPECT_EQ(rect.size.width, 468.000000); |
| EXPECT_STREQ(url.absoluteString.UTF8String, "http://example.com/"); |
| drawFooterCalled = true; |
| } |
| |
| @end |
| |
| TEST(WebKit, PrintFrame) |
| { |
| auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600)]); |
| auto delegate = adoptNS([[PrintDelegate alloc] init]); |
| [webView setUIDelegate:delegate.get()]; |
| [webView loadHTMLString:@"<head><title>test_title</title></head><body onload='print()'>hello world!</body>" baseURL:[NSURL URLWithString:@"http://example.com/"]]; |
| TestWebKitAPI::Util::run(&done); |
| |
| NSPrintOperation *operation = [webView _printOperationWithPrintInfo:[NSPrintInfo sharedPrintInfo]]; |
| EXPECT_TRUE(operation.canSpawnSeparateThread); |
| EXPECT_STREQ(operation.jobTitle.UTF8String, "test_title"); |
| |
| [operation runOperationModalForWindow:[webView hostWindow] delegate:nil didRunSelector:nil contextInfo:nil]; |
| TestWebKitAPI::Util::run(&headerHeightCalled); |
| TestWebKitAPI::Util::run(&footerHeightCalled); |
| TestWebKitAPI::Util::run(&drawHeaderCalled); |
| TestWebKitAPI::Util::run(&drawFooterCalled); |
| } |
| |
| @interface NotificationDelegate : NSObject <WKUIDelegatePrivate> { |
| bool _allowNotifications; |
| } |
| - (id)initWithAllowNotifications:(bool)allowNotifications; |
| @end |
| |
| @implementation NotificationDelegate |
| |
| - (id)initWithAllowNotifications:(bool)allowNotifications |
| { |
| if (!(self = [super init])) |
| return nil; |
| _allowNotifications = allowNotifications; |
| return self; |
| } |
| |
| - (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler |
| { |
| if (_allowNotifications) |
| EXPECT_STREQ(message.UTF8String, "permission granted"); |
| else |
| EXPECT_STREQ(message.UTF8String, "permission denied"); |
| completionHandler(); |
| done = true; |
| } |
| |
| - (void)_webView:(WKWebView *)webView requestNotificationPermissionForSecurityOrigin:(WKSecurityOrigin *)securityOrigin decisionHandler:(void (^)(BOOL))decisionHandler |
| { |
| if (_allowNotifications) |
| EXPECT_STREQ(securityOrigin.host.UTF8String, "example.org"); |
| else |
| EXPECT_STREQ(securityOrigin.host.UTF8String, "example.com"); |
| decisionHandler(_allowNotifications); |
| } |
| |
| @end |
| |
| TEST(WebKit, NotificationPermission) |
| { |
| NSString *html = @"<script>Notification.requestPermission(function(p){alert('permission '+p)})</script>"; |
| auto webView = adoptNS([[WKWebView alloc] init]); |
| [webView setUIDelegate:[[[NotificationDelegate alloc] initWithAllowNotifications:YES] autorelease]]; |
| [webView loadHTMLString:html baseURL:[NSURL URLWithString:@"http://example.org"]]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| [webView setUIDelegate:[[[NotificationDelegate alloc] initWithAllowNotifications:NO] autorelease]]; |
| [webView loadHTMLString:html baseURL:[NSURL URLWithString:@"http://example.com"]]; |
| TestWebKitAPI::Util::run(&done); |
| } |
| |
| @interface PlugInDelegate : NSObject <WKUIDelegatePrivate> |
| @end |
| |
| @implementation PlugInDelegate |
| |
| - (void)_webView:(WKWebView *)webView unavailablePlugInButtonClickedWithReason:(_WKPlugInUnavailabilityReason)reason plugInInfo:(NSDictionary *)plugInInfo |
| { |
| ASSERT_EQ(_WKPlugInUnavailabilityReasonPluginMissing, reason); |
| ASSERT_TRUE([@"application/x-shockwave-flash" isEqualToString:[plugInInfo objectForKey:@"PluginInformationMIMEType"]]); |
| done = true; |
| } |
| |
| @end |
| |
| TEST(WebKit, UnavailablePlugIn) |
| { |
| auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [[configuration preferences] setPlugInsEnabled:YES]; |
| auto delegate = adoptNS([[PlugInDelegate alloc] init]); |
| auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 800, 600) configuration:configuration.get()]); |
| [webView setUIDelegate:delegate.get()]; |
| [webView synchronouslyLoadHTMLString:@"<object type='application/x-shockwave-flash'/>"]; |
| [webView sendClicksAtPoint:NSMakePoint(210, 600 - 80) numberOfClicks:1]; |
| TestWebKitAPI::Util::run(&done); |
| } |
| |
| bool firstToolbarDone; |
| |
| @interface ToolbarDelegate : NSObject <WKUIDelegatePrivate> |
| @end |
| |
| @implementation ToolbarDelegate |
| |
| - (void)_webView:(WKWebView *)webView getToolbarsAreVisibleWithCompletionHandler:(void(^)(BOOL))completionHandler |
| { |
| completionHandler(firstToolbarDone); |
| } |
| |
| - (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler |
| { |
| if (firstToolbarDone) { |
| EXPECT_STREQ(message.UTF8String, "visible:true"); |
| done = true; |
| } else { |
| EXPECT_STREQ(message.UTF8String, "visible:false"); |
| firstToolbarDone = true; |
| } |
| completionHandler(); |
| } |
| |
| @end |
| |
| TEST(WebKit, ToolbarVisible) |
| { |
| auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 800, 600) configuration:[[[WKWebViewConfiguration alloc] init] autorelease]]); |
| auto delegate = adoptNS([[ToolbarDelegate alloc] init]); |
| [webView setUIDelegate:delegate.get()]; |
| [webView synchronouslyLoadHTMLString:@"<script>alert('visible:' + window.toolbar.visible);alert('visible:' + window.toolbar.visible)</script>"]; |
| TestWebKitAPI::Util::run(&done); |
| } |
| |
| @interface MouseMoveOverElementDelegate : NSObject <WKUIDelegatePrivate> |
| @end |
| |
| @implementation MouseMoveOverElementDelegate |
| |
| - (void)_webView:(WKWebView *)webview mouseDidMoveOverElement:(_WKHitTestResult *)hitTestResult withFlags:(NSEventModifierFlags)flags userInfo:(id <NSSecureCoding>)userInfo |
| { |
| EXPECT_STREQ(hitTestResult.absoluteLinkURL.absoluteString.UTF8String, "http://example.com/path"); |
| EXPECT_STREQ(hitTestResult.linkLabel.UTF8String, "link label"); |
| EXPECT_STREQ(hitTestResult.linkTitle.UTF8String, "link title"); |
| EXPECT_EQ(flags, NSEventModifierFlagShift); |
| EXPECT_STREQ(NSStringFromClass([(NSObject *)userInfo class]).UTF8String, "_WKFrameHandle"); |
| done = true; |
| } |
| |
| @end |
| |
| TEST(WebKit, MouseMoveOverElement) |
| { |
| WKWebViewConfiguration *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"FrameHandleSerialization"]; |
| auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 800, 600) configuration:configuration]); |
| [webView setUIDelegate:[[[MouseMoveOverElementDelegate alloc] init] autorelease]]; |
| [webView synchronouslyLoadHTMLString:@"<a href='http://example.com/path' title='link title'>link label</a>"]; |
| [webView mouseMoveToPoint:NSMakePoint(20, 600 - 20) withFlags:NSEventModifierFlagShift]; |
| TestWebKitAPI::Util::run(&done); |
| } |
| |
| static bool readyForClick; |
| |
| @interface AutoFillDelegate : NSObject <WKUIDelegatePrivate> |
| @end |
| |
| @implementation AutoFillDelegate |
| |
| - (void)_webView:(WKWebView *)webView didClickAutoFillButtonWithUserInfo:(id <NSSecureCoding>)userInfo |
| { |
| done = true; |
| ASSERT_TRUE([(id<NSObject>)userInfo isKindOfClass:[NSString class]]); |
| ASSERT_STREQ([(NSString*)userInfo UTF8String], "user data string"); |
| } |
| |
| - (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler |
| { |
| completionHandler(); |
| ASSERT_STREQ(message.UTF8String, "ready for click!"); |
| readyForClick = true; |
| } |
| |
| @end |
| |
| TEST(WebKit, ClickAutoFillButton) |
| { |
| WKWebViewConfiguration *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"ClickAutoFillButton"]; |
| |
| auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 800, 600) configuration:configuration]); |
| auto delegate = adoptNS([[AutoFillDelegate alloc] init]); |
| [webView setUIDelegate:delegate.get()]; |
| [webView evaluateJavaScript:@"" completionHandler: nil]; // Ensure the WebProcess and injected bundle are running. |
| TestWebKitAPI::Util::run(&readyForClick); |
| NSPoint buttonLocation = NSMakePoint(130, 575); |
| [webView mouseDownAtPoint:buttonLocation simulatePressure:NO]; |
| [webView mouseUpAtPoint:buttonLocation]; |
| TestWebKitAPI::Util::run(&done); |
| } |
| |
| static bool readytoResign; |
| |
| @interface DidResignInputElementStrongPasswordAppearanceDelegate : NSObject <WKUIDelegatePrivate> |
| @end |
| |
| @implementation DidResignInputElementStrongPasswordAppearanceDelegate |
| |
| - (void)_webView:(WKWebView *)webView didResignInputElementStrongPasswordAppearanceWithUserInfo:(id <NSSecureCoding>)userInfo |
| { |
| done = true; |
| ASSERT_TRUE([(id<NSObject>)userInfo isKindOfClass:[NSString class]]); |
| ASSERT_STREQ([(NSString*)userInfo UTF8String], "user data string"); |
| } |
| |
| - (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler |
| { |
| completionHandler(); |
| ASSERT_STREQ(message.UTF8String, "ready to resign!"); |
| readytoResign = true; |
| } |
| |
| @end |
| |
| static void testDidResignInputElementStrongPasswordAppearanceAfterEvaluatingJavaScript(NSString *script) |
| { |
| done = false; |
| readytoResign = false; |
| WKWebViewConfiguration *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"DidResignInputElementStrongPasswordAppearance"]; |
| |
| auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 800, 600) configuration:configuration]); |
| auto delegate = adoptNS([[DidResignInputElementStrongPasswordAppearanceDelegate alloc] init]); |
| [webView setUIDelegate:delegate.get()]; |
| [webView evaluateJavaScript:@"" completionHandler:nil]; // Make sure WebProcess and injected bundle are running. |
| TestWebKitAPI::Util::run(&readytoResign); |
| [webView evaluateJavaScript:script completionHandler:nil]; |
| TestWebKitAPI::Util::run(&done); |
| } |
| |
| TEST(WebKit, DidResignInputElementStrongPasswordAppearanceWhenTypeDidChange) |
| { |
| testDidResignInputElementStrongPasswordAppearanceAfterEvaluatingJavaScript(@"document.querySelector('input').type = 'text'"); |
| } |
| |
| TEST(WebKit, DidResignInputElementStrongPasswordAppearanceWhenValueDidChange) |
| { |
| testDidResignInputElementStrongPasswordAppearanceAfterEvaluatingJavaScript(@"document.querySelector('input').value = ''"); |
| } |
| |
| TEST(WebKit, DidResignInputElementStrongPasswordAppearanceWhenFormIsReset) |
| { |
| testDidResignInputElementStrongPasswordAppearanceAfterEvaluatingJavaScript(@"document.forms[0].reset()"); |
| } |
| |
| @interface AutoFillAvailableDelegate : NSObject <WKUIDelegatePrivate> |
| @end |
| |
| @implementation AutoFillAvailableDelegate |
| |
| - (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)())completionHandler |
| { |
| completionHandler(); |
| done = true; |
| ASSERT_STREQ(message.UTF8String, "autofill available"); |
| } |
| |
| @end |
| |
| TEST(WebKit, AutoFillAvailable) |
| { |
| WKWebViewConfiguration *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"AutoFillAvailable"]; |
| |
| auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 800, 600) configuration:configuration]); |
| auto delegate = adoptNS([[AutoFillAvailableDelegate alloc] init]); |
| [webView setUIDelegate:delegate.get()]; |
| [webView evaluateJavaScript:@"" completionHandler: nil]; // Ensure the WebProcess and injected bundle are running. |
| TestWebKitAPI::Util::run(&done); |
| } |
| |
| @interface InjectedBundleNodeHandleIsTextFieldDelegate : NSObject <WKUIDelegatePrivate> |
| @end |
| |
| @implementation InjectedBundleNodeHandleIsTextFieldDelegate |
| |
| - (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)())completionHandler |
| { |
| completionHandler(); |
| done = true; |
| ASSERT_STREQ(message.UTF8String, "isTextField success"); |
| } |
| |
| @end |
| |
| TEST(WebKit, InjectedBundleNodeHandleIsTextField) |
| { |
| WKWebViewConfiguration *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"InjectedBundleNodeHandleIsTextField"]; |
| |
| auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 800, 600) configuration:configuration]); |
| auto delegate = adoptNS([[InjectedBundleNodeHandleIsTextFieldDelegate alloc] init]); |
| [webView setUIDelegate:delegate.get()]; |
| [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"about:blank"]]]; |
| TestWebKitAPI::Util::run(&done); |
| } |
| |
| @interface PinnedStateObserver : NSObject |
| @end |
| |
| @implementation PinnedStateObserver |
| |
| - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *, id> *)change context:(void *)context |
| { |
| EXPECT_TRUE([keyPath isEqualToString:NSStringFromSelector(@selector(_pinnedState))]); |
| EXPECT_TRUE([[object class] isEqual:[TestWKWebView class]]); |
| EXPECT_EQ([[change objectForKey:NSKeyValueChangeOldKey] unsignedIntegerValue], _WKRectEdgeAll); |
| EXPECT_EQ([[change objectForKey:NSKeyValueChangeNewKey] unsignedIntegerValue], _WKRectEdgeLeft | _WKRectEdgeRight); |
| EXPECT_TRUE(context == nullptr); |
| done = true; |
| } |
| |
| @end |
| |
| TEST(WebKit, PinnedState) |
| { |
| auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 800, 600)]); |
| auto observer = adoptNS([[PinnedStateObserver alloc] init]); |
| [webView addObserver:observer.get() forKeyPath:@"_pinnedState" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil]; |
| [webView loadHTMLString:@"<body onload='scroll(100, 100)' style='height:10000vh;'/>" baseURL:[NSURL URLWithString:@"http://example.com/"]]; |
| TestWebKitAPI::Util::run(&done); |
| } |
| |
| @interface DidScrollDelegate : NSObject <WKUIDelegatePrivate> |
| @end |
| |
| @implementation DidScrollDelegate |
| |
| - (void)_webViewDidScroll:(WKWebView *)webView |
| { |
| done = true; |
| } |
| |
| @end |
| |
| TEST(WebKit, DidScroll) |
| { |
| auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 800, 600)]); |
| auto delegate = adoptNS([[DidScrollDelegate alloc] init]); |
| [webView setUIDelegate:delegate.get()]; |
| [webView loadHTMLString:@"<body onload='scroll(100, 100)' style='height:10000vh;'/>" baseURL:[NSURL URLWithString:@"http://example.com/"]]; |
| TestWebKitAPI::Util::run(&done); |
| } |
| |
| static NSEvent *tabEvent(NSWindow *window, NSEventType type, NSEventModifierFlags flags) |
| { |
| return [NSEvent keyEventWithType:type location:NSMakePoint(5, 5) modifierFlags:flags timestamp:GetCurrentEventTime() windowNumber:[window windowNumber] context:[NSGraphicsContext currentContext] characters:@"\t" charactersIgnoringModifiers:@"\t" isARepeat:NO keyCode:0]; |
| } |
| |
| static void synthesizeTab(NSWindow *window, NSView *view, bool withShiftDown) |
| { |
| [view keyDown:tabEvent(window, NSEventTypeKeyDown, withShiftDown ? NSEventModifierFlagShift : 0)]; |
| [view keyUp:tabEvent(window, NSEventTypeKeyUp, withShiftDown ? NSEventModifierFlagShift : 0)]; |
| } |
| |
| static _WKFocusDirection takenDirection; |
| |
| @interface FocusDelegate : NSObject <WKUIDelegatePrivate> |
| @end |
| |
| @implementation FocusDelegate |
| |
| - (void)_webView:(WKWebView *)webView takeFocus:(_WKFocusDirection)direction |
| { |
| takenDirection = direction; |
| done = true; |
| } |
| |
| - (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler |
| { |
| completionHandler(); |
| synthesizeTab([webView window], webView, true); |
| } |
| |
| @end |
| |
| TEST(WebKit, Focus) |
| { |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:CGRectMake(0, 0, 800, 600)]); |
| auto delegate = adoptNS([[FocusDelegate alloc] init]); |
| [webView setUIDelegate:delegate.get()]; |
| NSString *html = @"<script>function loaded() { document.getElementById('in').focus(); alert('ready'); }</script>" |
| "<body onload='loaded()'><input type='text' id='in'></body>"; |
| [webView loadHTMLString:html baseURL:[NSURL URLWithString:@"http://example.com/"]]; |
| TestWebKitAPI::Util::run(&done); |
| ASSERT_EQ(takenDirection, _WKFocusDirectionBackward); |
| } |
| |
| #define MOUSE_EVENT_CAUSES_DOWNLOAD 0 |
| // FIXME: At least on El Capitan, sending a mouse event does not cause the PDFPlugin to think the download button has been clicked. |
| // This test works on High Sierra, but it should be investigated on older platforms. |
| #if MOUSE_EVENT_CAUSES_DOWNLOAD |
| |
| @interface SaveDataToFileDelegate : NSObject <WKUIDelegatePrivate, WKNavigationDelegate> |
| @end |
| |
| @implementation SaveDataToFileDelegate |
| |
| - (void)_webView:(WKWebView *)webView saveDataToFile:(NSData *)data suggestedFilename:(NSString *)suggestedFilename mimeType:(NSString *)mimeType originatingURL:(NSURL *)url |
| { |
| NSURL *pdfURL = [[NSBundle mainBundle] URLForResource:@"test" withExtension:@"pdf" subdirectory:@"TestWebKitAPI.resources"]; |
| EXPECT_TRUE([data isEqualToData:[NSData dataWithContentsOfURL:pdfURL]]); |
| EXPECT_STREQ([suggestedFilename UTF8String], "test.pdf"); |
| EXPECT_STREQ([mimeType UTF8String], "application/pdf"); |
| EXPECT_STREQ([[url absoluteString] UTF8String], [[pdfURL absoluteString] UTF8String]); |
| done = true; |
| } |
| |
| - (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation |
| { |
| NSPoint location = NSMakePoint(490, 70); // Location of button to download the pdf. |
| [(TestWKWebView *)webView mouseDownAtPoint:location simulatePressure:NO]; |
| [(TestWKWebView *)webView mouseUpAtPoint:location]; |
| } |
| |
| @end |
| |
| TEST(WebKit, SaveDataToFile) |
| { |
| auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 800, 600)]); |
| auto delegate = adoptNS([[SaveDataToFileDelegate alloc] init]); |
| [webView setUIDelegate:delegate.get()]; |
| [webView setNavigationDelegate:delegate.get()]; |
| NSURL *pdfURL = [[NSBundle mainBundle] URLForResource:@"test" withExtension:@"pdf" subdirectory:@"TestWebKitAPI.resources"]; |
| [webView loadRequest:[NSURLRequest requestWithURL:pdfURL]]; |
| TestWebKitAPI::Util::run(&done); |
| } |
| |
| #endif // MOUSE_EVENT_CAUSES_DOWNLOAD |
| |
| #define RELIABLE_DID_NOT_HANDLE_WHEEL_EVENT 0 |
| // FIXME: make wheel event handling more reliable. |
| // https://bugs.webkit.org/show_bug.cgi?id=175967 |
| #if RELIABLE_DID_NOT_HANDLE_WHEEL_EVENT |
| |
| static void synthesizeWheelEvents(NSView *view, int x, int y) |
| { |
| RetainPtr<CGEventRef> cgScrollEvent = adoptCF(CGEventCreateScrollWheelEvent(nullptr, kCGScrollEventUnitLine, 2, y, x)); |
| NSEvent* event = [NSEvent eventWithCGEvent:cgScrollEvent.get()]; |
| [view scrollWheel:event]; |
| |
| // Wheel events get coalesced sometimes. Make more events until one is not handled. |
| dispatch_async(dispatch_get_main_queue(), ^ { |
| synthesizeWheelEvents(view, x, y); |
| }); |
| } |
| |
| @interface WheelDelegate : NSObject <WKUIDelegatePrivate> |
| @end |
| |
| @implementation WheelDelegate |
| |
| - (void)_webView:(WKWebView *)webView didNotHandleWheelEvent:(NSEvent *)event |
| { |
| done = true; |
| } |
| |
| - (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler |
| { |
| completionHandler(); |
| synthesizeWheelEvents(webView, 1, 1); |
| } |
| |
| @end |
| |
| TEST(WebKit, DidNotHandleWheelEvent) |
| { |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:CGRectMake(0, 0, 800, 600)]); |
| auto delegate = adoptNS([[WheelDelegate alloc] init]); |
| [webView setUIDelegate:delegate.get()]; |
| [webView loadHTMLString:@"<body onload='alert(\"ready\")' onwheel='()=>{}' style='overflow:hidden; height:10000vh;'></body>" baseURL:[NSURL URLWithString:@"http://example.com/"]]; |
| TestWebKitAPI::Util::run(&done); |
| } |
| |
| #endif // RELIABLE_DID_NOT_HANDLE_WHEEL_EVENT |
| |
| #endif // PLATFORM(MAC) |