Flutter Engine
The Flutter Engine
Instance Methods | List of all members
AppLifecycleTests Class Reference
Inheritance diagram for AppLifecycleTests:

Instance Methods

(void) - setUp [implementation]
 
(NSArray *) - initialPresentLifecycles [implementation]
 
(void) - skip_testDismissedFlutterViewControllerNotRespondingToApplicationLifecycle [implementation]
 
(void) - skip_testFlutterViewControllerDetachingSendsApplicationLifecycle [implementation]
 

Detailed Description

Definition at line 34 of file AppLifecycleTests.m.

Method Documentation

◆ initialPresentLifecycles

- (NSArray *) initialPresentLifecycles
implementation

Definition at line 15 of file AppLifecycleTests.m.

44 {
45 NSMutableArray* expectations =
46 [NSMutableArray arrayWithObject:[[XCAppLifecycleTestExpectation alloc]
47 initForLifecycle:@"AppLifecycleState.inactive"
48 forStep:@"showing a FlutterViewController"]];
49
50 // If the test is the very first test to run in the test target, the UIApplication may
51 // be in inactive state. Haven't found a good way to force it to go to active state.
52 // So just account for it in the initial lifecycle events with an extra resumed since
53 // the FlutterViewController tracks all view controller and application lifecycle events.
54 if ([UIApplication sharedApplication].applicationState != UIApplicationStateActive) {
55 [expectations addObject:[[XCAppLifecycleTestExpectation alloc]
56 initForLifecycle:@"AppLifecycleState.resumed"
57 forStep:@"showing a FlutterViewController"]];
58 }
59 [expectations addObject:[[XCAppLifecycleTestExpectation alloc]
60 initForLifecycle:@"AppLifecycleState.resumed"
61 forStep:@"showing a FlutterViewController"]];
62 return expectations;
63}

◆ setUp

- (void) setUp
implementation

Definition at line 15 of file AppLifecycleTests.m.

39 {
40 [super setUp];
41 self.continueAfterFailure = NO;
42}

◆ skip_testDismissedFlutterViewControllerNotRespondingToApplicationLifecycle

- (void) skip_testDismissedFlutterViewControllerNotRespondingToApplicationLifecycle
implementation

Definition at line 15 of file AppLifecycleTests.m.

