@@ -3,9 +3,12 @@ import 'package:flutter/material.dart';
3
3
import 'package:flutter_checks/flutter_checks.dart' ;
4
4
import 'package:flutter_test/flutter_test.dart' ;
5
5
import 'package:zulip/api/model/model.dart' ;
6
+ import 'package:zulip/basic.dart' ;
7
+ import 'package:zulip/model/store.dart' ;
6
8
import 'package:zulip/widgets/app_bar.dart' ;
7
9
import 'package:zulip/widgets/compose_box.dart' ;
8
10
import 'package:zulip/widgets/content.dart' ;
11
+ import 'package:zulip/widgets/emoji.dart' ;
9
12
import 'package:zulip/widgets/home.dart' ;
10
13
import 'package:zulip/widgets/icons.dart' ;
11
14
import 'package:zulip/widgets/new_dm_sheet.dart' ;
@@ -19,6 +22,8 @@ import '../model/test_store.dart';
19
22
import '../test_navigation.dart' ;
20
23
import 'test_app.dart' ;
21
24
25
+ late PerAccountStore store;
26
+
22
27
Future <void > setupSheet (WidgetTester tester, {
23
28
required List <User > users,
24
29
List <int >? mutedUserIds,
@@ -30,7 +35,7 @@ Future<void> setupSheet(WidgetTester tester, {
30
35
..onPushed = (route, _) => lastPushedRoute = route;
31
36
32
37
await testBinding.globalStore.add (eg.selfAccount, eg.initialSnapshot ());
33
- final store = await testBinding.globalStore.perAccount (eg.selfAccount.id);
38
+ store = await testBinding.globalStore.perAccount (eg.selfAccount.id);
34
39
await store.addUsers (users);
35
40
if (mutedUserIds != null ) {
36
41
await store.setMutedUsers (mutedUserIds);
@@ -65,7 +70,8 @@ void main() {
65
70
}
66
71
67
72
Finder findUserTile (User user) =>
68
- find.widgetWithText (InkWell , user.fullName).first;
73
+ find.ancestor (of: find.textContaining (user.fullName),
74
+ matching: find.byType (InkWell )).first;
69
75
70
76
Finder findUserChip (User user) {
71
77
final findAvatar = find.byWidgetPredicate ((widget) =>
@@ -120,23 +126,23 @@ void main() {
120
126
121
127
testWidgets ('shows all non-muted users initially' , (tester) async {
122
128
await setupSheet (tester, users: testUsers, mutedUserIds: [mutedUser.userId]);
123
- check (find.text ('Alice Anderson' )).findsOne ();
124
- check (find.text ('Bob Brown' )).findsOne ();
125
- check (find.text ('Charlie Carter' )).findsOne ();
129
+ check (find.textContaining ('Alice Anderson' )).findsOne ();
130
+ check (find.textContaining ('Bob Brown' )).findsOne ();
131
+ check (find.textContaining ('Charlie Carter' )).findsOne ();
126
132
127
133
check (find.byIcon (ZulipIcons .check_circle_unchecked)).findsExactly (3 );
128
134
check (find.byIcon (ZulipIcons .check_circle_checked)).findsNothing ();
129
- check (find.text ('Someone Muted' )).findsNothing ();
130
- check (find.text ('Muted user' )).findsNothing ();
135
+ check (find.textContaining ('Someone Muted' )).findsNothing ();
136
+ check (find.textContaining ('Muted user' )).findsNothing ();
131
137
});
132
138
133
139
testWidgets ('shows filtered users based on search' , (tester) async {
134
140
await setupSheet (tester, users: testUsers);
135
141
await tester.enterText (find.byType (TextField ), 'Alice' );
136
142
await tester.pump ();
137
- check (find.text ('Alice Anderson' )).findsOne ();
138
- check (find.text ('Charlie Carter' )).findsNothing ();
139
- check (find.text ('Bob Brown' )).findsNothing ();
143
+ check (find.textContaining ('Alice Anderson' )).findsOne ();
144
+ check (find.textContaining ('Charlie Carter' )).findsNothing ();
145
+ check (find.textContaining ('Bob Brown' )).findsNothing ();
140
146
});
141
147
142
148
// TODO test sorting by recent-DMs
@@ -146,43 +152,43 @@ void main() {
146
152
await setupSheet (tester, users: testUsers);
147
153
await tester.enterText (find.byType (TextField ), 'alice' );
148
154
await tester.pump ();
149
- check (find.text ('Alice Anderson' )).findsOne ();
155
+ check (find.textContaining ('Alice Anderson' )).findsOne ();
150
156
151
157
await tester.enterText (find.byType (TextField ), 'ALICE' );
152
158
await tester.pump ();
153
- check (find.text ('Alice Anderson' )).findsOne ();
159
+ check (find.textContaining ('Alice Anderson' )).findsOne ();
154
160
});
155
161
156
162
testWidgets ('partial name and last name search handling' , (tester) async {
157
163
await setupSheet (tester, users: testUsers);
158
164
159
165
await tester.enterText (find.byType (TextField ), 'Ali' );
160
166
await tester.pump ();
161
- check (find.text ('Alice Anderson' )).findsOne ();
162
- check (find.text ('Bob Brown' )).findsNothing ();
163
- check (find.text ('Charlie Carter' )).findsNothing ();
167
+ check (find.textContaining ('Alice Anderson' )).findsOne ();
168
+ check (find.textContaining ('Bob Brown' )).findsNothing ();
169
+ check (find.textContaining ('Charlie Carter' )).findsNothing ();
164
170
165
171
await tester.enterText (find.byType (TextField ), 'Anderson' );
166
172
await tester.pump ();
167
- check (find.text ('Alice Anderson' )).findsOne ();
168
- check (find.text ('Charlie Carter' )).findsNothing ();
169
- check (find.text ('Bob Brown' )).findsNothing ();
173
+ check (find.textContaining ('Alice Anderson' )).findsOne ();
174
+ check (find.textContaining ('Charlie Carter' )).findsNothing ();
175
+ check (find.textContaining ('Bob Brown' )).findsNothing ();
170
176
171
177
await tester.enterText (find.byType (TextField ), 'son' );
172
178
await tester.pump ();
173
- check (find.text ('Alice Anderson' )).findsOne ();
174
- check (find.text ('Charlie Carter' )).findsNothing ();
175
- check (find.text ('Bob Brown' )).findsNothing ();
179
+ check (find.textContaining ('Alice Anderson' )).findsOne ();
180
+ check (find.textContaining ('Charlie Carter' )).findsNothing ();
181
+ check (find.textContaining ('Bob Brown' )).findsNothing ();
176
182
});
177
183
178
184
testWidgets ('shows empty state when no users match' , (tester) async {
179
185
await setupSheet (tester, users: testUsers);
180
186
await tester.enterText (find.byType (TextField ), 'Zebra' );
181
187
await tester.pump ();
182
- check (find.text ('No users found' )).findsOne ();
183
- check (find.text ('Alice Anderson' )).findsNothing ();
184
- check (find.text ('Bob Brown' )).findsNothing ();
185
- check (find.text ('Charlie Carter' )).findsNothing ();
188
+ check (find.textContaining ('No users found' )).findsOne ();
189
+ check (find.textContaining ('Alice Anderson' )).findsNothing ();
190
+ check (find.textContaining ('Bob Brown' )).findsNothing ();
191
+ check (find.textContaining ('Charlie Carter' )).findsNothing ();
186
192
});
187
193
188
194
testWidgets ('search text clears when user is selected' , (tester) async {
@@ -252,7 +258,7 @@ void main() {
252
258
await tester.tap (findUserTile (eg.selfUser));
253
259
await tester.pump ();
254
260
checkUserSelected (tester, eg.selfUser, true );
255
- check (find.text (eg.selfUser.fullName)).findsExactly (2 );
261
+ check (find.textContaining (eg.selfUser.fullName)).findsExactly (2 );
256
262
257
263
await tester.tap (findUserTile (otherUser));
258
264
await tester.pump ();
@@ -264,7 +270,7 @@ void main() {
264
270
final otherUser = eg.user (fullName: 'Other User' );
265
271
await setupSheet (tester, users: [eg.selfUser, otherUser]);
266
272
267
- check (find.text (eg.selfUser.fullName)).findsOne ();
273
+ check (find.textContaining (eg.selfUser.fullName)).findsOne ();
268
274
269
275
await tester.tap (findUserTile (otherUser));
270
276
await tester.pump ();
@@ -285,6 +291,110 @@ void main() {
285
291
});
286
292
});
287
293
294
+ group ('User status' , () {
295
+ void checkTileStatusEmoji (WidgetTester tester, User user, {required bool isPresent}) {
296
+ final statusEmojiFinder = find.ancestor (
297
+ of: find.byType (UnicodeEmojiWidget ),
298
+ matching: find.byType (UserStatusEmoji ));
299
+ final tileStatusEmojiFinder = find.descendant (of: findUserTile (user),
300
+ matching: statusEmojiFinder);
301
+
302
+ if (isPresent) {
303
+ check (tester.firstWidget <UserStatusEmoji >(tileStatusEmojiFinder)
304
+ .neverAnimate).isTrue ();
305
+ check (tileStatusEmojiFinder).findsOne ();
306
+ } else {
307
+ check (tileStatusEmojiFinder).findsNothing ();
308
+ }
309
+ }
310
+
311
+ void checkChipStatusEmoji (WidgetTester tester, User user, {required bool isPresent}) {
312
+ final statusEmojiFinder = find.ancestor (
313
+ of: find.byType (UnicodeEmojiWidget ),
314
+ matching: find.byType (UserStatusEmoji ));
315
+ final chipStatusEmojiFinder = find.descendant (of: findUserChip (user),
316
+ matching: statusEmojiFinder);
317
+
318
+ if (isPresent) {
319
+ check (tester.firstWidget <UserStatusEmoji >(chipStatusEmojiFinder)
320
+ .neverAnimate).isTrue ();
321
+ check (chipStatusEmojiFinder).findsOne ();
322
+ } else {
323
+ check (chipStatusEmojiFinder).findsNothing ();
324
+ }
325
+ }
326
+
327
+ testWidgets ('status emoji & text are set -> emoji is displayed, text is not' , (tester) async {
328
+ final user = eg.user ();
329
+ await setupSheet (tester, users: [user]);
330
+ await store.changeUserStatuses ({
331
+ user.userId: UserStatusChange (
332
+ text: OptionSome ('Busy' ),
333
+ emoji: OptionSome (StatusEmoji (emojiName: 'working_on_it' ,
334
+ emojiCode: '1f6e0' , reactionType: ReactionType .unicodeEmoji))),
335
+ });
336
+ await tester.pump ();
337
+
338
+ checkTileStatusEmoji (tester, user, isPresent: true );
339
+ check (find.descendant (of: findUserTile (user),
340
+ matching: find.textContaining ('Busy' ))).findsNothing ();
341
+ check (findUserChip (user)).findsNothing ();
342
+
343
+ await tester.tap (findUserTile (user));
344
+ await tester.pump ();
345
+
346
+ checkTileStatusEmoji (tester, user, isPresent: true );
347
+ check (find.descendant (of: findUserTile (user),
348
+ matching: find.textContaining ('Busy' ))).findsNothing ();
349
+ check (findUserChip (user)).findsOne ();
350
+ checkChipStatusEmoji (tester, user, isPresent: true );
351
+ check (find.descendant (of: findUserChip (user),
352
+ matching: find.text ('Busy' ))).findsNothing ();
353
+ });
354
+
355
+ testWidgets ('status emoji is not set, text is set -> none of them is displayed' , (tester) async {
356
+ final user = eg.user ();
357
+ await setupSheet (tester, users: [user]);
358
+ await store.changeUserStatuses ({
359
+ user.userId: UserStatusChange (
360
+ text: OptionSome ('Busy' ),
361
+ emoji: OptionNone ()),
362
+ });
363
+ await tester.pump ();
364
+
365
+ checkTileStatusEmoji (tester, user, isPresent: false );
366
+ check (find.descendant (of: findUserTile (user),
367
+ matching: find.textContaining ('Busy' ))).findsNothing ();
368
+ check (findUserChip (user)).findsNothing ();
369
+
370
+ await tester.tap (findUserTile (user));
371
+ await tester.pump ();
372
+
373
+ checkTileStatusEmoji (tester, user, isPresent: false );
374
+ check (find.descendant (of: findUserTile (user),
375
+ matching: find.textContaining ('Busy' ))).findsNothing ();
376
+ check (findUserChip (user)).findsOne ();
377
+ checkChipStatusEmoji (tester, user, isPresent: false );
378
+ check (find.descendant (of: findUserChip (user),
379
+ matching: find.text ('Busy' ))).findsNothing ();
380
+ });
381
+
382
+ testWidgets ('status is not set -> emoji is not displayed' , (tester) async {
383
+ final user = eg.user ();
384
+ await setupSheet (tester, users: [user]);
385
+
386
+ checkTileStatusEmoji (tester, user, isPresent: false );
387
+ check (findUserChip (user)).findsNothing ();
388
+
389
+ await tester.tap (findUserTile (user));
390
+ await tester.pump ();
391
+
392
+ checkTileStatusEmoji (tester, user, isPresent: false );
393
+ check (findUserChip (user)).findsOne ();
394
+ checkChipStatusEmoji (tester, user, isPresent: false );
395
+ });
396
+ });
397
+
288
398
group ('navigation to DM Narrow' , () {
289
399
Future <void > runAndCheck (WidgetTester tester, {
290
400
required List <User > users,
0 commit comments