1
1
import 'package:checks/checks.dart' ;
2
2
import 'package:flutter/material.dart' ;
3
+ import 'package:flutter_checks/flutter_checks.dart' ;
3
4
import 'package:flutter_test/flutter_test.dart' ;
5
+ import 'package:zulip/api/model/events.dart' ;
4
6
import 'package:zulip/api/model/model.dart' ;
5
7
import 'package:zulip/api/route/messages.dart' ;
6
8
import 'package:zulip/api/route/channels.dart' ;
9
+ import 'package:zulip/api/route/realm.dart' ;
7
10
import 'package:zulip/model/compose.dart' ;
11
+ import 'package:zulip/model/emoji.dart' ;
8
12
import 'package:zulip/model/localizations.dart' ;
9
13
import 'package:zulip/model/narrow.dart' ;
10
14
import 'package:zulip/model/store.dart' ;
@@ -28,7 +32,7 @@ import 'test_app.dart';
28
32
/// The caller must set [debugNetworkImageHttpClientProvider] back to null
29
33
/// before the end of the test.
30
34
Future <Finder > setupToComposeInput (WidgetTester tester, {
31
- required List <User > users,
35
+ List <User > users = const [] ,
32
36
}) async {
33
37
TypingNotifier .debugEnable = false ;
34
38
addTearDown (TypingNotifier .debugReset);
@@ -108,19 +112,20 @@ Future<Finder> setupToTopicInput(WidgetTester tester, {
108
112
return finder;
109
113
}
110
114
111
- void main () {
112
- TestZulipBinding .ensureInitialized ();
115
+ Finder findNetworkImage (String url) {
116
+ return find.byWidgetPredicate ((widget) => switch (widget) {
117
+ Image (image: NetworkImage (url: var imageUrl)) when imageUrl == url
118
+ => true ,
119
+ _ => false ,
120
+ });
121
+ }
113
122
114
- group ( 'ComposeAutocomplete' , () {
123
+ typedef ExpectedEmoji = ( String label, EmojiDisplay display);
115
124
116
- Finder findNetworkImage (String url) {
117
- return find.byWidgetPredicate ((widget) => switch (widget) {
118
- Image (image: NetworkImage (url: var imageUrl)) when imageUrl == url
119
- => true ,
120
- _ => false ,
121
- });
122
- }
125
+ void main () {
126
+ TestZulipBinding .ensureInitialized ();
123
127
128
+ group ('@-mentions' , () {
124
129
void checkUserShown (User user, PerAccountStore store, {required bool expected}) {
125
130
check (find.text (user.fullName).evaluate ().length).equals (expected ? 1 : 0 );
126
131
final avatarFinder =
@@ -174,6 +179,98 @@ void main() {
174
179
});
175
180
});
176
181
182
+ group ('emoji' , () {
183
+ void checkEmojiShown (ExpectedEmoji option, {required bool expected}) {
184
+ final (label, display) = option;
185
+ final labelSubject = check (find.text (label));
186
+ expected ? labelSubject.findsOne () : labelSubject.findsNothing ();
187
+
188
+ final Subject <Finder > displaySubject;
189
+ switch (display) {
190
+ case UnicodeEmojiDisplay ():
191
+ displaySubject = check (find.text (display.emojiUnicode));
192
+ case ImageEmojiDisplay ():
193
+ displaySubject = check (findNetworkImage (display.resolvedUrl.toString ()));
194
+ case TextEmojiDisplay ():
195
+ // We test this case in the "text emoji" test below,
196
+ // but that doesn't use this helper method.
197
+ throw UnimplementedError ();
198
+ }
199
+ expected ? displaySubject.findsOne (): displaySubject.findsNothing ();
200
+ }
201
+
202
+ testWidgets ('show, update, choose' , (tester) async {
203
+ final composeInputFinder = await setupToComposeInput (tester);
204
+ final store = await testBinding.globalStore.perAccount (eg.selfAccount.id);
205
+ store.setServerEmojiData (ServerEmojiData (codeToNames: {
206
+ '1f4a4' : ['zzz' , 'sleepy' ], // (just 'zzz' in real data)
207
+ }));
208
+ await store.handleEvent (RealmEmojiUpdateEvent (id: 1 , realmEmoji: {
209
+ '1' : eg.realmEmojiItem (emojiCode: '1' , emojiName: 'buzzing' ),
210
+ }));
211
+
212
+ final zulipOption = ('zulip' , store.emojiDisplayFor (
213
+ emojiType: ReactionType .zulipExtraEmoji,
214
+ emojiCode: 'zulip' , emojiName: 'zulip' ));
215
+ final buzzingOption = ('buzzing' , store.emojiDisplayFor (
216
+ emojiType: ReactionType .realmEmoji,
217
+ emojiCode: '1' , emojiName: 'buzzing' ));
218
+ final zzzOption = ('zzz, sleepy' , store.emojiDisplayFor (
219
+ emojiType: ReactionType .unicodeEmoji,
220
+ emojiCode: '1f4a4' , emojiName: 'zzz' ));
221
+
222
+ // Enter a query; options appear, of all three emoji types.
223
+ // TODO(#226): Remove this extra edit when this bug is fixed.
224
+ await tester.enterText (composeInputFinder, 'hi :' );
225
+ await tester.enterText (composeInputFinder, 'hi :z' );
226
+ await tester.pump ();
227
+ checkEmojiShown (expected: true , zzzOption);
228
+ checkEmojiShown (expected: true , buzzingOption);
229
+ checkEmojiShown (expected: true , zulipOption);
230
+
231
+ // Edit query; options change.
232
+ await tester.enterText (composeInputFinder, 'hi :zz' );
233
+ await tester.pump ();
234
+ checkEmojiShown (expected: true , zzzOption);
235
+ checkEmojiShown (expected: true , buzzingOption);
236
+ checkEmojiShown (expected: false , zulipOption);
237
+
238
+ // Choosing an option enters result and closes autocomplete.
239
+ await tester.tap (find.text ('buzzing' ));
240
+ await tester.pump ();
241
+ check (tester.widget <TextField >(composeInputFinder).controller! .text)
242
+ .equals ('hi :buzzing:' );
243
+ checkEmojiShown (expected: false , zzzOption);
244
+ checkEmojiShown (expected: false , buzzingOption);
245
+ checkEmojiShown (expected: false , zulipOption);
246
+
247
+ debugNetworkImageHttpClientProvider = null ;
248
+ });
249
+
250
+ testWidgets ('text emoji means just show text' , (tester) async {
251
+ final composeInputFinder = await setupToComposeInput (tester);
252
+ final store = await testBinding.globalStore.perAccount (eg.selfAccount.id);
253
+ await store.handleEvent (UserSettingsUpdateEvent (id: 1 ,
254
+ property: UserSettingName .emojiset, value: Emojiset .text));
255
+
256
+ // TODO(#226): Remove this extra edit when this bug is fixed.
257
+ await tester.enterText (composeInputFinder, 'hi :' );
258
+ await tester.enterText (composeInputFinder, 'hi :z' );
259
+ await tester.pump ();
260
+
261
+ // The emoji's name appears. (And only once.)
262
+ check (find.text ('zulip' )).findsOne ();
263
+
264
+ // But no emoji image appears.
265
+ check (find.byWidgetPredicate ((widget) => switch (widget) {
266
+ Image (image: NetworkImage ()) => true ,
267
+ _ => false ,
268
+ })).findsNothing ();
269
+
270
+ debugNetworkImageHttpClientProvider = null ;
271
+ });
272
+ });
273
+
177
274
group ('TopicAutocomplete' , () {
178
275
void checkTopicShown (GetStreamTopicsEntry topic, PerAccountStore store, {required bool expected}) {
179
276
check (find.text (topic.name).evaluate ().length).equals (expected ? 1 : 0 );
0 commit comments