65 {
66 XCTestExpectation* engineStartedExpectation = [self expectationWithDescription:@"Engine started"];
67 // Let the engine finish booting (at the end of which the channels are properly set-up) before
68 // moving onto the next step of showing the next view controller.
69 ScreenBeforeFlutter* rootVC = [[ScreenBeforeFlutter alloc] initWithEngineRunCompletion:^void() {
70 [engineStartedExpectation fulfill];
71 }];
72 [self waitForExpectationsWithTimeout:5 handler:nil];
73
74 UIApplication* application = UIApplication.sharedApplication;
75 application.delegate.window.rootViewController = rootVC;
76 FlutterEngine* engine = rootVC.engine;
77
78 NSMutableArray* lifecycleExpectations = [NSMutableArray arrayWithCapacity:10];
79
80 // Expected sequence from showing the FlutterViewController is inactive and resumed.
81 [lifecycleExpectations addObjectsFromArray:[self initialPresentLifecycles]];
82
83 [engine.lifecycleChannel setMessageHandler:^(id message, FlutterReply callback) {
84 if (lifecycleExpectations.count == 0) {
85 XCTFail(@"Unexpected lifecycle transition: %@", message);
86 return;
87 }
88 XCAppLifecycleTestExpectation* nextExpectation = [lifecycleExpectations objectAtIndex:0];
89 if (![[nextExpectation expectedLifecycle] isEqualToString:message]) {
90 XCTFail(@"Expected lifecycle %@ but instead received %@", [nextExpectation expectedLifecycle],
91 message);
92 return;
93 }
94
95 [nextExpectation fulfill];
96 [lifecycleExpectations removeObjectAtIndex:0];
97 }];
98
99 FlutterViewController* flutterVC;
100 @autoreleasepool {
101 // Holding onto this FlutterViewController is consequential here. Since a released
102 // FlutterViewController wouldn't keep listening to the application lifecycle events and produce
103 // false positives for the application lifecycle tests further below.
104 XCTestExpectation* vcShown = [self expectationWithDescription:@"present"];
105 flutterVC = [rootVC showFlutter:^{
106 [vcShown fulfill];
107 }];
108 [self waitForExpectationsWithTimeout:5.0 handler:nil];
109 // The expectations list isn't dequeued by the message handler yet.
110 [self waitForExpectations:lifecycleExpectations timeout:5 enforceOrder:YES];
111
112 // Now dismiss the FlutterViewController again and expect another inactive and paused.
113 [lifecycleExpectations addObjectsFromArray:@[
115 initForLifecycle:@"AppLifecycleState.inactive"
116 forStep:@"dismissing a FlutterViewController"],
118 initForLifecycle:@"AppLifecycleState.paused"
119 forStep:@"dismissing a FlutterViewController"]
120 ]];
121 XCTestExpectation* vcDismissed = [self expectationWithDescription:@"dismiss"];
122 [flutterVC dismissViewControllerAnimated:NO
123 completion:^{
124 [vcDismissed fulfill];
125 }];
126 [self waitForExpectationsWithTimeout:5.0 handler:nil];
127 [self waitForExpectations:lifecycleExpectations timeout:5 enforceOrder:YES];
128
129 // Now put the app in the background (while the engine is still running) and bring it back to
130 // the foreground. Granted, we're not winning any awards for hyper-realism but at least we're
131 // checking that we aren't observing the UIApplication notifications and double registering
132 // for AppLifecycleState events.
133
134 // These operations are synchronous so if they trigger any lifecycle events, they should trigger
135 // failures in the message handler immediately.
136 [[NSNotificationCenter defaultCenter]
137 postNotificationName:UIApplicationWillResignActiveNotification
138 object:nil];
139 [[NSNotificationCenter defaultCenter]
140 postNotificationName:UIApplicationDidEnterBackgroundNotification
141 object:nil];
142 [[NSNotificationCenter defaultCenter]
143 postNotificationName:UIApplicationWillEnterForegroundNotification
144 object:nil];
145 [[NSNotificationCenter defaultCenter]
146 postNotificationName:UIApplicationDidBecomeActiveNotification
147 object:nil];
148
149 flutterVC = nil;
150 [engine setViewController:nil];
151 }
152
153 // There's no timing latch for our semi-fake background-foreground cycle so launch the
154 // FlutterViewController again to check the complete event list again.
155
156 // Expect only lifecycle events from showing the FlutterViewController again, not from any
157 // backgrounding/foregrounding.
158 [lifecycleExpectations addObjectsFromArray:@[
160 initForLifecycle:@"AppLifecycleState.inactive"
161 forStep:@"showing a FlutterViewController a second time after backgrounding"],
163 initForLifecycle:@"AppLifecycleState.resumed"
164 forStep:@"showing a FlutterViewController a second time after backgrounding"]
165 ]];
166
167 @autoreleasepool {
168 XCTestExpectation* vcShown = [self expectationWithDescription:@"present"];
169 flutterVC = [rootVC showFlutter:^{
170 [vcShown fulfill];
171 }];
172 [self waitForExpectationsWithTimeout:5.0 handler:nil];
173 NSLog(@"FlutterViewController instance %@ created", flutterVC);
174 [self waitForExpectations:lifecycleExpectations timeout:5 enforceOrder:YES];
175
176 // The final dismissal cycles through inactive and paused again.
177 [lifecycleExpectations addObjectsFromArray:@[
178 [[XCAppLifecycleTestExpectation alloc] initForLifecycle:@"AppLifecycleState.inactive"
179 forStep:@"popping the FlutterViewController"],
181 initForLifecycle:@"AppLifecycleState.paused"
182 forStep:@"popping the FlutterViewController"]
183 ]];
184 XCTestExpectation* vcDismissed = [self expectationWithDescription:@"dismiss"];
185 [flutterVC dismissViewControllerAnimated:NO
186 completion:^{
187 [vcDismissed fulfill];
188 }];
189 [self waitForExpectationsWithTimeout:5.0 handler:nil];
190 flutterVC = nil;
191 [engine setViewController:nil];
192 }
193
194 // Dismantle.
195 [engine.lifecycleChannel setMessageHandler:nil];
196 [rootVC dismissViewControllerAnimated:NO completion:nil];
197 [engine destroyContext];
198}
FlutterEngine engine
Definition: main.cc:68
void setViewController:(FlutterViewController *viewController)
FlutterViewController * showFlutter:(dispatch_block_t showCompletion)
FlutterEngine * engine

