blob: 33b4e423ce3dd00f27708f300f656c22e5d17cac [file] [log] [blame]
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import <OCMock/OCMock.h>
#import <XCTest/XCTest.h>
#import "flutter/shell/platform/darwin/ios/framework/Headers/FlutterAppDelegate.h"
#import "flutter/shell/platform/darwin/ios/framework/Headers/FlutterEngine.h"
#import "flutter/shell/platform/darwin/ios/framework/Headers/FlutterViewController.h"
#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterAppDelegate_Test.h"
#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterEngine_Test.h"
FLUTTER_ASSERT_ARC
@interface FlutterAppDelegateTest : XCTestCase
@property(strong) FlutterAppDelegate* appDelegate;
@property(strong) id mockMainBundle;
@property(strong) id mockNavigationChannel;
// Retain callback until the tests are done.
// https://github.com/flutter/flutter/issues/74267
@property(strong) id mockEngineFirstFrameCallback;
@end
@implementation FlutterAppDelegateTest
- (void)setUp {
[super setUp];
id mockMainBundle = OCMClassMock([NSBundle class]);
OCMStub([mockMainBundle mainBundle]).andReturn(mockMainBundle);
self.mockMainBundle = mockMainBundle;
FlutterAppDelegate* appDelegate = [[FlutterAppDelegate alloc] init];
self.appDelegate = appDelegate;
FlutterViewController* viewController = OCMClassMock([FlutterViewController class]);
FlutterMethodChannel* navigationChannel = OCMClassMock([FlutterMethodChannel class]);
self.mockNavigationChannel = navigationChannel;
FlutterEngine* engine = OCMClassMock([FlutterEngine class]);
OCMStub([engine navigationChannel]).andReturn(navigationChannel);
OCMStub([viewController engine]).andReturn(engine);
id mockEngineFirstFrameCallback = [OCMArg invokeBlockWithArgs:@NO, nil];
self.mockEngineFirstFrameCallback = mockEngineFirstFrameCallback;
OCMStub([engine waitForFirstFrame:3.0 callback:mockEngineFirstFrameCallback]);
appDelegate.rootFlutterViewControllerGetter = ^{
return viewController;
};
}
- (void)tearDown {
// Explicitly stop mocking the NSBundle class property.
[self.mockMainBundle stopMocking];
[super tearDown];
}
- (void)testLaunchUrl {
OCMStub([self.mockMainBundle objectForInfoDictionaryKey:@"FlutterDeepLinkingEnabled"])
.andReturn(@YES);
BOOL result =
[self.appDelegate application:[UIApplication sharedApplication]
openURL:[NSURL URLWithString:@"http://myApp/custom/route?query=test"]
options:@{}];
XCTAssertTrue(result);
OCMVerify([self.mockNavigationChannel invokeMethod:@"pushRoute"
arguments:@"/custom/route?query=test"]);
}
- (void)testLaunchUrlWithDeepLinkingNotSet {
OCMStub([self.mockMainBundle objectForInfoDictionaryKey:@"FlutterDeepLinkingEnabled"])
.andReturn(nil);
BOOL result =
[self.appDelegate application:[UIApplication sharedApplication]
openURL:[NSURL URLWithString:@"http://myApp/custom/route?query=test"]
options:@{}];
XCTAssertFalse(result);
OCMReject([self.mockNavigationChannel invokeMethod:OCMOCK_ANY arguments:OCMOCK_ANY]);
}
- (void)testLaunchUrlWithDeepLinkingDisabled {
OCMStub([self.mockMainBundle objectForInfoDictionaryKey:@"FlutterDeepLinkingEnabled"])
.andReturn(@NO);
BOOL result =
[self.appDelegate application:[UIApplication sharedApplication]
openURL:[NSURL URLWithString:@"http://myApp/custom/route?query=test"]
options:@{}];
XCTAssertFalse(result);
OCMReject([self.mockNavigationChannel invokeMethod:OCMOCK_ANY arguments:OCMOCK_ANY]);
}
- (void)testLaunchUrlWithQueryParameterAndFragment {
OCMStub([self.mockMainBundle objectForInfoDictionaryKey:@"FlutterDeepLinkingEnabled"])
.andReturn(@YES);
BOOL result = [self.appDelegate
application:[UIApplication sharedApplication]
openURL:[NSURL URLWithString:@"http://myApp/custom/route?query=test#fragment"]
options:@{}];
XCTAssertTrue(result);
OCMVerify([self.mockNavigationChannel invokeMethod:@"pushRoute"
arguments:@"/custom/route?query=test#fragment"]);
}
- (void)testLaunchUrlWithFragmentNoQueryParameter {
OCMStub([self.mockMainBundle objectForInfoDictionaryKey:@"FlutterDeepLinkingEnabled"])
.andReturn(@YES);
BOOL result =
[self.appDelegate application:[UIApplication sharedApplication]
openURL:[NSURL URLWithString:@"http://myApp/custom/route#fragment"]
options:@{}];
XCTAssertTrue(result);
OCMVerify([self.mockNavigationChannel invokeMethod:@"pushRoute"
arguments:@"/custom/route#fragment"]);
}
- (void)testReleasesWindowOnDealloc {
__weak UIWindow* weakWindow;
@autoreleasepool {
id mockWindow = OCMClassMock([UIWindow class]);
FlutterAppDelegate* appDelegate = [[FlutterAppDelegate alloc] init];
appDelegate.window = mockWindow;
weakWindow = mockWindow;
XCTAssertNotNil(weakWindow);
[mockWindow stopMocking];
mockWindow = nil;
appDelegate = nil;
}
// App delegate has released the window.
XCTAssertNil(weakWindow);
}
#pragma mark - Deep linking
- (void)testUniversalLinkPushRoute {
OCMStub([self.mockMainBundle objectForInfoDictionaryKey:@"FlutterDeepLinkingEnabled"])
.andReturn(@YES);
NSUserActivity* userActivity = [[NSUserActivity alloc] initWithActivityType:@"com.example.test"];
userActivity.webpageURL = [NSURL URLWithString:@"http://myApp/custom/route?query=test"];
BOOL result = [self.appDelegate
application:[UIApplication sharedApplication]
continueUserActivity:userActivity
restorationHandler:^(NSArray<id<UIUserActivityRestoring>>* __nullable restorableObjects){
}];
XCTAssertTrue(result);
OCMVerify([self.mockNavigationChannel invokeMethod:@"pushRoute"
arguments:@"/custom/route?query=test"]);
}
@end