/* Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ #import #import #import "CDVWKWebViewEngine.h" #import "CDVWKProcessPoolFactory.h" #import #import @interface CDVWKWebViewEngineTest : XCTestCase @property (nonatomic, strong) CDVWKWebViewEngine* plugin; @property (nonatomic, strong) CDVViewController* viewController; @end @interface CDVWKWebViewEngine () // TODO: expose private interface, if needed - (BOOL)shouldReloadWebView; - (BOOL)shouldReloadWebView:(NSURL*)location title:(NSString*)title; @end @interface CDVViewController () // expose property as readwrite, for test purposes @property (nonatomic, readwrite, strong) NSMutableDictionary* settings; @end @implementation CDVWKWebViewEngineTest - (void)setUp { [super setUp]; // Put setup code here. This method is called before the invocation of each test method in the class. // NOTE: no app settings are set, so it will rely on default WKWebViewConfiguration settings self.plugin = [[CDVWKWebViewEngine alloc] initWithFrame:CGRectMake(0, 0, 100, 100)]; self.viewController = [[CDVViewController alloc] init]; [self.viewController registerPlugin:self.plugin withClassName:NSStringFromClass([self.plugin class])]; XCTAssert([self.plugin conformsToProtocol:@protocol(CDVWebViewEngineProtocol)], @"Plugin does not conform to CDVWebViewEngineProtocol"); } - (void)tearDown { // Put teardown code here. This method is called after the invocation of each test method in the class. [super tearDown]; } - (void) testCanLoadRequest { NSURLRequest* fileUrlRequest = [NSURLRequest requestWithURL:[NSURL fileURLWithPath:@"path/to/file.html"]]; NSURLRequest* httpUrlRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://apache.org"]]; NSURLRequest* miscUrlRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:@"foo://bar"]]; id webViewEngineProtocol = self.plugin; SEL wk_sel = NSSelectorFromString(@"loadFileURL:allowingReadAccessToURL:"); if ([self.plugin.engineWebView respondsToSelector:wk_sel]) { XCTAssertTrue([webViewEngineProtocol canLoadRequest:fileUrlRequest]); } else { XCTAssertFalse([webViewEngineProtocol canLoadRequest:fileUrlRequest]); } XCTAssertTrue([webViewEngineProtocol canLoadRequest:httpUrlRequest]); XCTAssertTrue([webViewEngineProtocol canLoadRequest:miscUrlRequest]); } - (void) testUpdateInfo { // Add -ObjC to Other Linker Flags to test project, to load Categories // Update objc test template generator as well id webViewEngineProtocol = self.plugin; WKWebView* wkWebView = (WKWebView*)self.plugin.engineWebView; // iOS >=10 defaults to NO, < 10 defaults to YES. BOOL mediaPlaybackRequiresUserActionDefault = IsAtLeastiOSVersion(@"10.0")? NO : YES; NSDictionary* preferences = @{ [@"MinimumFontSize" lowercaseString] : @1.1, // default is 0.0 [@"AllowInlineMediaPlayback" lowercaseString] : @YES, // default is NO [@"MediaPlaybackRequiresUserAction" lowercaseString] : @(!mediaPlaybackRequiresUserActionDefault), // default is NO on iOS >= 10, YES for < 10 [@"SuppressesIncrementalRendering" lowercaseString] : @YES, // default is NO [@"MediaPlaybackAllowsAirPlay" lowercaseString] : @NO, // default is YES [@"DisallowOverscroll" lowercaseString] : @YES, // so bounces is to be NO. defaults to NO [@"WKWebViewDecelerationSpeed" lowercaseString] : @"fast" // default is 'normal' }; NSDictionary* info = @{ kCDVWebViewEngineWebViewPreferences : preferences }; [webViewEngineProtocol updateWithInfo:info]; // the only preference we can set, we **can** change this during runtime XCTAssertEqualWithAccuracy(wkWebView.configuration.preferences.minimumFontSize, 1.1, 0.0001); // the WKWebViewConfiguration properties, we **cannot** change outside of initialization if (IsAtLeastiOSVersion(@"10.0")) { XCTAssertFalse(wkWebView.configuration.mediaPlaybackRequiresUserAction); } else { XCTAssertTrue(wkWebView.configuration.mediaPlaybackRequiresUserAction); } XCTAssertFalse(wkWebView.configuration.allowsInlineMediaPlayback); XCTAssertFalse(wkWebView.configuration.suppressesIncrementalRendering); XCTAssertTrue(wkWebView.configuration.mediaPlaybackAllowsAirPlay); // in the test above, DisallowOverscroll is YES, so no bounce if ([wkWebView respondsToSelector:@selector(scrollView)]) { XCTAssertFalse(((UIScrollView*)[wkWebView scrollView]).bounces); } else { for (id subview in wkWebView.subviews) { if ([[subview class] isSubclassOfClass:[UIScrollView class]]) { XCTAssertFalse(((UIScrollView*)subview).bounces = NO); } } } XCTAssertTrue(wkWebView.scrollView.decelerationRate == UIScrollViewDecelerationRateFast); } - (void) testConfigurationFromSettings { // we need to re-set the plugin from the "setup" to take in the app settings we need self.plugin = [[CDVWKWebViewEngine alloc] initWithFrame:CGRectMake(0, 0, 100, 100)]; self.viewController = [[CDVViewController alloc] init]; // generate the app settings // iOS >=10 defaults to NO, < 10 defaults to YES. BOOL mediaPlaybackRequiresUserActionDefault = IsAtLeastiOSVersion(@"10.0")? NO : YES; NSDictionary* settings = @{ [@"MinimumFontSize" lowercaseString] : @1.1, // default is 0.0 [@"AllowInlineMediaPlayback" lowercaseString] : @YES, // default is NO [@"MediaPlaybackRequiresUserAction" lowercaseString] : @(!mediaPlaybackRequiresUserActionDefault), // default is NO on iOS >= 10, YES for < 10 [@"SuppressesIncrementalRendering" lowercaseString] : @YES, // default is NO [@"MediaPlaybackAllowsAirPlay" lowercaseString] : @NO, // default is YES [@"DisallowOverscroll" lowercaseString] : @YES, // so bounces is to be NO. defaults to NO [@"WKWebViewDecelerationSpeed" lowercaseString] : @"fast" // default is 'normal' }; // this can be set because of the Category at the top of the file self.viewController.settings = [settings mutableCopy]; // app settings are read after you register the plugin [self.viewController registerPlugin:self.plugin withClassName:NSStringFromClass([self.plugin class])]; XCTAssert([self.plugin conformsToProtocol:@protocol(CDVWebViewEngineProtocol)], @"Plugin does not conform to CDVWebViewEngineProtocol"); // after registering (thus plugin initialization), we can grab the webview configuration WKWebView* wkWebView = (WKWebView*)self.plugin.engineWebView; // the only preference we can set, we **can** change this during runtime XCTAssertEqualWithAccuracy(wkWebView.configuration.preferences.minimumFontSize, 1.1, 0.0001); // the WKWebViewConfiguration properties, we **cannot** change outside of initialization if (IsAtLeastiOSVersion(@"10.0")) { XCTAssertTrue(wkWebView.configuration.mediaPlaybackRequiresUserAction); } else { XCTAssertFalse(wkWebView.configuration.mediaPlaybackRequiresUserAction); } XCTAssertTrue(wkWebView.configuration.allowsInlineMediaPlayback); XCTAssertTrue(wkWebView.configuration.suppressesIncrementalRendering); // The test case below is in a separate test "testConfigurationWithMediaPlaybackAllowsAirPlay" (Apple bug) // XCTAssertFalse(wkWebView.configuration.mediaPlaybackAllowsAirPlay); // in the test above, DisallowOverscroll is YES, so no bounce if ([wkWebView respondsToSelector:@selector(scrollView)]) { XCTAssertFalse(((UIScrollView*)[wkWebView scrollView]).bounces); } else { for (id subview in wkWebView.subviews) { if ([[subview class] isSubclassOfClass:[UIScrollView class]]) { XCTAssertFalse(((UIScrollView*)subview).bounces = NO); } } } XCTAssertTrue(wkWebView.scrollView.decelerationRate == UIScrollViewDecelerationRateFast); } - (void) testShouldReloadWebView { WKWebView* wkWebView = (WKWebView*)self.plugin.engineWebView; NSURL* about_blank = [NSURL URLWithString:@"about:blank"]; NSURL* real_site = [NSURL URLWithString:@"https://cordova.apache.org"]; NSString* empty_title_document = @""; // about:blank should reload [wkWebView loadRequest:[NSURLRequest requestWithURL:about_blank]]; XCTAssertTrue([self.plugin shouldReloadWebView]); // a network location should *not* reload [wkWebView loadRequest:[NSURLRequest requestWithURL:real_site]]; XCTAssertFalse([self.plugin shouldReloadWebView]); // document with empty title should *not* reload // baseURL:nil results in about:blank, so we use a dummy here [wkWebView loadHTMLString:empty_title_document baseURL:[NSURL URLWithString:@"about:"]]; XCTAssertFalse([self.plugin shouldReloadWebView]); // Anecdotal assertion that when the WKWebView process has died, // the title is nil, should always reload XCTAssertTrue([self.plugin shouldReloadWebView:about_blank title:nil]); XCTAssertTrue([self.plugin shouldReloadWebView:real_site title:nil]); // about:blank should always reload XCTAssertTrue([self.plugin shouldReloadWebView:about_blank title:@"some title"]); // non about:blank with a non-nil title should **not** reload XCTAssertFalse([self.plugin shouldReloadWebView:real_site title:@""]); } - (void) testConfigurationWithMediaPlaybackAllowsAirPlay { WKWebViewConfiguration* configuration = [WKWebViewConfiguration new]; configuration.allowsAirPlayForMediaPlayback = NO; WKWebView* wkWebView = [[WKWebView alloc] initWithFrame:CGRectMake(0, 0, 100, 100) configuration:configuration]; XCTAssertFalse(configuration.allowsAirPlayForMediaPlayback); // Uh-oh, bug in WKWebView below. Tested on iOS 9, iOS 10 beta 3 XCTAssertFalse(wkWebView.configuration.allowsAirPlayForMediaPlayback); } - (void) testWKProcessPoolFactory { WKProcessPool* shared = [[CDVWKProcessPoolFactory sharedFactory] sharedProcessPool]; XCTAssertTrue(shared != nil); } @end