1
+ import 'dart:convert' ;
2
+
1
3
import 'package:checks/checks.dart' ;
2
4
import 'package:flutter/material.dart' ;
3
5
import 'package:flutter/services.dart' ;
@@ -7,10 +9,12 @@ import 'package:http/http.dart' as http;
7
9
import 'package:zulip/api/model/model.dart' ;
8
10
import 'package:zulip/api/route/messages.dart' ;
9
11
import 'package:zulip/model/compose.dart' ;
12
+ import 'package:zulip/model/localizations.dart' ;
10
13
import 'package:zulip/model/narrow.dart' ;
11
14
import 'package:zulip/model/store.dart' ;
12
15
import 'package:zulip/widgets/compose_box.dart' ;
13
16
import 'package:zulip/widgets/content.dart' ;
17
+ import 'package:zulip/widgets/icons.dart' ;
14
18
import 'package:zulip/widgets/message_list.dart' ;
15
19
import 'package:zulip/widgets/store.dart' ;
16
20
import 'package:share_plus_platform_interface/method_channel/method_channel_share.dart' ;
@@ -142,6 +146,102 @@ void main() {
142
146
});
143
147
});
144
148
149
+ group ('StarButton' , () {
150
+ Future <void > tapButton (WidgetTester tester) async {
151
+ // Starred messages include the same icon so we need to
152
+ // match only by descendants of [BottomSheet].
153
+ await tester.ensureVisible (find.descendant (
154
+ of: find.byType (BottomSheet ),
155
+ matching: find.byIcon (ZulipIcons .star_filled, skipOffstage: false )));
156
+ await tester.tap (find.descendant (
157
+ of: find.byType (BottomSheet ),
158
+ matching: find.byIcon (ZulipIcons .star_filled)));
159
+ await tester.pump (); // [MenuItemButton.onPressed] called in a post-frame callback: flutter/flutter@e4a39fa2e
160
+ }
161
+
162
+ testWidgets ('star success' , (WidgetTester tester) async {
163
+ final message = eg.streamMessage (flags: []);
164
+ await setupToMessageActionSheet (tester, message: message, narrow: TopicNarrow .ofMessage (message));
165
+ final store = await testBinding.globalStore.perAccount (eg.selfAccount.id);
166
+
167
+ final connection = store.connection as FakeApiConnection ;
168
+ connection.prepare (json: {});
169
+ await tapButton (tester);
170
+ await tester.pump (Duration .zero);
171
+
172
+ check (connection.lastRequest).isA< http.Request > ()
173
+ ..method.equals ('POST' )
174
+ ..url.path.equals ('/api/v1/messages/flags' )
175
+ ..bodyFields.deepEquals ({
176
+ 'messages' : jsonEncode ([message.id]),
177
+ 'op' : 'add' ,
178
+ 'flag' : 'starred' ,
179
+ });
180
+ });
181
+
182
+ testWidgets ('unstar success' , (WidgetTester tester) async {
183
+ final message = eg.streamMessage (flags: [MessageFlag .starred]);
184
+ await setupToMessageActionSheet (tester, message: message, narrow: TopicNarrow .ofMessage (message));
185
+ final store = await testBinding.globalStore.perAccount (eg.selfAccount.id);
186
+
187
+ final connection = store.connection as FakeApiConnection ;
188
+ connection.prepare (json: {});
189
+ await tapButton (tester);
190
+ await tester.pump (Duration .zero);
191
+
192
+ check (connection.lastRequest).isA< http.Request > ()
193
+ ..method.equals ('POST' )
194
+ ..url.path.equals ('/api/v1/messages/flags' )
195
+ ..bodyFields.deepEquals ({
196
+ 'messages' : jsonEncode ([message.id]),
197
+ 'op' : 'remove' ,
198
+ 'flag' : 'starred' ,
199
+ });
200
+ });
201
+
202
+ testWidgets ('star request has an error' , (WidgetTester tester) async {
203
+ final message = eg.streamMessage (flags: []);
204
+ await setupToMessageActionSheet (tester, message: message, narrow: TopicNarrow .ofMessage (message));
205
+ final store = await testBinding.globalStore.perAccount (eg.selfAccount.id);
206
+ final zulipLocalizations = GlobalLocalizations .zulipLocalizations;
207
+
208
+ final connection = store.connection as FakeApiConnection ;
209
+
210
+ connection.prepare (httpStatus: 400 , json: {
211
+ 'code' : 'BAD_REQUEST' ,
212
+ 'msg' : 'Invalid message(s)' ,
213
+ 'result' : 'error' ,
214
+ });
215
+ await tapButton (tester);
216
+ await tester.pump (Duration .zero); // error arrives; error dialog shows
217
+
218
+ await tester.tap (find.byWidget (checkErrorDialog (tester,
219
+ expectedTitle: zulipLocalizations.errorStarMessageFailedTitle,
220
+ expectedMessage: 'Invalid message(s)' )));
221
+ });
222
+
223
+ testWidgets ('unstar request has an error' , (WidgetTester tester) async {
224
+ final message = eg.streamMessage (flags: [MessageFlag .starred]);
225
+ await setupToMessageActionSheet (tester, message: message, narrow: TopicNarrow .ofMessage (message));
226
+ final store = await testBinding.globalStore.perAccount (eg.selfAccount.id);
227
+ final zulipLocalizations = GlobalLocalizations .zulipLocalizations;
228
+
229
+ final connection = store.connection as FakeApiConnection ;
230
+
231
+ connection.prepare (httpStatus: 400 , json: {
232
+ 'code' : 'BAD_REQUEST' ,
233
+ 'msg' : 'Invalid message(s)' ,
234
+ 'result' : 'error' ,
235
+ });
236
+ await tapButton (tester);
237
+ await tester.pump (Duration .zero); // error arrives; error dialog shows
238
+
239
+ await tester.tap (find.byWidget (checkErrorDialog (tester,
240
+ expectedTitle: zulipLocalizations.errorUnstarMessageFailedTitle,
241
+ expectedMessage: 'Invalid message(s)' )));
242
+ });
243
+ });
244
+
145
245
group ('ShareButton' , () {
146
246
// Tests should call this.
147
247
MockSharePlus setupMockSharePlus () {
0 commit comments