| 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_Internal.h"
12 #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterAppDelegate_Test.h"
13 #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterEngine_Test.h"
14
15 FLUTTER_ASSERT_ARC
16
17 @interface FlutterAppDelegateTest : XCTestCase
18 @property(strong) FlutterAppDelegate* appDelegate;
19 @property(strong) FlutterViewController* viewController;
20 @property(strong) id mockMainBundle;
21 @property(strong) id mockNavigationChannel;
22
23 // Retain callback until the tests are done.
24 // https://github.com/flutter/flutter/issues/74267
25 @property(strong) id mockEngineFirstFrameCallback;
26 @end
27
28 @implementation FlutterAppDelegateTest
29
30 - (void)setUp {
31 [super setUp];
32
33 id mockMainBundle = OCMClassMock([NSBundle class]);
34 OCMStub([mockMainBundle mainBundle]).andReturn(mockMainBundle);
35 self.mockMainBundle = mockMainBundle;
36
37 FlutterAppDelegate* appDelegate = [[FlutterAppDelegate alloc] init];
38 self.appDelegate = appDelegate;
39
40 FlutterViewController* viewController = OCMClassMock([FlutterViewController class]);
41 self.viewController = viewController;
42
43 FlutterMethodChannel* navigationChannel = OCMClassMock([FlutterMethodChannel class]);
44 self.mockNavigationChannel = navigationChannel;
45
46 FlutterEngine* engine = OCMClassMock([FlutterEngine class]);
47 OCMStub([engine navigationChannel]).andReturn(navigationChannel);
48 OCMStub([viewController engine]).andReturn(engine);
49
50 id mockEngineFirstFrameCallback = [OCMArg invokeBlockWithArgs:@NO, nil];
51 self.mockEngineFirstFrameCallback = mockEngineFirstFrameCallback;
52 OCMStub([engine waitForFirstFrame:3.0 callback:mockEngineFirstFrameCallback]);
53 appDelegate.rootFlutterViewControllerGetter = ^{
54 return viewController;
55 };
56 }
57
58 - (void)tearDown {
59 // Explicitly stop mocking the NSBundle class property.
60 [self.mockMainBundle stopMocking];
61 [super tearDown];
62 }
63
64 - (void)testLaunchUrl {
65 OCMStub([self.mockMainBundle objectForInfoDictionaryKey:@"FlutterDeepLinkingEnabled"])
66 .andReturn(@YES);
67
68 OCMStub([self.mockNavigationChannel
69 invokeMethod:@"pushRouteInformation"
70 arguments:@{@"location" : @"http://myApp/custom/route?query=test"}])
71 .andReturn(@YES);
72
73 BOOL result =
74 [self.appDelegate application:[UIApplication sharedApplication]
75 openURL:[NSURL URLWithString:@"http://myApp/custom/route?query=test"]
76 options:@{}];
77
78 XCTAssertTrue(result);
79 OCMVerifyAll(self.mockNavigationChannel);
80 }
81
82 - (void)testLaunchUrlWithDeepLinkingNotSet {
83 OCMStub([self.mockMainBundle objectForInfoDictionaryKey:@"FlutterDeepLinkingEnabled"])
84 .andReturn(nil);
85
86 OCMStub([self.mockNavigationChannel
87 invokeMethod:@"pushRouteInformation"
88 arguments:@{@"location" : @"http://myApp/custom/route?query=test"}])
89 .andReturn(@YES);
90
91 BOOL result =
92 [self.appDelegate application:[UIApplication sharedApplication]
93 openURL:[NSURL URLWithString:@"http://myApp/custom/route?query=test"]
94 options:@{}];
95
96 XCTAssertTrue(result);
97 OCMVerifyAll(self.mockNavigationChannel);
98 }
99
100 - (void)testLaunchUrlWithDeepLinkingDisabled {
101 OCMStub([self.mockMainBundle objectForInfoDictionaryKey:@"FlutterDeepLinkingEnabled"])
102 .andReturn(@NO);
103
104 BOOL result =
105 [self.appDelegate application:[UIApplication sharedApplication]
106 openURL:[NSURL URLWithString:@"http://myApp/custom/route?query=test"]
107 options:@{}];
108 XCTAssertFalse(result);
109 OCMReject([self.mockNavigationChannel invokeMethod:OCMOCK_ANY arguments:OCMOCK_ANY]);
110 }
111
112 - (void)testLaunchUrlWithQueryParameterAndFragment {
113 OCMStub([self.mockMainBundle objectForInfoDictionaryKey:@"FlutterDeepLinkingEnabled"])
114 .andReturn(@YES);
115 OCMStub([self.mockNavigationChannel
116 invokeMethod:@"pushRouteInformation"
117 arguments:@{@"location" : @"http://myApp/custom/route?query=test#fragment"}])
118 .andReturn(@YES);
119 BOOL result = [self.appDelegate
120 application:[UIApplication sharedApplication]
121 openURL:[NSURL URLWithString:@"http://myApp/custom/route?query=test#fragment"]
122 options:@{}];
123 XCTAssertTrue(result);
124 OCMVerifyAll(self.mockNavigationChannel);
125 }
126
127 - (void)testLaunchUrlWithFragmentNoQueryParameter {
128 OCMStub([self.mockMainBundle objectForInfoDictionaryKey:@"FlutterDeepLinkingEnabled"])
129 .andReturn(@YES);
130 OCMStub([self.mockNavigationChannel
131 invokeMethod:@"pushRouteInformation"
132 arguments:@{@"location" : @"http://myApp/custom/route#fragment"}])
133 .andReturn(@YES);
134 BOOL result =
135 [self.appDelegate application:[UIApplication sharedApplication]
136 openURL:[NSURL URLWithString:@"http://myApp/custom/route#fragment"]
137 options:@{}];
138 XCTAssertTrue(result);
139 OCMVerifyAll(self.mockNavigationChannel);
140 }
141
142 - (void)testReleasesWindowOnDealloc {
143 __weak UIWindow* weakWindow;
144 @autoreleasepool {
145 id mockWindow = OCMClassMock([UIWindow class]);
146 FlutterAppDelegate* appDelegate = [[FlutterAppDelegate alloc] init];
147 appDelegate.window = mockWindow;
148 weakWindow = mockWindow;
149 XCTAssertNotNil(weakWindow);
150 [mockWindow stopMocking];
151 mockWindow = nil;
152 appDelegate = nil;
153 }
154 // App delegate has released the window.
155 XCTAssertNil(weakWindow);
156 }
157
158 - (void)testGrabLaunchEngine {
159 // Clear out the mocking of the root view controller.
160 [self.mockMainBundle stopMocking];
161 self.appDelegate.rootFlutterViewControllerGetter = nil;
162 // Working with plugins forces the creation of an engine.
163 XCTAssertFalse([self.appDelegate hasPlugin:@"hello"]);
164 XCTAssertNotNil([self.appDelegate takeLaunchEngine]);
165 XCTAssertNil([self.appDelegate takeLaunchEngine]);
166 }
167
168 - (void)testGrabLaunchEngineWithoutPlugins {
169 XCTAssertNil([self.appDelegate takeLaunchEngine]);
170 }
171
172 #pragma mark - Deep linking
173
174 - (void)testUniversalLinkPushRouteInformation {
175 OCMStub([self.mockMainBundle objectForInfoDictionaryKey:@"FlutterDeepLinkingEnabled"])
176 .andReturn(@YES);
177 OCMStub([self.mockNavigationChannel
178 invokeMethod:@"pushRouteInformation"
179 arguments:@{@"location" : @"http://myApp/custom/route?query=test"}])
180 .andReturn(@YES);
181 NSUserActivity* userActivity = [[NSUserActivity alloc] initWithActivityType:@"com.example.test"];
182 userActivity.webpageURL = [NSURL URLWithString:@"http://myApp/custom/route?query=test"];
183 BOOL result = [self.appDelegate
184 application:[UIApplication sharedApplication]
185 continueUserActivity:userActivity
186 restorationHandler:^(NSArray<id<UIUserActivityRestoring>>* __nullable restorableObjects){
187 }];
188 XCTAssertTrue(result);
189 OCMVerifyAll(self.mockNavigationChannel);
190 }
191
192 - (void)testUseNonDeprecatedOpenURLAPI {
193 OCMStub([self.mockMainBundle objectForInfoDictionaryKey:@"FlutterDeepLinkingEnabled"])
194 .andReturn(@YES);
195 NSUserActivity* userActivity = [[NSUserActivity alloc] initWithActivityType:@"com.example.test"];
196 userActivity.webpageURL = [NSURL URLWithString:@"http://myApp/custom/route?query=nonexist"];
197 OCMStub([self.viewController sendDeepLinkToFramework:[OCMArg any] completionHandler:[OCMArg any]])
198 .andDo(^(NSInvocation* invocation) {
199 void (^handler)(BOOL success);
200 [invocation getArgument:&handler atIndex:3];
201 handler(NO);
202 });
203 id mockApplication = OCMClassMock([UIApplication class]);
204 OCMStub([mockApplication sharedApplication]).andReturn(mockApplication);
205 BOOL result = [self.appDelegate
206 application:[UIApplication sharedApplication]
207 continueUserActivity:userActivity
208 restorationHandler:^(NSArray<id<UIUserActivityRestoring>>* __nullable restorableObjects){
209 }];
210 XCTAssertTrue(result);
211 OCMVerify([mockApplication openURL:[OCMArg any]
212 options:[OCMArg any]
213 completionHandler:[OCMArg any]]);
214 }
215
216 - (void)testSetGetPluginRegistrant {
217 id mockRegistrant = OCMProtocolMock(@protocol(FlutterPluginRegistrant));
218 self.appDelegate.pluginRegistrant = mockRegistrant;
219 XCTAssertEqual(self.appDelegate.pluginRegistrant, mockRegistrant);
220 }
221
222 - (void)testSetGetPluginRegistrantSelf {
223 __weak FlutterAppDelegate* appDelegate = self.appDelegate;
224 @autoreleasepool {
225 appDelegate.pluginRegistrant = (id)appDelegate;
226 self.appDelegate = nil;
227 }
228 // A retain cycle would keep this alive.
229 XCTAssertNil(appDelegate);
230 }
231
232 @end
FlutterAppDelegate.h
FlutterAppDelegate_Internal.h
FlutterAppDelegate_Test.h
FlutterEngine.h
FlutterEngine_Test.h
engine
id engine
Definition: FlutterTextInputPluginTest.mm:136
FlutterViewController.h
FlutterAppDelegate
Definition: FlutterAppDelegate.h:28
FlutterAppDelegate::window
FlutterAppLifeCycleProvider UIWindow * window
Definition: FlutterAppDelegate.h:30
FlutterAppDelegate::pluginRegistrant
NSObject< FlutterPluginRegistrant > * pluginRegistrant
Definition: FlutterAppDelegate.h:44
FlutterAppDelegate::rootFlutterViewControllerGetter
FlutterViewController *(^ rootFlutterViewControllerGetter)(void)
FlutterAppDelegateTest
Definition: FlutterAppDelegateTest.mm:18
FlutterAppDelegateTest::mockEngineFirstFrameCallback
id mockEngineFirstFrameCallback
Definition: FlutterAppDelegateTest.mm:25
FlutterAppDelegateTest::appDelegate
FlutterAppDelegate * appDelegate
Definition: FlutterAppDelegateTest.mm:18
FlutterAppDelegateTest::mockNavigationChannel
id mockNavigationChannel
Definition: FlutterAppDelegateTest.mm:21
FlutterAppDelegateTest::mockMainBundle
id mockMainBundle
Definition: FlutterAppDelegateTest.mm:20
FlutterAppDelegateTest::viewController
FlutterViewController * viewController
Definition: FlutterAppDelegateTest.mm:19
FlutterEngine
Definition: FlutterEngine.h:61
FlutterMethodChannel
Definition: FlutterChannels.h:221
FlutterViewController
Definition: FlutterViewController.h:57
FLUTTER_ASSERT_ARC
Definition: FlutterChannelKeyResponder.mm:13
FlutterPluginRegistrant-p
Definition: FlutterPlugin.h:436