Skip to content

Commit 215b889

Browse files
notif test: Add more tests for messaging style notif
Add more tests for Android messaging style notif implementation, listed here: #718 (review)
1 parent ce65dd6 commit 215b889

File tree

1 file changed

+192
-8
lines changed

1 file changed

+192
-8
lines changed

test/notifications/display_test.dart

Lines changed: 192 additions & 8 deletions
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,8 @@ 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) : it.isNull())
139157
..key.equals(expectedSenderKey)
140158
..name.equals(messageData.senderFullName));
141159
});
@@ -221,7 +239,7 @@ void main() {
221239
async.flushMicrotasks();
222240
}
223241

224-
test('stream message', () => awaitFakeAsync((async) async {
242+
test('stream message', runWithHttpClient((async) async {
225243
await init();
226244
final stream = eg.stream();
227245
final message = eg.streamMessage(stream: stream);
@@ -231,7 +249,7 @@ void main() {
231249
expectedTagComponent: 'stream:${message.streamId}:${message.topic}');
232250
}));
233251

234-
test('stream message: multiple messages, same topic', () => awaitFakeAsync((async) async {
252+
test('stream message: multiple messages, same topic', runWithHttpClient((async) async {
235253
await init();
236254
final stream = eg.stream();
237255
const topic = 'topic 1';
@@ -267,7 +285,67 @@ void main() {
267285
expectedTagComponent: expectedTagComponent);
268286
}));
269287

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

280-
test('group DM: 3 users', () => awaitFakeAsync((async) async {
358+
test('group DM: 3 users', runWithHttpClient((async) async {
281359
await init();
282360
final message = eg.dmMessage(from: eg.thirdUser, to: [eg.otherUser, eg.selfUser]);
283361
await checkNotifications(async, messageFcmMessage(message),
@@ -286,7 +364,7 @@ void main() {
286364
expectedTagComponent: 'dm:${message.allRecipientIds.join(",")}');
287365
}));
288366

289-
test('group DM: more than 3 users', () => awaitFakeAsync((async) async {
367+
test('group DM: more than 3 users', runWithHttpClient((async) async {
290368
await init();
291369
final message = eg.dmMessage(from: eg.thirdUser,
292370
to: [eg.otherUser, eg.selfUser, eg.fourthUser]);
@@ -296,7 +374,31 @@ void main() {
296374
expectedTagComponent: 'dm:${message.allRecipientIds.join(",")}');
297375
}));
298376

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

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

0 commit comments

Comments
 (0)