◆ skip_testFlutterViewControllerDetachingSendsApplicationLifecycle

- (void) skip_testFlutterViewControllerDetachingSendsApplicationLifecycle
implementation

Definition at line 15 of file AppLifecycleTests.m.

200 {
201 XCTestExpectation* engineStartedExpectation = [self expectationWithDescription:@"Engine started"];
202
203 // Let the engine finish booting (at the end of which the channels are properly set-up) before
204 // moving onto the next step of showing the next view controller.
205 ScreenBeforeFlutter* rootVC = [[ScreenBeforeFlutter alloc] initWithEngineRunCompletion:^void() {
206 [engineStartedExpectation fulfill];
207 }];
208
209 [self waitForExpectationsWithTimeout:5 handler:nil];
210
211 UIApplication* application = UIApplication.sharedApplication;
212 application.delegate.window.rootViewController = rootVC;
213 FlutterEngine* engine = rootVC.engine;
214
215 NSMutableArray* lifecycleExpectations = [NSMutableArray arrayWithCapacity:10];
216
217 // Expected sequence from showing the FlutterViewController is inactive and resumed.
218 [lifecycleExpectations addObjectsFromArray:[self initialPresentLifecycles]];
219
220 [engine.lifecycleChannel setMessageHandler:^(id message, FlutterReply callback) {
221 if (lifecycleExpectations.count == 0) {
222 XCTFail(@"Unexpected lifecycle transition: %@", message);
223 return;
224 }
225 XCAppLifecycleTestExpectation* nextExpectation = [lifecycleExpectations objectAtIndex:0];
226 if (![[nextExpectation expectedLifecycle] isEqualToString:message]) {
227 XCTFail(@"Expected lifecycle %@ but instead received %@", [nextExpectation expectedLifecycle],
228 message);
229 return;
230 }
231
232 [nextExpectation fulfill];
233 [lifecycleExpectations removeObjectAtIndex:0];
234 }];
235
236 // At the end of Flutter VC, we want to make sure it deallocs and sends detached signal.
237 // Using autoreleasepool will guarantee that.
238 FlutterViewController* flutterVC;
239 @autoreleasepool {
240 XCTestExpectation* vcShown = [self expectationWithDescription:@"present"];
241 flutterVC = [rootVC showFlutter:^{
242 [vcShown fulfill];
243 }];
244 [self waitForExpectationsWithTimeout:5.0 handler:nil];
245 [self waitForExpectations:lifecycleExpectations timeout:5];
246
247 // Starts dealloc flutter VC.
248 [lifecycleExpectations addObjectsFromArray:@[
249 [[XCAppLifecycleTestExpectation alloc] initForLifecycle:@"AppLifecycleState.inactive"
250 forStep:@"detaching a FlutterViewController"],
251 [[XCAppLifecycleTestExpectation alloc] initForLifecycle:@"AppLifecycleState.paused"
252 forStep:@"detaching a FlutterViewController"],
254 initForLifecycle:@"AppLifecycleState.detached"
255 forStep:@"detaching a FlutterViewController"]
256 ]];
257 [flutterVC dismissViewControllerAnimated:NO completion:nil];
258 flutterVC = nil;
259 }
260 [self waitForExpectations:lifecycleExpectations timeout:5];
261
262 // Dismantle.
263 [engine setViewController:nil];
264 [engine.lifecycleChannel setMessageHandler:nil];
265 [rootVC dismissViewControllerAnimated:NO completion:nil];
266 [engine destroyContext];
267}

The documentation for this class was generated from the following file: