@@ -1061,6 +1061,163 @@ void main() {
1061
1061
});
1062
1062
});
1063
1063
1064
+ group ('MarkTopicAsReadButton' , () {
1065
+ Future <void > setupToTopicActionSheetWithUnreadMessages (WidgetTester tester, {
1066
+ int ? zulipFeatureLevel,
1067
+ ZulipStream ? channel,
1068
+ }) async {
1069
+ addTearDown (testBinding.reset);
1070
+
1071
+ final effectiveChannel = channel ?? eg.stream ();
1072
+ const topicName = TopicName ('test topic' );
1073
+ final message = eg.streamMessage (stream: effectiveChannel, topic: 'test topic' );
1074
+ final account = eg.selfAccount.copyWith (zulipFeatureLevel: zulipFeatureLevel);
1075
+ await testBinding.globalStore.add (account, eg.initialSnapshot (
1076
+ realmUsers: [eg.selfUser],
1077
+ streams: [effectiveChannel],
1078
+ subscriptions: [eg.subscription (effectiveChannel)],
1079
+ zulipFeatureLevel: zulipFeatureLevel));
1080
+ store = await testBinding.globalStore.perAccount (account.id);
1081
+ connection = store.connection as FakeApiConnection ;
1082
+
1083
+ connection.prepare (json: eg.newestGetMessagesResult (
1084
+ foundOldest: true , messages: [message]).toJson ());
1085
+
1086
+ await store.addMessage (message);
1087
+ store.unreads.streams[effectiveChannel.streamId] ?? = {};
1088
+ store.unreads.streams[effectiveChannel.streamId]! [topicName] ?? = QueueList <int >();
1089
+ store.unreads.streams[effectiveChannel.streamId]! [topicName]! .add (message.id);
1090
+
1091
+ await tester.pumpWidget (TestZulipApp (accountId: account.id,
1092
+ child: MessageListPage (initNarrow: TopicNarrow (effectiveChannel.streamId, topicName))));
1093
+ await tester.pumpAndSettle ();
1094
+
1095
+ await tester.longPress (find.byType (ZulipAppBar ));
1096
+ await tester.pump (const Duration (milliseconds: 250 ));
1097
+ }
1098
+
1099
+ Future <void > setupToTopicActionSheetWithNoUnreadMessages (WidgetTester tester) async {
1100
+ addTearDown (testBinding.reset);
1101
+
1102
+ final channel = eg.stream ();
1103
+ const topicName = TopicName ('test topic' );
1104
+ final message = eg.streamMessage (stream: channel, topic: 'test topic' , flags: [MessageFlag .read]);
1105
+
1106
+ await testBinding.globalStore.add (eg.selfAccount, eg.initialSnapshot (
1107
+ realmUsers: [eg.selfUser],
1108
+ streams: [channel],
1109
+ subscriptions: [eg.subscription (channel)]));
1110
+ store = await testBinding.globalStore.perAccount (eg.selfAccount.id);
1111
+ connection = store.connection as FakeApiConnection ;
1112
+
1113
+ connection.prepare (json: eg.newestGetMessagesResult (
1114
+ foundOldest: true , messages: [message]).toJson ());
1115
+
1116
+ await store.addMessage (message);
1117
+
1118
+ await tester.pumpWidget (TestZulipApp (accountId: eg.selfAccount.id,
1119
+ child: MessageListPage (initNarrow: TopicNarrow (channel.streamId, topicName))));
1120
+ await tester.pumpAndSettle ();
1121
+
1122
+ await tester.longPress (find.byType (ZulipAppBar ));
1123
+ await tester.pump (const Duration (milliseconds: 250 ));
1124
+ }
1125
+
1126
+ Future <void > tapMarkTopicAsReadButton (WidgetTester tester) async {
1127
+ final zulipLocalizations = GlobalLocalizations .zulipLocalizations;
1128
+ await tester.tap (find.text (zulipLocalizations.actionSheetOptionMarkTopicAsRead));
1129
+ await tester.pump ();
1130
+ }
1131
+
1132
+ group ('visibility' , () {
1133
+ testWidgets ('shows button when topic has unread messages' , (tester) async {
1134
+ await setupToTopicActionSheetWithUnreadMessages (tester);
1135
+
1136
+ final zulipLocalizations = GlobalLocalizations .zulipLocalizations;
1137
+ check (find.text (zulipLocalizations.actionSheetOptionMarkTopicAsRead)).findsOne ();
1138
+ });
1139
+
1140
+ testWidgets ('hides button when topic has no unread messages' , (tester) async {
1141
+ await setupToTopicActionSheetWithNoUnreadMessages (tester);
1142
+
1143
+ final zulipLocalizations = GlobalLocalizations .zulipLocalizations;
1144
+ check (find.text (zulipLocalizations.actionSheetOptionMarkTopicAsRead)).findsNothing ();
1145
+ });
1146
+ });
1147
+
1148
+ group ('API requests' , () {
1149
+ testWidgets ('sends mark_topic_as_read request for server feature level < 155' , (tester) async {
1150
+ final channel = eg.stream ();
1151
+ await setupToTopicActionSheetWithUnreadMessages (tester,
1152
+ zulipFeatureLevel: 154 ,
1153
+ channel: channel);
1154
+
1155
+ connection.prepare (json: {'result' : 'success' });
1156
+ await tapMarkTopicAsReadButton (tester);
1157
+ await tester.pumpAndSettle ();
1158
+
1159
+ check (connection.lastRequest).isA< http.Request > ()
1160
+ ..method.equals ('POST' )
1161
+ ..url.path.equals ('/api/v1/mark_topic_as_read' )
1162
+ ..bodyFields.deepEquals ({
1163
+ 'stream_id' : '${channel .streamId }' ,
1164
+ 'topic_name' : 'test topic' ,
1165
+ });
1166
+ // await tester.pumpAndSettle();
1167
+ });
1168
+
1169
+ testWidgets ('sends messages/flags/narrow request for server feature level >= 155' , (tester) async {
1170
+ final channel = eg.stream ();
1171
+ await setupToTopicActionSheetWithUnreadMessages (tester,
1172
+ zulipFeatureLevel: 155 ,
1173
+ channel: channel);
1174
+
1175
+ connection.prepare (json: UpdateMessageFlagsForNarrowResult (
1176
+ processedCount: 11 ,
1177
+ updatedCount: 3 ,
1178
+ firstProcessedId: 1 ,
1179
+ lastProcessedId: 1980 ,
1180
+ foundOldest: true ,
1181
+ foundNewest: true ).toJson ());
1182
+
1183
+ await tapMarkTopicAsReadButton (tester);
1184
+ await tester.pumpAndSettle ();
1185
+
1186
+ check (connection.lastRequest).isA< http.Request > ()
1187
+ ..method.equals ('POST' )
1188
+ ..url.path.equals ('/api/v1/messages/flags/narrow' )
1189
+ ..bodyFields.deepEquals ({
1190
+ 'anchor' : 'oldest' ,
1191
+ 'num_before' : '0' ,
1192
+ 'num_after' : '1000' ,
1193
+ 'narrow' : jsonEncode ([
1194
+ {'operator' : 'stream' , 'operand' : channel.streamId},
1195
+ {'operator' : 'topic' , 'operand' : 'test topic' },
1196
+ {'operator' : 'is' , 'operand' : 'unread' },
1197
+ ]),
1198
+ 'op' : 'add' ,
1199
+ 'flag' : 'read' ,
1200
+ });
1201
+ });
1202
+
1203
+ testWidgets ('shows error dialog when mark-as-read request fails' , (tester) async {
1204
+ final channel = eg.stream ();
1205
+ await setupToTopicActionSheetWithUnreadMessages (tester,
1206
+ zulipFeatureLevel: 154 ,
1207
+ channel: channel);
1208
+
1209
+ prepareRawContentResponseError ();
1210
+ await tapMarkTopicAsReadButton (tester);
1211
+ await tester.pumpAndSettle ();
1212
+
1213
+ final zulipLocalizations = GlobalLocalizations .zulipLocalizations;
1214
+ checkErrorDialog (tester,
1215
+ expectedTitle: zulipLocalizations.errorMarkTopicAsReadFailed,
1216
+ expectedMessage: 'Invalid message(s)' );
1217
+ });
1218
+ });
1219
+ });
1220
+
1064
1221
group ('MessageActionSheetCancelButton' , () {
1065
1222
final zulipLocalizations = GlobalLocalizations .zulipLocalizations;
1066
1223
0 commit comments