Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 074391f

Browse files
committed
refactor the tests a bit. Remove the double list
1 parent b6853d6 commit 074391f

1 file changed

Lines changed: 95 additions & 94 deletions

File tree

testing/scenario_app/ios/Scenarios/ScenariosTests/AppLifecycleTests.m

Lines changed: 95 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,28 @@
66
#import <XCTest/XCTest.h>
77
#import "ScreenBeforeFlutter.h"
88

9+
@interface XCAppLifecycleTestExpectation : XCTestExpectation
10+
11+
- (instancetype)initForLifecycle:(NSString*)expectedLifecycle forStep:(NSString*)step;
12+
@property(nonatomic, readonly) NSString* expectedLifecycle;
13+
14+
@end
15+
16+
@implementation XCAppLifecycleTestExpectation
17+
18+
@synthesize expectedLifecycle = _expectedLifecycle;
19+
- (instancetype)initForLifecycle:(NSString*)expectedLifecycle forStep:(NSString*)step {
20+
// The step is here because the callbacks into the handler which checks these expectations isn't
21+
// synchronous with the executions in the test, so it's hard to find the cause in the test
22+
// otherwise.
23+
self = [self initWithDescription:[NSString stringWithFormat:@"Expected state %@ during step %@",
24+
expectedLifecycle, step]];
25+
_expectedLifecycle = expectedLifecycle;
26+
return self;
27+
}
28+
29+
@end
30+
931
@interface AppLifecycleTests : XCTestCase
1032
@end
1133

@@ -32,59 +54,56 @@ - (void)testDismissedFlutterViewControllerNotRespondingToApplicationLifecycle {
3254
FlutterEngine* engine = rootVC.engine;
3355

3456
NSMutableArray* lifecycleExpectations = [NSMutableArray arrayWithCapacity:10];
35-
NSMutableArray* lifecycleEvents = [NSMutableArray arrayWithCapacity:10];
3657

37-
[lifecycleExpectations addObject:[[XCTestExpectation alloc]
38-
initWithDescription:@"A loading FlutterViewController goes "
39-
@"through AppLifecycleState.inactive"]];
40-
[lifecycleExpectations
41-
addObject:[[XCTestExpectation alloc]
42-
initWithDescription:
43-
@"A loading FlutterViewController goes through AppLifecycleState.resumed"]];
58+
// Expected sequence from showing the FlutterViewController is inactive and resumed.
59+
[lifecycleExpectations addObjectsFromArray:@[
60+
[[XCAppLifecycleTestExpectation alloc] initForLifecycle:@"AppLifecycleState.inactive"
61+
forStep:@"showing a FlutterViewController"],
62+
[[XCAppLifecycleTestExpectation alloc] initForLifecycle:@"AppLifecycleState.resumed"
63+
forStep:@"showing a FlutterViewController"]
64+
]];
4465

4566
// Holding onto this FlutterViewController is consequential here. Since a released
4667
// FlutterViewController wouldn't keep listening to the application lifecycle events and produce
47-
// false positives.
68+
// false positives for the application lifecycle tests further below.
4869
FlutterViewController* flutterVC = [rootVC showFlutter];
4970
[engine.lifecycleChannel setMessageHandler:^(id message, FlutterReply callback) {
5071
if (lifecycleExpectations.count == 0) {
5172
XCTFail(@"Unexpected lifecycle transition: %@", message);
73+
return;
5274
}
53-
[lifecycleEvents addObject:message];
54-
[[lifecycleExpectations objectAtIndex:0] fulfill];
75+
XCAppLifecycleTestExpectation* nextExpectation = [lifecycleExpectations objectAtIndex:0];
76+
if (![[nextExpectation expectedLifecycle] isEqualToString:message]) {
77+
XCTFail(@"Expected lifecycle %@ but instead received %@", [nextExpectation expectedLifecycle],
78+
message);
79+
return;
80+
}
81+
82+
[nextExpectation fulfill];
5583
[lifecycleExpectations removeObjectAtIndex:0];
5684
}];
5785

58-
[self waitForExpectations:lifecycleExpectations timeout:5];
59-
60-
// Expected sequence from showing the FlutterViewController is inactive and resumed.
61-
NSArray* expectedStates = @[ @"AppLifecycleState.inactive", @"AppLifecycleState.resumed" ];
62-
XCTAssertEqualObjects(lifecycleEvents, expectedStates,
63-
@"AppLifecycleState transitions while presenting not as expected");
86+
// The expectations list isn't dequeued by the message handler yet.
87+
[self waitForExpectations:lifecycleExpectations timeout:5 enforceOrder:YES];
6488

6589
// Now dismiss the FlutterViewController again and expect another inactive and paused.
66-
[lifecycleExpectations
67-
addObject:[[XCTestExpectation alloc]
68-
initWithDescription:@"A dismissed FlutterViewController goes through "
69-
@"AppLifecycleState.inactive"]];
70-
[lifecycleExpectations
71-
addObject:[[XCTestExpectation alloc]
72-
initWithDescription:@"A dismissed FlutterViewController goes through "
73-
@"AppLifecycleState.paused"]];
90+
[lifecycleExpectations addObjectsFromArray:@[
91+
[[XCAppLifecycleTestExpectation alloc] initForLifecycle:@"AppLifecycleState.inactive"
92+
forStep:@"dismissing a FlutterViewController"],
93+
[[XCAppLifecycleTestExpectation alloc]
94+
initForLifecycle:@"AppLifecycleState.paused"
95+
forStep:@"dismissing a FlutterViewController"]
96+
]];
7497
[flutterVC dismissViewControllerAnimated:NO completion:nil];
75-
[self waitForExpectations:lifecycleExpectations timeout:5];
76-
expectedStates = @[
77-
@"AppLifecycleState.inactive", @"AppLifecycleState.resumed", @"AppLifecycleState.inactive",
78-
@"AppLifecycleState.paused"
79-
];
80-
XCTAssertEqualObjects(lifecycleEvents, expectedStates,
81-
@"AppLifecycleState transitions while dismissing not as expected");
98+
[self waitForExpectations:lifecycleExpectations timeout:5 enforceOrder:YES];
8299

83100
// Now put the app in the background (while the engine is still running) and bring it back to
84101
// the foreground. Granted, we're not winning any awards for hyper-realism but at least we're
85102
// checking that we aren't observing the UIApplication notifications and double registering
86103
// for AppLifecycleState events.
87104

105+
// These operations are synchronous so if they trigger any lifecycle events, they should trigger
106+
// failures in the message handler immediately.
88107
[[NSNotificationCenter defaultCenter]
89108
postNotificationName:UIApplicationWillResignActiveNotification
90109
object:nil];
@@ -100,26 +119,19 @@ - (void)testDismissedFlutterViewControllerNotRespondingToApplicationLifecycle {
100119

101120
// There's no timing latch for our semi-fake background-foreground cycle so launch the
102121
// FlutterViewController again to check the complete event list again.
103-
[lifecycleExpectations addObject:[[XCTestExpectation alloc]
104-
initWithDescription:@"A second FlutterViewController goes "
105-
@"through AppLifecycleState.inactive"]];
106-
[lifecycleExpectations
107-
addObject:[[XCTestExpectation alloc]
108-
initWithDescription:
109-
@"A second FlutterViewController goes through AppLifecycleState.resumed"]];
122+
123+
// Expect only lifecycle events from showing the FlutterViewController again, not from any
124+
// backgrounding/foregrounding.
125+
[lifecycleExpectations addObjectsFromArray:@[
126+
[[XCAppLifecycleTestExpectation alloc]
127+
initForLifecycle:@"AppLifecycleState.inactive"
128+
forStep:@"showing a FlutterViewController a second time after backgrounding"],
129+
[[XCAppLifecycleTestExpectation alloc]
130+
initForLifecycle:@"AppLifecycleState.resumed"
131+
forStep:@"showing a FlutterViewController a second time after backgrounding"]
132+
]];
110133
flutterVC = [rootVC showFlutter];
111-
[self waitForExpectations:lifecycleExpectations timeout:5];
112-
expectedStates = @[
113-
@"AppLifecycleState.inactive", @"AppLifecycleState.resumed", @"AppLifecycleState.inactive",
114-
@"AppLifecycleState.paused",
115-
116-
// We only added 2 from re-launching the FlutterViewController
117-
// and none from the background-foreground cycle.
118-
@"AppLifecycleState.inactive", @"AppLifecycleState.resumed"
119-
];
120-
XCTAssertEqualObjects(
121-
lifecycleEvents, expectedStates,
122-
@"AppLifecycleState transitions while presenting a second time not as expected");
134+
[self waitForExpectations:lifecycleExpectations timeout:5 enforceOrder:YES];
123135

124136
// Dismantle.
125137
[engine.lifecycleChannel setMessageHandler:nil];
@@ -146,78 +158,67 @@ - (void)testVisibleFlutterViewControllerRespondsToApplicationLifecycle {
146158
FlutterEngine* engine = rootVC.engine;
147159

148160
NSMutableArray* lifecycleExpectations = [NSMutableArray arrayWithCapacity:10];
149-
NSMutableArray* lifecycleEvents = [NSMutableArray arrayWithCapacity:10];
150161

151-
[lifecycleExpectations addObject:[[XCTestExpectation alloc]
152-
initWithDescription:@"A loading FlutterViewController goes "
153-
@"through AppLifecycleState.inactive"]];
154-
[lifecycleExpectations
155-
addObject:[[XCTestExpectation alloc]
156-
initWithDescription:
157-
@"A loading FlutterViewController goes through AppLifecycleState.resumed"]];
162+
// Expected sequence from showing the FlutterViewController is inactive and resumed.
163+
[lifecycleExpectations addObjectsFromArray:@[
164+
[[XCAppLifecycleTestExpectation alloc] initForLifecycle:@"AppLifecycleState.inactive"
165+
forStep:@"showing a FlutterViewController"],
166+
[[XCAppLifecycleTestExpectation alloc] initForLifecycle:@"AppLifecycleState.resumed"
167+
forStep:@"showing a FlutterViewController"]
168+
]];
158169

159170
FlutterViewController* flutterVC = [rootVC showFlutter];
160171
[engine.lifecycleChannel setMessageHandler:^(id message, FlutterReply callback) {
161172
if (lifecycleExpectations.count == 0) {
162173
XCTFail(@"Unexpected lifecycle transition: %@", message);
174+
return;
175+
}
176+
XCAppLifecycleTestExpectation* nextExpectation = [lifecycleExpectations objectAtIndex:0];
177+
if (![[nextExpectation expectedLifecycle] isEqualToString:message]) {
178+
XCTFail(@"Expected lifecycle %@ but instead received %@", [nextExpectation expectedLifecycle],
179+
message);
180+
return;
163181
}
164-
[lifecycleEvents addObject:message];
165-
[[lifecycleExpectations objectAtIndex:0] fulfill];
182+
183+
[nextExpectation fulfill];
166184
[lifecycleExpectations removeObjectAtIndex:0];
167185
}];
168186

169187
[self waitForExpectations:lifecycleExpectations timeout:5];
170188

171-
// Expected sequence from showing the FlutterViewController is inactive and resumed.
172-
NSArray* expectedStates = @[ @"AppLifecycleState.inactive", @"AppLifecycleState.resumed" ];
173-
XCTAssertEqualObjects(lifecycleEvents, expectedStates,
174-
@"AppLifecycleState transitions while presenting not as expected");
175-
176189
// Now put the FlutterViewController into background.
177-
[lifecycleExpectations
178-
addObject:[[XCTestExpectation alloc]
179-
initWithDescription:@"A backgrounding FlutterViewController goes through "
180-
@"AppLifecycleState.inactive"]];
181-
[lifecycleExpectations
182-
addObject:[[XCTestExpectation alloc]
183-
initWithDescription:@"A backgrounding FlutterViewController goes through "
184-
@"AppLifecycleState.paused"]];
190+
[lifecycleExpectations addObjectsFromArray:@[
191+
[[XCAppLifecycleTestExpectation alloc]
192+
initForLifecycle:@"AppLifecycleState.inactive"
193+
forStep:@"putting FlutterViewController to the background"],
194+
[[XCAppLifecycleTestExpectation alloc]
195+
initForLifecycle:@"AppLifecycleState.paused"
196+
forStep:@"putting FlutterViewController to the background"]
197+
]];
185198
[[NSNotificationCenter defaultCenter]
186199
postNotificationName:UIApplicationWillResignActiveNotification
187200
object:nil];
188201
[[NSNotificationCenter defaultCenter]
189202
postNotificationName:UIApplicationDidEnterBackgroundNotification
190203
object:nil];
191204
[self waitForExpectations:lifecycleExpectations timeout:5];
192-
expectedStates = @[
193-
@"AppLifecycleState.inactive", @"AppLifecycleState.resumed", @"AppLifecycleState.inactive",
194-
@"AppLifecycleState.paused"
195-
];
196-
XCTAssertEqualObjects(lifecycleEvents, expectedStates,
197-
@"AppLifecycleState transitions while backgrounding not as expected");
198205

199206
// Now restore to foreground
200-
[lifecycleExpectations
201-
addObject:[[XCTestExpectation alloc]
202-
initWithDescription:@"A foregrounding FlutterViewController goes through "
203-
@"AppLifecycleState.inactive"]];
204-
[lifecycleExpectations
205-
addObject:[[XCTestExpectation alloc]
206-
initWithDescription:@"A foregrounding FlutterViewController goes through "
207-
@"AppLifecycleState.paused"]];
207+
[lifecycleExpectations addObjectsFromArray:@[
208+
[[XCAppLifecycleTestExpectation alloc]
209+
initForLifecycle:@"AppLifecycleState.inactive"
210+
forStep:@"putting FlutterViewController back to foreground"],
211+
[[XCAppLifecycleTestExpectation alloc]
212+
initForLifecycle:@"AppLifecycleState.resumed"
213+
forStep:@"putting FlutterViewController back to foreground"]
214+
]];
208215
[[NSNotificationCenter defaultCenter]
209216
postNotificationName:UIApplicationWillEnterForegroundNotification
210217
object:nil];
211218
[[NSNotificationCenter defaultCenter]
212219
postNotificationName:UIApplicationDidBecomeActiveNotification
213220
object:nil];
214221
[self waitForExpectations:lifecycleExpectations timeout:5];
215-
expectedStates = @[
216-
@"AppLifecycleState.inactive", @"AppLifecycleState.resumed", @"AppLifecycleState.inactive",
217-
@"AppLifecycleState.paused", @"AppLifecycleState.inactive", @"AppLifecycleState.resumed"
218-
];
219-
XCTAssertEqualObjects(lifecycleEvents, expectedStates,
220-
@"AppLifecycleState transitions while foregrounding not as expected");
221222

222223
// Dismantle.
223224
[engine.lifecycleChannel setMessageHandler:nil];

0 commit comments

Comments
 (0)