1
+ import 'dart:io' ;
2
+
1
3
import 'package:checks/checks.dart' ;
4
+ import 'package:firebase_messaging/firebase_messaging.dart' ;
2
5
import 'package:flutter/foundation.dart' ;
3
6
import 'package:flutter_test/flutter_test.dart' ;
4
7
import 'package:http/http.dart' as http;
8
+ import 'package:http/testing.dart' as http_testing;
5
9
import 'package:zulip/model/actions.dart' ;
6
10
import 'package:zulip/model/store.dart' ;
7
11
import 'package:zulip/notifications/receive.dart' ;
@@ -12,7 +16,9 @@ import '../fake_async.dart';
12
16
import '../model/binding.dart' ;
13
17
import '../model/store_checks.dart' ;
14
18
import '../model/test_store.dart' ;
19
+ import '../notifications/display_test.dart' ;
15
20
import '../stdlib_checks.dart' ;
21
+ import '../test_images.dart' ;
16
22
import 'store_test.dart' ;
17
23
18
24
void main () {
@@ -21,12 +27,35 @@ void main() {
21
27
late PerAccountStore store;
22
28
late FakeApiConnection connection;
23
29
30
+ http.Client makeFakeHttpClient ({http.Response ? response, Exception ? exception}) {
31
+ return http_testing.MockClient ((request) async {
32
+ assert ((response != null ) ^ (exception != null ));
33
+ if (exception != null ) throw exception;
34
+ return response! ; // TODO return 404 on non avatar urls
35
+ });
36
+ }
37
+
38
+ final fakeHttpClientGivingSuccess = makeFakeHttpClient (
39
+ response: http.Response .bytes (kSolidBlueAvatar, HttpStatus .ok));
40
+
41
+ T runWithHttpClient <T >(
42
+ T Function () callback, {
43
+ http.Client Function ()? httpClientFactory,
44
+ }) {
45
+ return http.runWithClient (callback, httpClientFactory ?? () => fakeHttpClientGivingSuccess);
46
+ }
47
+
24
48
Future <void > prepare ({String ? ackedPushToken = '123' }) async {
25
49
addTearDown (testBinding.reset);
26
50
final selfAccount = eg.selfAccount.copyWith (ackedPushToken: Value (ackedPushToken));
27
51
await testBinding.globalStore.add (selfAccount, eg.initialSnapshot ());
28
52
store = await testBinding.globalStore.perAccount (selfAccount.id);
29
53
connection = store.connection as FakeApiConnection ;
54
+
55
+ testBinding.firebaseMessagingInitialToken = '123' ;
56
+ addTearDown (NotificationService .debugReset);
57
+ NotificationService .debugBackgroundIsolateIsLive = false ;
58
+ await NotificationService .instance.start ();
30
59
}
31
60
32
61
/// Creates and caches a new [FakeApiConnection] in [TestGlobalStore] .
@@ -71,14 +100,23 @@ void main() {
71
100
}
72
101
73
102
group ('logOutAccount' , () {
74
- test ('smoke' , () => awaitFakeAsync ((async ) async {
103
+ test ('smoke' , () => runWithHttpClient (() => awaitFakeAsync ((async ) async {
75
104
await prepare ();
76
105
check (testBinding.globalStore).accountIds.single.equals (eg.selfAccount.id);
77
106
const unregisterDelay = Duration (seconds: 5 );
78
107
assert (unregisterDelay > TestGlobalStore .removeAccountDuration);
79
108
final newConnection = separateConnection ()
80
109
..prepare (delay: unregisterDelay, json: {'msg' : '' , 'result' : 'success' });
81
110
111
+ // Create a notification to check that it's removed after logout
112
+ final message = eg.dmMessage (from: eg.otherUser, to: [eg.selfUser]);
113
+ testBinding.firebaseMessaging.onMessage.add (
114
+ RemoteMessage (data: messageFcmMessage (message).toJson ()));
115
+ async .flushMicrotasks ();
116
+
117
+ // Check that notifications were created
118
+ check (testBinding.androidNotificationHost.activeNotifications).isNotEmpty ();
119
+
82
120
final future = logOutAccount (testBinding.globalStore, eg.selfAccount.id);
83
121
// Unregister-token request and account removal dispatched together
84
122
checkSingleUnregisterRequest (newConnection);
@@ -94,9 +132,12 @@ void main() {
94
132
95
133
async .elapse (unregisterDelay - TestGlobalStore .removeAccountDuration);
96
134
check (newConnection.isOpen).isFalse ();
97
- }));
98
135
99
- test ('unregister request has an error' , () => awaitFakeAsync ((async ) async {
136
+ // Check that notifications were removed
137
+ check (testBinding.androidNotificationHost.activeNotifications).isEmpty ();
138
+ })));
139
+
140
+ test ('unregister request has an error' , () => runWithHttpClient (() => awaitFakeAsync ((async ) async {
100
141
await prepare ();
101
142
check (testBinding.globalStore).accountIds.single.equals (eg.selfAccount.id);
102
143
const unregisterDelay = Duration (seconds: 5 );
@@ -105,6 +146,15 @@ void main() {
105
146
final newConnection = separateConnection ()
106
147
..prepare (delay: unregisterDelay, apiException: exception);
107
148
149
+ // Create a notification to check that it's removed after logout
150
+ final message = eg.dmMessage (from: eg.otherUser, to: [eg.selfUser]);
151
+ testBinding.firebaseMessaging.onMessage.add (
152
+ RemoteMessage (data: messageFcmMessage (message).toJson ()));
153
+ async .flushMicrotasks ();
154
+
155
+ // Check that notifications were created
156
+ check (testBinding.androidNotificationHost.activeNotifications).isNotEmpty ();
157
+
108
158
final future = logOutAccount (testBinding.globalStore, eg.selfAccount.id);
109
159
// Unregister-token request and account removal dispatched together
110
160
checkSingleUnregisterRequest (newConnection);
@@ -120,7 +170,10 @@ void main() {
120
170
121
171
async .elapse (unregisterDelay - TestGlobalStore .removeAccountDuration);
122
172
check (newConnection.isOpen).isFalse ();
123
- }));
173
+
174
+ // Check that notifications were removed
175
+ check (testBinding.androidNotificationHost.activeNotifications).isEmpty ();
176
+ })));
124
177
});
125
178
126
179
group ('unregisterToken' , () {
0 commit comments