@@ -37,19 +37,22 @@ void main () {
37
37
late Route <dynamic >? topRoute;
38
38
late Route <dynamic >? previousTopRoute;
39
39
late List <Route <dynamic >> pushedRoutes;
40
+ late Route <dynamic >? lastPoppedRoute;
40
41
41
42
final testNavObserver = TestNavigatorObserver ()
42
43
..onChangedTop = ((current, previous) {
43
44
topRoute = current;
44
45
previousTopRoute = previous;
45
46
})
46
- ..onPushed = ((route, prevRoute) => pushedRoutes.add (route));
47
+ ..onPushed = ((route, prevRoute) => pushedRoutes.add (route))
48
+ ..onPopped = ((route, prevRoute) => lastPoppedRoute = route);
47
49
48
50
Future <void > prepare (WidgetTester tester) async {
49
51
addTearDown (testBinding.reset);
50
52
topRoute = null ;
51
53
previousTopRoute = null ;
52
54
pushedRoutes = [];
55
+ lastPoppedRoute = null ;
53
56
await testBinding.globalStore.add (eg.selfAccount, eg.initialSnapshot ());
54
57
store = await testBinding.globalStore.perAccount (eg.selfAccount.id);
55
58
connection = store.connection as FakeApiConnection ;
@@ -168,6 +171,44 @@ void main () {
168
171
check (find.byType (BottomSheet )).findsOne ();
169
172
}
170
173
174
+ /// Taps the [buttonFinder] button and awaits the bottom sheet's exit.
175
+ ///
176
+ /// Includes a check that the bottom sheet is gone.
177
+ /// Also awaits the transition to a new pushed route, if one is pushed.
178
+ ///
179
+ /// [buttonFinder] will be run only in the bottom sheet's subtree;
180
+ /// it doesn't need its own `find.descendant` logic.
181
+ Future <void > tapButtonAndAwaitTransition (WidgetTester tester, Finder buttonFinder) async {
182
+ final topRouteBeforePress = topRoute;
183
+ check (topRouteBeforePress).isA <ModalBottomSheetRoute <void >>();
184
+ final numPushedRoutesBeforePress = pushedRoutes.length;
185
+ await tester.tap (find.descendant (
186
+ of: find.byType (BottomSheet ),
187
+ matching: buttonFinder));
188
+ await tester.pump (Duration .zero);
189
+
190
+ final newPushedRoute = pushedRoutes.skip (numPushedRoutesBeforePress)
191
+ .singleOrNull;
192
+
193
+ final sheetPopDuration = (topRouteBeforePress as ModalBottomSheetRoute <void >)
194
+ .reverseTransitionDuration;
195
+ // TODO not sure why a 1ms fudge is needed; investigate.
196
+ await tester.pump (sheetPopDuration + Duration (milliseconds: 1 ));
197
+ check (find.byType (BottomSheet )).findsNothing ();
198
+
199
+ if (newPushedRoute != null ) {
200
+ final pushDuration = (newPushedRoute as TransitionRoute ).transitionDuration;
201
+ if (pushDuration > sheetPopDuration) {
202
+ await tester.pump (pushDuration - sheetPopDuration);
203
+ }
204
+ }
205
+
206
+ // We dismissed the sheet by popping, not pushing or replacing.
207
+ check (topRouteBeforePress as Route <dynamic >? )
208
+ ..not ((it) => it.identicalTo (topRoute))
209
+ ..identicalTo (lastPoppedRoute);
210
+ }
211
+
171
212
void checkIconSelected (WidgetTester tester, Finder finder) {
172
213
final widget = tester.widget (find.descendant (
173
214
of: find.byType (BottomSheet ),
@@ -190,9 +231,7 @@ void main () {
190
231
await tapOpenMenuAndAwait (tester);
191
232
checkIconSelected (tester, inboxMenuIconFinder);
192
233
checkIconNotSelected (tester, channelsMenuIconFinder);
193
- await tester.tap (find.text ('Cancel' ));
194
- await tester.pump (Duration .zero); // tap the button
195
- await tester.pump (const Duration (milliseconds: 250 )); // wait for animation
234
+ await tapButtonAndAwaitTransition (tester, find.text ('Cancel' ));
196
235
197
236
await tester.tap (find.byIcon (ZulipIcons .hash_italic));
198
237
await tester.pump ();
@@ -211,12 +250,7 @@ void main () {
211
250
check (find.byType (InboxPageBody )).findsOne ();
212
251
check (find.byType (SubscriptionListPageBody )).findsNothing ();
213
252
214
- await tester.tap (find.descendant (
215
- of: find.byType (BottomSheet ),
216
- matching: channelsMenuIconFinder));
217
- await tester.pump (Duration .zero); // tap the button
218
- await tester.pump (const Duration (milliseconds: 250 )); // wait for animation
219
- check (find.byType (BottomSheet )).findsNothing ();
253
+ await tapButtonAndAwaitTransition (tester, channelsMenuIconFinder);
220
254
check (find.byType (InboxPageBody )).findsNothing ();
221
255
check (find.byType (SubscriptionListPageBody )).findsOne ();
222
256
@@ -228,30 +262,21 @@ void main () {
228
262
testWidgets ('navigation bar menu buttons dismiss the menu' , (tester) async {
229
263
await prepare (tester);
230
264
await tapOpenMenuAndAwait (tester);
231
-
232
- await tester.tap (find.descendant (
233
- of: find.byType (BottomSheet ),
234
- matching: channelsMenuIconFinder));
235
- await tester.pump (Duration .zero); // tap the button
236
- await tester.pump (const Duration (milliseconds: 250 )); // wait for animation
237
- check (find.byType (BottomSheet )).findsNothing ();
265
+ await tapButtonAndAwaitTransition (tester, channelsMenuIconFinder);
238
266
});
239
267
240
268
testWidgets ('cancel button dismisses the menu' , (tester) async {
241
269
await prepare (tester);
242
270
await tapOpenMenuAndAwait (tester);
243
-
244
- await tester.tap (find.text ('Cancel' ));
245
- await tester.pump (Duration .zero); // tap the button
246
- await tester.pump (const Duration (milliseconds: 250 )); // wait for animation
247
- check (find.byType (BottomSheet )).findsNothing ();
271
+ await tapButtonAndAwaitTransition (tester, find.text ('Cancel' ));
248
272
});
249
273
250
274
testWidgets ('menu buttons dismiss the menu' , (tester) async {
251
275
addTearDown (testBinding.reset);
252
276
topRoute = null ;
253
277
previousTopRoute = null ;
254
278
pushedRoutes = [];
279
+ lastPoppedRoute = null ;
255
280
await testBinding.globalStore.add (eg.selfAccount, eg.initialSnapshot ());
256
281
257
282
await tester.pumpWidget (ZulipApp (navigatorObservers: [testNavObserver]));
@@ -263,11 +288,7 @@ void main () {
263
288
264
289
connection.prepare (json: eg.newestGetMessagesResult (
265
290
foundOldest: true , messages: [eg.streamMessage ()]).toJson ());
266
- await tester.tap (find.descendant (
267
- of: find.byType (BottomSheet ),
268
- matching: combinedFeedMenuIconFinder));
269
- await tester.pump (Duration .zero); // tap the button
270
- await tester.pump (const Duration (milliseconds: 250 )); // wait for animation
291
+ await tapButtonAndAwaitTransition (tester, combinedFeedMenuIconFinder);
271
292
272
293
// When we go back to the home page, the menu sheet should be gone.
273
294
(await ZulipApp .navigator).pop ();
@@ -278,21 +299,15 @@ void main () {
278
299
testWidgets ('_MyProfileButton' , (tester) async {
279
300
await prepare (tester);
280
301
await tapOpenMenuAndAwait (tester);
281
-
282
- await tester.tap (find.text ('My profile' ));
283
- await tester.pump (Duration .zero); // tap the button
284
- await tester.pump (const Duration (milliseconds: 250 )); // wait for animation
302
+ await tapButtonAndAwaitTransition (tester, find.text ('My profile' ));
285
303
check (find.byType (ProfilePage )).findsOne ();
286
304
check (find.text (eg.selfUser.fullName)).findsAny ();
287
305
});
288
306
289
307
testWidgets ('_AboutZulipButton' , (tester) async {
290
308
await prepare (tester);
291
309
await tapOpenMenuAndAwait (tester);
292
-
293
- await tester.tap (find.byIcon (ZulipIcons .info));
294
- await tester.pump (Duration .zero); // tap the button
295
- await tester.pump (const Duration (milliseconds: 250 )); // wait for animation
310
+ await tapButtonAndAwaitTransition (tester, find.byIcon (ZulipIcons .info));
296
311
check (find.byType (AboutZulipPage )).findsOne ();
297
312
});
298
313
});
0 commit comments