| Flutter iOS Embedder |

FlutterAppDelegateTest.mm
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #import <OCMock/OCMock.h>
6 #import <XCTest/XCTest.h>
7
8 #import "flutter/shell/platform/darwin/ios/framework/Headers/FlutterAppDelegate.h"
9 #import "flutter/shell/platform/darwin/ios/framework/Headers/FlutterEngine.h"
10 #import "flutter/shell/platform/darwin/ios/framework/Headers/FlutterViewController.h"
11 #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterAppDelegate_Test.h"
12 #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterEngine_Test.h"
13
14 FLUTTER_ASSERT_ARC
15
16 @interface FlutterAppDelegateTest : XCTestCase
17 @property(strong) FlutterAppDelegate* appDelegate;
18 @property(strong) FlutterViewController* viewController;
19 @property(strong) id mockMainBundle;
20 @property(strong) id mockNavigationChannel;
21
22 // Retain callback until the tests are done.
23 // https://github.com/flutter/flutter/issues/74267
24 @property(strong) id mockEngineFirstFrameCallback;
25 @end
26
27 @implementation FlutterAppDelegateTest
28
29 - (void)setUp {
30 [super setUp];
31
32 id mockMainBundle = OCMClassMock([NSBundle class]);
33 OCMStub([mockMainBundle mainBundle]).andReturn(mockMainBundle);
34 self.mockMainBundle = mockMainBundle;
35
36 FlutterAppDelegate* appDelegate = [[FlutterAppDelegate alloc] init];
37 self.appDelegate = appDelegate;
38
39 FlutterViewController* viewController = OCMClassMock([FlutterViewController class]);
40 self.viewController = viewController;
41
42 FlutterMethodChannel* navigationChannel = OCMClassMock([FlutterMethodChannel class]);
43 self.mockNavigationChannel = navigationChannel;
44
45 FlutterEngine* engine = OCMClassMock([FlutterEngine class]);
46 OCMStub([engine navigationChannel]).andReturn(navigationChannel);
47 OCMStub([viewController engine]).andReturn(engine);
48
49 id mockEngineFirstFrameCallback = [OCMArg invokeBlockWithArgs:@NO, nil];
50 self.mockEngineFirstFrameCallback = mockEngineFirstFrameCallback;
51 OCMStub([engine waitForFirstFrame:3.0 callback:mockEngineFirstFrameCallback]);
52 appDelegate.rootFlutterViewControllerGetter = ^{
53 return viewController;
54 };
55 }
56
57 - (void)tearDown {
58 // Explicitly stop mocking the NSBundle class property.
59 [self.mockMainBundle stopMocking];
60 [super tearDown];
61 }
62
63 - (void)testLaunchUrl {
64 OCMStub([self.mockMainBundle objectForInfoDictionaryKey:@"FlutterDeepLinkingEnabled"])
65 .andReturn(@YES);
66
67 OCMStub([self.mockNavigationChannel
68 invokeMethod:@"pushRouteInformation"
69 arguments:@{@"location" : @"http://myApp/custom/route?query=test"}])
70 .andReturn(@YES);
71
72 BOOL result =
73 [self.appDelegate application:[UIApplication sharedApplication]
74 openURL:[NSURL URLWithString:@"http://myApp/custom/route?query=test"]
75 options:@{}];
76
77 XCTAssertTrue(result);
78 OCMVerifyAll(self.mockNavigationChannel);
79 }
80
81 - (void)testLaunchUrlWithDeepLinkingNotSet {
82 OCMStub([self.mockMainBundle objectForInfoDictionaryKey:@"FlutterDeepLinkingEnabled"])
83 .andReturn(nil);
84
85 OCMStub([self.mockNavigationChannel
86 invokeMethod:@"pushRouteInformation"
87 arguments:@{@"location" : @"http://myApp/custom/route?query=test"}])
88 .andReturn(@YES);
89
90 BOOL result =
91 [self.appDelegate application:[UIApplication sharedApplication]
92 openURL:[NSURL URLWithString:@"http://myApp/custom/route?query=test"]
93 options:@{}];
94
95 XCTAssertTrue(result);
96 OCMVerifyAll(self.mockNavigationChannel);
97 }
98
99 - (void)testLaunchUrlWithDeepLinkingDisabled {
100 OCMStub([self.mockMainBundle objectForInfoDictionaryKey:@"FlutterDeepLinkingEnabled"])
101 .andReturn(@NO);
102
103 BOOL result =
104 [self.appDelegate application:[UIApplication sharedApplication]
105 openURL:[NSURL URLWithString:@"http://myApp/custom/route?query=test"]
106 options:@{}];
107 XCTAssertFalse(result);
108 OCMReject([self.mockNavigationChannel invokeMethod:OCMOCK_ANY arguments:OCMOCK_ANY]);
109 }
110
111 - (void)testLaunchUrlWithQueryParameterAndFragment {
112 OCMStub([self.mockMainBundle objectForInfoDictionaryKey:@"FlutterDeepLinkingEnabled"])
113 .andReturn(@YES);
114 OCMStub([self.mockNavigationChannel
115 invokeMethod:@"pushRouteInformation"
116 arguments:@{@"location" : @"http://myApp/custom/route?query=test#fragment"}])
117 .andReturn(@YES);
118 BOOL result = [self.appDelegate
119 application:[UIApplication sharedApplication]
120 openURL:[NSURL URLWithString:@"http://myApp/custom/route?query=test#fragment"]
121 options:@{}];
122 XCTAssertTrue(result);
123 OCMVerifyAll(self.mockNavigationChannel);
124 }
125
126 - (void)testLaunchUrlWithFragmentNoQueryParameter {
127 OCMStub([self.mockMainBundle objectForInfoDictionaryKey:@"FlutterDeepLinkingEnabled"])
128 .andReturn(@YES);
129 OCMStub([self.mockNavigationChannel
130 invokeMethod:@"pushRouteInformation"
131 arguments:@{@"location" : @"http://myApp/custom/route#fragment"}])
132 .andReturn(@YES);
133 BOOL result =
134 [self.appDelegate application:[UIApplication sharedApplication]
135 openURL:[NSURL URLWithString:@"http://myApp/custom/route#fragment"]
136 options:@{}];
137 XCTAssertTrue(result);
138 OCMVerifyAll(self.mockNavigationChannel);
139 }
140
141 - (void)testReleasesWindowOnDealloc {
142 __weak UIWindow* weakWindow;
143 @autoreleasepool {
144 id mockWindow = OCMClassMock([UIWindow class]);
145 FlutterAppDelegate* appDelegate = [[FlutterAppDelegate alloc] init];
146 appDelegate.window = mockWindow;
147 weakWindow = mockWindow;
148 XCTAssertNotNil(weakWindow);
149 [mockWindow stopMocking];
150 mockWindow = nil;
151 appDelegate = nil;
152 }
153 // App delegate has released the window.
154 XCTAssertNil(weakWindow);
155 }
156
157 #pragma mark - Deep linking
158
159 - (void)testUniversalLinkPushRouteInformation {
160 OCMStub([self.mockMainBundle objectForInfoDictionaryKey:@"FlutterDeepLinkingEnabled"])
161 .andReturn(@YES);
162 OCMStub([self.mockNavigationChannel
163 invokeMethod:@"pushRouteInformation"
164 arguments:@{@"location" : @"http://myApp/custom/route?query=test"}])
165 .andReturn(@YES);
166 NSUserActivity* userActivity = [[NSUserActivity alloc] initWithActivityType:@"com.example.test"];
167 userActivity.webpageURL = [NSURL URLWithString:@"http://myApp/custom/route?query=test"];
168 BOOL result = [self.appDelegate
169 application:[UIApplication sharedApplication]
170 continueUserActivity:userActivity
171 restorationHandler:^(NSArray<id<UIUserActivityRestoring>>* __nullable restorableObjects){
172 }];
173 XCTAssertTrue(result);
174 OCMVerifyAll(self.mockNavigationChannel);
175 }
176
177 - (void)testUseNonDeprecatedOpenURLAPI {
178 OCMStub([self.mockMainBundle objectForInfoDictionaryKey:@"FlutterDeepLinkingEnabled"])
179 .andReturn(@YES);
180 NSUserActivity* userActivity = [[NSUserActivity alloc] initWithActivityType:@"com.example.test"];
181 userActivity.webpageURL = [NSURL URLWithString:@"http://myApp/custom/route?query=nonexist"];
182 OCMStub([self.viewController sendDeepLinkToFramework:[OCMArg any] completionHandler:[OCMArg any]])
183 .andDo(^(NSInvocation* invocation) {
184 void (^handler)(BOOL success);
185 [invocation getArgument:&handler atIndex:3];
186 handler(NO);
187 });
188 id mockApplication = OCMClassMock([UIApplication class]);
189 OCMStub([mockApplication sharedApplication]).andReturn(mockApplication);
190 BOOL result = [self.appDelegate
191 application:[UIApplication sharedApplication]
192 continueUserActivity:userActivity
193 restorationHandler:^(NSArray<id<UIUserActivityRestoring>>* __nullable restorableObjects){
194 }];
195 XCTAssertTrue(result);
196 OCMVerify([mockApplication openURL:[OCMArg any]
197 options:[OCMArg any]
198 completionHandler:[OCMArg any]]);
199 }
200
201 @end
FlutterAppDelegate.h
FlutterAppDelegate_Test.h
FlutterEngine.h
FlutterEngine_Test.h
engine
id engine
Definition: FlutterTextInputPluginTest.mm:92
FlutterViewController.h
FlutterAppDelegate
Definition: FlutterAppDelegate.h:28
FlutterAppDelegate::window
FlutterAppLifeCycleProvider UIWindow * window
Definition: FlutterAppDelegate.h:30
FlutterAppDelegate::rootFlutterViewControllerGetter
FlutterViewController *(^ rootFlutterViewControllerGetter)(void)
FlutterAppDelegateTest
Definition: FlutterAppDelegateTest.mm:17
FlutterAppDelegateTest::mockEngineFirstFrameCallback
id mockEngineFirstFrameCallback
Definition: FlutterAppDelegateTest.mm:24
FlutterAppDelegateTest::appDelegate
FlutterAppDelegate * appDelegate
Definition: FlutterAppDelegateTest.mm:17
FlutterAppDelegateTest::mockNavigationChannel
id mockNavigationChannel
Definition: FlutterAppDelegateTest.mm:20
FlutterAppDelegateTest::mockMainBundle
id mockMainBundle
Definition: FlutterAppDelegateTest.mm:19
FlutterAppDelegateTest::viewController
FlutterViewController * viewController
Definition: FlutterAppDelegateTest.mm:18
FlutterEngine
Definition: FlutterEngine.h:61
FlutterMethodChannel
Definition: FlutterChannels.h:221
FlutterViewController
Definition: FlutterViewController.h:57
FLUTTER_ASSERT_ARC
Definition: FlutterChannelKeyResponder.mm:13