Skip to content

Commit 62ac84f

Browse files
notif test: Expand test coverage for messaging style notif
Add more tests for Android messaging style notif implementation, listed here: #718 (review)
1 parent 8556775 commit 62ac84f

File tree

1 file changed

+193
-8
lines changed

1 file changed

+193
-8
lines changed

test/notifications/display_test.dart

+193-8
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
11
import 'dart:convert';
2+
import 'dart:io';
23
import 'dart:typed_data';
34

45
import 'package:checks/checks.dart';
56
import 'package:collection/collection.dart';
67
import 'package:fake_async/fake_async.dart';
78
import 'package:firebase_messaging/firebase_messaging.dart';
9+
import 'package:flutter/foundation.dart';
810
import 'package:flutter/material.dart';
911
import 'package:flutter_local_notifications/flutter_local_notifications.dart' hide Message, Person;
1012
import 'package:flutter_test/flutter_test.dart';
13+
import 'package:http/http.dart' as http;
14+
import 'package:http/testing.dart' as http_testing;
1115
import 'package:zulip/api/model/model.dart';
1216
import 'package:zulip/api/notifications.dart';
1317
import 'package:zulip/host/android_notifications.dart';
@@ -25,6 +29,7 @@ import 'package:zulip/widgets/theme.dart';
2529
import '../fake_async.dart';
2630
import '../model/binding.dart';
2731
import '../example_data.dart' as eg;
32+
import '../test_images.dart';
2833
import '../test_navigation.dart';
2934
import '../widgets/message_list_checks.dart';
3035
import '../widgets/page_checks.dart';
@@ -79,6 +84,17 @@ void main() {
7984
TestZulipBinding.ensureInitialized();
8085
final zulipLocalizations = GlobalLocalizations.zulipLocalizations;
8186

87+
final mockHttpClient = http_testing.MockClient(
88+
(request) async => http.Response.bytes(kSolidBlueAvatar, HttpStatus.ok));
89+
90+
T Function() runWithHttpClient<T>(
91+
Future<T> Function(FakeAsync async) callback, {
92+
http.Client Function()? httpClientFactory,
93+
}) =>
94+
() => http.runWithClient(
95+
() => awaitFakeAsync(callback),
96+
httpClientFactory ?? () => mockHttpClient);
97+
8298
Future<void> init() async {
8399
addTearDown(testBinding.reset);
84100
testBinding.firebaseMessagingInitialToken = '012abc';
@@ -114,6 +130,7 @@ void main() {
114130
required String expectedTitle,
115131
required String expectedTagComponent,
116132
required bool expectedIsGroupConversation,
133+
List<int>? expectedIconBitmap = kSolidBlueAvatar,
117134
}) {
118135
final expectedTag = '${data.realmUri}|${data.userId}|$expectedTagComponent';
119136
final expectedGroupKey = '${data.realmUri}|${data.userId}';
@@ -135,7 +152,9 @@ void main() {
135152
..text.equals(messageData.content)
136153
..timestampMs.equals(messageData.time * 1000)
137154
..person.which((it) => it.isNotNull()
138-
..iconBitmap.which((it) => isLast ? it.isNotNull() : it.isNull())
155+
..iconBitmap.which((it) => (isLast && expectedIconBitmap != null)
156+
? it.isNotNull().deepEquals(expectedIconBitmap)
157+
: it.isNull())
139158
..key.equals(expectedSenderKey)
140159
..name.equals(messageData.senderFullName));
141160
});
@@ -221,7 +240,7 @@ void main() {
221240
async.flushMicrotasks();
222241
}
223242

224-
test('stream message', () => awaitFakeAsync((async) async {
243+
test('stream message', runWithHttpClient((async) async {
225244
await init();
226245
final stream = eg.stream();
227246
final message = eg.streamMessage(stream: stream);
@@ -231,7 +250,7 @@ void main() {
231250
expectedTagComponent: 'stream:${message.streamId}:${message.topic}');
232251
}));
233252

234-
test('stream message: multiple messages, same topic', () => awaitFakeAsync((async) async {
253+
test('stream message: multiple messages, same topic', runWithHttpClient((async) async {
235254
await init();
236255
final stream = eg.stream();
237256
const topic = 'topic 1';
@@ -267,7 +286,67 @@ void main() {
267286
expectedTagComponent: expectedTagComponent);
268287
}));
269288

270-
test('stream message: stream name omitted', () => awaitFakeAsync((async) async {
289+
test('stream message: multiple messages, different topics', runWithHttpClient((async) async {
290+
await init();
291+
final stream = eg.stream();
292+
const topicA = 'topic A';
293+
const topicB = 'topic B';
294+
final message1 = eg.streamMessage(topic: topicA, stream: stream);
295+
final data1 = messageFcmMessage(message1, streamName: stream.name);
296+
final message2 = eg.streamMessage(topic: topicB, stream: stream);
297+
final data2 = messageFcmMessage(message2, streamName: stream.name);
298+
final message3 = eg.streamMessage(topic: topicA, stream: stream);
299+
final data3 = messageFcmMessage(message3, streamName: stream.name);
300+
301+
await receiveFcmMessage(async, data1);
302+
checkNotification(data1,
303+
messageStyleMessages: [data1],
304+
expectedIsGroupConversation: true,
305+
expectedTitle: '#${stream.name} > $topicA',
306+
expectedTagComponent: 'stream:${stream.streamId}:$topicA');
307+
308+
await receiveFcmMessage(async, data2);
309+
checkNotification(data2,
310+
messageStyleMessages: [data2],
311+
expectedIsGroupConversation: true,
312+
expectedTitle: '#${stream.name} > $topicB',
313+
expectedTagComponent: 'stream:${stream.streamId}:$topicB');
314+
315+
await receiveFcmMessage(async, data3);
316+
checkNotification(data3,
317+
messageStyleMessages: [data1, data3],
318+
expectedIsGroupConversation: true,
319+
expectedTitle: '#${stream.name} > $topicA',
320+
expectedTagComponent: 'stream:${stream.streamId}:$topicA');
321+
}));
322+
323+
test('stream message: conversation stays same when stream is renamed', runWithHttpClient((async) async {
324+
await init();
325+
var stream = eg.stream(streamId: 1, name: 'Before');
326+
const topic = 'topic';
327+
final message1 = eg.streamMessage(topic: topic, stream: stream);
328+
final data1 = messageFcmMessage(message1, streamName: stream.name);
329+
330+
await receiveFcmMessage(async, data1);
331+
checkNotification(data1,
332+
messageStyleMessages: [data1],
333+
expectedIsGroupConversation: true,
334+
expectedTitle: '#Before > $topic',
335+
expectedTagComponent: 'stream:${stream.streamId}:$topic');
336+
337+
stream = eg.stream(streamId: 1, name: 'After');
338+
final message2 = eg.streamMessage(topic: topic, stream: stream);
339+
final data2 = messageFcmMessage(message2, streamName: stream.name);
340+
341+
await receiveFcmMessage(async, data2);
342+
checkNotification(data2,
343+
messageStyleMessages: [data1, data2],
344+
expectedIsGroupConversation: true,
345+
expectedTitle: '#After > $topic',
346+
expectedTagComponent: 'stream:${stream.streamId}:$topic');
347+
}));
348+
349+
test('stream message: stream name omitted', runWithHttpClient((async) async {
271350
await init();
272351
final stream = eg.stream();
273352
final message = eg.streamMessage(stream: stream);
@@ -277,7 +356,7 @@ void main() {
277356
expectedTagComponent: 'stream:${message.streamId}:${message.topic}');
278357
}));
279358

280-
test('group DM: 3 users', () => awaitFakeAsync((async) async {
359+
test('group DM: 3 users', runWithHttpClient((async) async {
281360
await init();
282361
final message = eg.dmMessage(from: eg.thirdUser, to: [eg.otherUser, eg.selfUser]);
283362
await checkNotifications(async, messageFcmMessage(message),
@@ -286,7 +365,7 @@ void main() {
286365
expectedTagComponent: 'dm:${message.allRecipientIds.join(",")}');
287366
}));
288367

289-
test('group DM: more than 3 users', () => awaitFakeAsync((async) async {
368+
test('group DM: more than 3 users', runWithHttpClient((async) async {
290369
await init();
291370
final message = eg.dmMessage(from: eg.thirdUser,
292371
to: [eg.otherUser, eg.selfUser, eg.fourthUser]);
@@ -296,7 +375,31 @@ void main() {
296375
expectedTagComponent: 'dm:${message.allRecipientIds.join(",")}');
297376
}));
298377

299-
test('1:1 DM', () => awaitFakeAsync((async) async {
378+
test('group DM: title updates with latest sender', runWithHttpClient((async) async {
379+
await init();
380+
final message1 = eg.dmMessage(from: eg.otherUser, to: [eg.selfUser, eg.thirdUser]);
381+
final data1 = messageFcmMessage(message1);
382+
final message2 = eg.dmMessage(from: eg.thirdUser, to: [eg.selfUser, eg.otherUser]);
383+
final data2 = messageFcmMessage(message2);
384+
385+
final expectedTagComponent = 'dm:${message1.allRecipientIds.join(",")}';
386+
387+
await receiveFcmMessage(async, data1);
388+
checkNotification(data1,
389+
messageStyleMessages: [data1],
390+
expectedIsGroupConversation: true,
391+
expectedTitle: "${eg.otherUser.fullName} to you and 1 other",
392+
expectedTagComponent: expectedTagComponent);
393+
394+
await receiveFcmMessage(async, data2);
395+
checkNotification(data2,
396+
messageStyleMessages: [data1, data2],
397+
expectedIsGroupConversation: true,
398+
expectedTitle: "${eg.thirdUser.fullName} to you and 1 other",
399+
expectedTagComponent: expectedTagComponent);
400+
}));
401+
402+
test('1:1 DM', runWithHttpClient((async) async {
300403
await init();
301404
final message = eg.dmMessage(from: eg.otherUser, to: [eg.selfUser]);
302405
await checkNotifications(async, messageFcmMessage(message),
@@ -305,7 +408,89 @@ void main() {
305408
expectedTagComponent: 'dm:${message.allRecipientIds.join(",")}');
306409
}));
307410

308-
test('self-DM', () => awaitFakeAsync((async) async {
411+
test('1:1 DM: title updates when sender name changes', runWithHttpClient((async) async {
412+
await init();
413+
final otherUser = eg.user(fullName: 'Before');
414+
final message1 = eg.dmMessage(from: otherUser, to: [eg.selfUser]);
415+
final data1 = messageFcmMessage(message1);
416+
417+
final expectedTagComponent = 'dm:${message1.allRecipientIds.join(",")}';
418+
419+
await receiveFcmMessage(async, data1);
420+
checkNotification(data1,
421+
messageStyleMessages: [data1],
422+
expectedIsGroupConversation: false,
423+
expectedTitle: 'Before',
424+
expectedTagComponent: expectedTagComponent);
425+
426+
otherUser.fullName = 'After';
427+
final message2 = eg.dmMessage(from: otherUser, to: [eg.selfUser]);
428+
final data2 = messageFcmMessage(message2);
429+
430+
await receiveFcmMessage(async, data2);
431+
checkNotification(data2,
432+
messageStyleMessages: [data1, data2],
433+
expectedIsGroupConversation: false,
434+
expectedTitle: 'After',
435+
expectedTagComponent: expectedTagComponent);
436+
}));
437+
438+
test('1:1 DM: conversation stays same when sender email changes', runWithHttpClient((async) async {
439+
await init();
440+
final otherUser = eg.user(email: '[email protected]');
441+
final message1 = eg.dmMessage(from: otherUser, to: [eg.selfUser]);
442+
final data1 = messageFcmMessage(message1);
443+
444+
final expectedTagComponent = 'dm:${message1.allRecipientIds.join(",")}';
445+
446+
await receiveFcmMessage(async, data1);
447+
checkNotification(data1,
448+
messageStyleMessages: [data1],
449+
expectedIsGroupConversation: false,
450+
expectedTitle: otherUser.fullName,
451+
expectedTagComponent: expectedTagComponent);
452+
453+
otherUser.email = '[email protected]';
454+
final message2 = eg.dmMessage(from: otherUser, to: [eg.selfUser]);
455+
final data2 = messageFcmMessage(message2);
456+
457+
await receiveFcmMessage(async, data2);
458+
checkNotification(data2,
459+
messageStyleMessages: [data1, data2],
460+
expectedIsGroupConversation: false,
461+
expectedTitle: otherUser.fullName,
462+
expectedTagComponent: expectedTagComponent);
463+
}));
464+
465+
test('1:1 DM: sender avatar loading fails, remote error', runWithHttpClient((async) async {
466+
await init();
467+
final message = eg.dmMessage(from: eg.otherUser, to: [eg.selfUser]);
468+
final data = messageFcmMessage(message);
469+
await receiveFcmMessage(async, data);
470+
checkNotification(data,
471+
messageStyleMessages: [data],
472+
expectedIsGroupConversation: false,
473+
expectedTitle: eg.otherUser.fullName,
474+
expectedTagComponent: 'dm:${message.allRecipientIds.join(",")}',
475+
expectedIconBitmap: null);
476+
}, httpClientFactory: () => http_testing.MockClient((request) async =>
477+
http.Response.bytes([], HttpStatus.internalServerError))));
478+
479+
test('1:1 DM: sender avatar loading fails, local error', runWithHttpClient((async) async {
480+
await init();
481+
final message = eg.dmMessage(from: eg.otherUser, to: [eg.selfUser]);
482+
final data = messageFcmMessage(message);
483+
await receiveFcmMessage(async, data);
484+
checkNotification(data,
485+
messageStyleMessages: [data],
486+
expectedIsGroupConversation: false,
487+
expectedTitle: eg.otherUser.fullName,
488+
expectedTagComponent: 'dm:${message.allRecipientIds.join(",")}',
489+
expectedIconBitmap: null);
490+
}, httpClientFactory: () => http_testing.MockClient((request) async =>
491+
throw http.ClientException('Network failure'))));
492+
493+
test('self-DM', runWithHttpClient((async) async {
309494
await init();
310495
final message = eg.dmMessage(from: eg.selfUser, to: []);
311496
await checkNotifications(async, messageFcmMessage(message),

0 commit comments

Comments
 (0)