@@ -16,6 +16,7 @@ import 'package:zulip/widgets/message_list.dart';
16
16
import 'package:zulip/widgets/page.dart' ;
17
17
import 'package:zulip/widgets/store.dart' ;
18
18
19
+ import 'flutter_checks.dart' ;
19
20
import 'model/binding.dart' ;
20
21
import 'example_data.dart' as eg;
21
22
import 'test_navigation.dart' ;
@@ -185,72 +186,67 @@ void main() {
185
186
group ('NotificationDisplayManager open' , () {
186
187
late List <Route <dynamic >> pushedRoutes;
187
188
188
- Future <void > prepare (WidgetTester tester) async {
189
+ Future <void > prepare (WidgetTester tester, { bool early = false } ) async {
189
190
await init ();
190
191
pushedRoutes = [];
191
192
final testNavObserver = TestNavigatorObserver ()
192
193
..onPushed = (route, prevRoute) => pushedRoutes.add (route);
193
194
await tester.pumpWidget (ZulipApp (navigatorObservers: [testNavObserver]));
195
+ if (early) {
196
+ check (pushedRoutes).isEmpty ();
197
+ return ;
198
+ }
194
199
await tester.pump ();
195
200
check (pushedRoutes).length.equals (1 );
196
201
pushedRoutes.clear ();
197
202
}
198
203
199
- void openNotification (Account account, Message message) {
204
+ Future < void > openNotification (Account account, Message message) async {
200
205
final fcmMessage = messageFcmMessage (message, account: account);
201
206
testBinding.notifications.receiveNotificationResponse (NotificationResponse (
202
207
notificationResponseType: NotificationResponseType .selectedNotification,
203
208
payload: jsonEncode (fcmMessage)));
209
+ await null ; // let _navigateForNotification find navigator
204
210
}
205
211
206
- void checkOpenedMessageList ({ required int expectedAccountId, required Narrow expectedNarrow} ) {
207
- check (pushedRoutes).single .isA <WidgetRoute >().page
212
+ void matchesNavigation ( Subject < Route > route, Account account, Message message ) {
213
+ route .isA <WidgetRoute >().page
208
214
.isA <PerAccountStoreWidget >()
209
- ..accountId.equals (expectedAccountId )
215
+ ..accountId.equals (account.id )
210
216
..child.isA <MessageListPage >()
211
- .narrow.equals (expectedNarrow);
212
- pushedRoutes. clear ( );
217
+ .narrow.equals (SendableNarrow . ofMessage (message,
218
+ selfUserId : account.userId) );
213
219
}
214
220
215
- void checkOpenNotification (Account account, Message message) {
216
- openNotification (account, message);
217
- checkOpenedMessageList (
218
- expectedAccountId: account.id,
219
- expectedNarrow: SendableNarrow .ofMessage (message,
220
- selfUserId: account.userId));
221
+ Future <void > checkOpenNotification (Account account, Message message) async {
222
+ await openNotification (account, message);
223
+ matchesNavigation (check (pushedRoutes).single, account, message);
224
+ pushedRoutes.clear ();
221
225
}
222
226
223
227
testWidgets ('stream message' , (tester) async {
224
228
testBinding.globalStore.insertAccount (eg.selfAccount.toCompanion (false ));
225
229
await prepare (tester);
226
- checkOpenNotification (eg.selfAccount, eg.streamMessage ());
230
+ await checkOpenNotification (eg.selfAccount, eg.streamMessage ());
227
231
});
228
232
229
233
testWidgets ('direct message' , (tester) async {
230
234
testBinding.globalStore.insertAccount (eg.selfAccount.toCompanion (false ));
231
235
await prepare (tester);
232
- checkOpenNotification (eg.selfAccount,
236
+ await checkOpenNotification (eg.selfAccount,
233
237
eg.dmMessage (from: eg.otherUser, to: [eg.selfUser]));
234
238
});
235
239
236
- testWidgets ('no widgets in tree' , (tester) async {
237
- await init ();
238
- final message = eg.dmMessage (from: eg.otherUser, to: [eg.selfUser]);
239
-
240
- openNotification (eg.selfAccount, message);
241
- // nothing happened, but nothing blew up
242
- });
243
-
244
240
testWidgets ('no accounts' , (tester) async {
245
241
await prepare (tester);
246
- openNotification (eg.selfAccount, eg.streamMessage ());
242
+ await openNotification (eg.selfAccount, eg.streamMessage ());
247
243
check (pushedRoutes).isEmpty ();
248
244
});
249
245
250
246
testWidgets ('mismatching account' , (tester) async {
251
247
testBinding.globalStore.insertAccount (eg.selfAccount.toCompanion (false ));
252
248
await prepare (tester);
253
- openNotification (eg.otherAccount, eg.streamMessage ());
249
+ await openNotification (eg.otherAccount, eg.streamMessage ());
254
250
check (pushedRoutes).isEmpty ();
255
251
});
256
252
@@ -268,10 +264,52 @@ void main() {
268
264
}
269
265
await prepare (tester);
270
266
271
- checkOpenNotification (accounts[0 ], eg.streamMessage ());
272
- checkOpenNotification (accounts[1 ], eg.streamMessage ());
273
- checkOpenNotification (accounts[2 ], eg.streamMessage ());
274
- checkOpenNotification (accounts[3 ], eg.streamMessage ());
267
+ await checkOpenNotification (accounts[0 ], eg.streamMessage ());
268
+ await checkOpenNotification (accounts[1 ], eg.streamMessage ());
269
+ await checkOpenNotification (accounts[2 ], eg.streamMessage ());
270
+ await checkOpenNotification (accounts[3 ], eg.streamMessage ());
271
+ });
272
+
273
+ testWidgets ('wait for app to become ready' , (tester) async {
274
+ testBinding.globalStore.insertAccount (eg.selfAccount.toCompanion (false ));
275
+ await prepare (tester, early: true );
276
+ final message = eg.streamMessage ();
277
+ await openNotification (eg.selfAccount, message);
278
+ // The app should still not be ready (or else this test won't work right).
279
+ check (ZulipApp .ready.value).isFalse ();
280
+ check (ZulipApp .navigatorKey.currentState).isNull ();
281
+ // And the openNotification hasn't caused any navigation yet.
282
+ check (pushedRoutes).isEmpty ();
283
+
284
+ // Now let the GlobalStore get loaded and the app's main UI get mounted.
285
+ await tester.pump ();
286
+ // The navigator first pushes the home route…
287
+ check (pushedRoutes).length.equals (2 );
288
+ check (pushedRoutes[0 ]).settings.name.equals ("/" );
289
+ // … and then the one the notification leads to.
290
+ matchesNavigation (check (pushedRoutes[1 ]), eg.selfAccount, message);
291
+ });
292
+
293
+ testWidgets ('at app launch' , (tester) async {
294
+ // Set up a value for `getNotificationLaunchDetails` to return.
295
+ final account = eg.selfAccount;
296
+ final message = eg.streamMessage ();
297
+ final response = NotificationResponse (
298
+ notificationResponseType: NotificationResponseType .selectedNotification,
299
+ payload: jsonEncode (messageFcmMessage (message, account: account)));
300
+ testBinding.notifications.appLaunchDetails =
301
+ NotificationAppLaunchDetails (true , notificationResponse: response);
302
+
303
+ // Now start the app.
304
+ testBinding.globalStore.insertAccount (account.toCompanion (false ));
305
+ await prepare (tester, early: true );
306
+ check (pushedRoutes).isEmpty (); // GlobalStore hasn't loaded yet
307
+
308
+ // Once the app is ready, we navigate to the conversation.
309
+ await tester.pump ();
310
+ check (pushedRoutes).length.equals (2 );
311
+ check (pushedRoutes[0 ]).settings.name.equals ("/" );
312
+ matchesNavigation (check (pushedRoutes[1 ]), account, message);
275
313
});
276
314
});
277
315
}
0 commit comments