@@ -169,32 +169,40 @@ void main() {
169169 await prepareOutboxMessage (destination: DmDestination (
170170 userIds: [eg.selfUser.userId, eg.otherUser.userId]));
171171 checkState ().equals (OutboxMessageState .hidden);
172+ checkNotNotified ();
172173
173174 async .elapse (kLocalEchoDebounceDuration);
174175 checkState ().equals (OutboxMessageState .waiting);
176+ checkNotNotified (); // TODO once (it appears)
175177
176178 await receiveMessage (eg.dmMessage (from: eg.selfUser, to: [eg.otherUser]));
177179 check (store.outboxMessages).isEmpty ();
180+ checkNotifiedOnce ();
178181 }));
179182
180183 test ('smoke stream message: hidden -> waiting -> (delete)' , () => awaitFakeAsync ((async ) async {
181184 await prepareOutboxMessage (destination: StreamDestination (
182185 stream.streamId, eg.t ('foo' )));
183186 checkState ().equals (OutboxMessageState .hidden);
187+ checkNotNotified ();
184188
185189 async .elapse (kLocalEchoDebounceDuration);
186190 checkState ().equals (OutboxMessageState .waiting);
191+ checkNotNotified (); // TODO once (it appears)
187192
188193 await receiveMessage (eg.streamMessage (stream: stream, topic: 'foo' ));
189194 check (store.outboxMessages).isEmpty ();
195+ checkNotifiedOnce ();
190196 }));
191197
192198 test ('hidden -> waiting and never transition to waitPeriodExpired' , () => awaitFakeAsync ((async ) async {
193199 await prepareOutboxMessage ();
194200 checkState ().equals (OutboxMessageState .hidden);
201+ checkNotNotified ();
195202
196203 async .elapse (kLocalEchoDebounceDuration);
197204 checkState ().equals (OutboxMessageState .waiting);
205+ checkNotNotified (); // TODO once (it appears)
198206
199207 // Wait till we reach at least [kSendMessageOfferRestoreWaitPeriod] after
200208 // the send request was initiated.
@@ -204,16 +212,19 @@ void main() {
204212 // The outbox message should stay in the waiting state;
205213 // it should not transition to waitPeriodExpired.
206214 checkState ().equals (OutboxMessageState .waiting);
215+ checkNotNotified ();
207216 }));
208217
209218 test ('waiting -> waitPeriodExpired' , () => awaitFakeAsync ((async ) async {
210219 await prepareOutboxMessageToFailAfterDelay (
211220 kSendMessageOfferRestoreWaitPeriod + Duration (seconds: 1 ));
212221 async .elapse (kLocalEchoDebounceDuration);
213222 checkState ().equals (OutboxMessageState .waiting);
223+ checkNotNotified (); // TODO once (it appears)
214224
215225 async .elapse (kSendMessageOfferRestoreWaitPeriod - kLocalEchoDebounceDuration);
216226 checkState ().equals (OutboxMessageState .waitPeriodExpired);
227+ checkNotNotified (); // TODO once (it offers restore)
217228
218229 await check (outboxMessageFailFuture).throws ();
219230 }));
@@ -231,10 +242,12 @@ void main() {
231242 destination: streamDestination, content: 'content' );
232243 async .elapse (kSendMessageOfferRestoreWaitPeriod);
233244 checkState ().equals (OutboxMessageState .waitPeriodExpired);
245+ checkNotNotified (); // TODO twice (it appears; it offers restore)
234246
235247 // Wait till the [sendMessage] request succeeds.
236248 await future;
237249 checkState ().equals (OutboxMessageState .waiting);
250+ checkNotNotified (); // TODO once (it un-offers restore)
238251
239252 // Wait till we reach at least [kSendMessageOfferRestoreWaitPeriod] after
240253 // returning to the waiting state.
@@ -243,15 +256,18 @@ void main() {
243256 // The outbox message should stay in the waiting state;
244257 // it should not transition to waitPeriodExpired.
245258 checkState ().equals (OutboxMessageState .waiting);
259+ checkNotNotified ();
246260 }));
247261
248262 group ('… -> failed' , () {
249263 test ('hidden -> failed' , () => awaitFakeAsync ((async ) async {
250264 await prepareOutboxMessageToFailAfterDelay (Duration .zero);
251265 checkState ().equals (OutboxMessageState .hidden);
266+ checkNotNotified ();
252267
253268 await check (outboxMessageFailFuture).throws ();
254269 checkState ().equals (OutboxMessageState .failed);
270+ checkNotNotified (); // TODO once (it appears, offering restore)
255271
256272 // Wait till we reach at least [kSendMessageOfferRestoreWaitPeriod] after
257273 // the send request was initiated.
@@ -260,62 +276,74 @@ void main() {
260276 // The outbox message should stay in the failed state;
261277 // it should not transition to waitPeriodExpired.
262278 checkState ().equals (OutboxMessageState .failed);
279+ checkNotNotified ();
263280 }));
264281
265282 test ('waiting -> failed' , () => awaitFakeAsync ((async ) async {
266283 await prepareOutboxMessageToFailAfterDelay (
267284 kLocalEchoDebounceDuration + Duration (seconds: 1 ));
268285 async .elapse (kLocalEchoDebounceDuration);
269286 checkState ().equals (OutboxMessageState .waiting);
287+ checkNotNotified (); // TODO once (it appears)
270288
271289 await check (outboxMessageFailFuture).throws ();
272290 checkState ().equals (OutboxMessageState .failed);
291+ checkNotNotified (); // TODO once (it offers restore)
273292 }));
274293
275294 test ('waitPeriodExpired -> failed' , () => awaitFakeAsync ((async ) async {
276295 await prepareOutboxMessageToFailAfterDelay (
277296 kSendMessageOfferRestoreWaitPeriod + Duration (seconds: 1 ));
278297 async .elapse (kSendMessageOfferRestoreWaitPeriod);
279298 checkState ().equals (OutboxMessageState .waitPeriodExpired);
299+ checkNotNotified (); // TODO twice (it appears; it offers restore)
280300
281301 await check (outboxMessageFailFuture).throws ();
282302 checkState ().equals (OutboxMessageState .failed);
303+ checkNotNotified (); // TODO once (it shows failure text)
283304 }));
284305 });
285306
286307 group ('… -> (delete)' , () {
287308 test ('hidden -> (delete) because event received' , () => awaitFakeAsync ((async ) async {
288309 await prepareOutboxMessage ();
289310 checkState ().equals (OutboxMessageState .hidden);
311+ checkNotNotified ();
290312
291313 await receiveMessage ();
292314 check (store.outboxMessages).isEmpty ();
315+ checkNotifiedOnce ();
293316 }));
294317
295318 test ('hidden -> (delete) when event arrives before send request fails' , () => awaitFakeAsync ((async ) async {
296319 // Set up an error to fail `sendMessage` with a delay, leaving time for
297320 // the message event to arrive.
298321 await prepareOutboxMessageToFailAfterDelay (const Duration (seconds: 1 ));
299322 checkState ().equals (OutboxMessageState .hidden);
323+ checkNotNotified ();
300324
301325 // Received the message event while the message is being sent.
302326 await receiveMessage ();
303327 check (store.outboxMessages).isEmpty ();
328+ checkNotifiedOnce ();
304329
305330 // Complete the send request. There should be no error despite
306331 // the send request failure, because the outbox message is not
307332 // in the store any more.
308333 await check (outboxMessageFailFuture).completes ();
309334 async .elapse (const Duration (seconds: 1 ));
335+ checkNotNotified ();
310336 }));
311337
312338 test ('waiting -> (delete) because event received' , () => awaitFakeAsync ((async ) async {
313339 await prepareOutboxMessage ();
314340 async .elapse (kLocalEchoDebounceDuration);
315341 checkState ().equals (OutboxMessageState .waiting);
342+ checkNotNotified (); // TODO once (it appears)
316343
317344 await receiveMessage ();
318345 check (store.outboxMessages).isEmpty ();
346+ checkNotifiedOnce ();
319347 }));
320348
321349 test ('waiting -> (delete) when event arrives before send request fails' , () => awaitFakeAsync ((async ) async {
@@ -325,15 +353,18 @@ void main() {
325353 kLocalEchoDebounceDuration + Duration (seconds: 1 ));
326354 async .elapse (kLocalEchoDebounceDuration);
327355 checkState ().equals (OutboxMessageState .waiting);
356+ checkNotNotified (); // TODO once (it appears)
328357
329358 // Received the message event while the message is being sent.
330359 await receiveMessage ();
331360 check (store.outboxMessages).isEmpty ();
361+ checkNotifiedOnce ();
332362
333363 // Complete the send request. There should be no error despite
334364 // the send request failure, because the outbox message is not
335365 // in the store any more.
336366 await check (outboxMessageFailFuture).completes ();
367+ checkNotNotified ();
337368 }));
338369
339370 test ('waitPeriodExpired -> (delete) when event arrives before send request fails' , () => awaitFakeAsync ((async ) async {
@@ -343,15 +374,18 @@ void main() {
343374 kSendMessageOfferRestoreWaitPeriod + Duration (seconds: 1 ));
344375 async .elapse (kSendMessageOfferRestoreWaitPeriod);
345376 checkState ().equals (OutboxMessageState .waitPeriodExpired);
377+ checkNotNotified (); // TODO twice (it appears; it offers restore)
346378
347379 // Received the message event while the message is being sent.
348380 await receiveMessage ();
349381 check (store.outboxMessages).isEmpty ();
382+ checkNotifiedOnce ();
350383
351384 // Complete the send request. There should be no error despite
352385 // the send request failure, because the outbox message is not
353386 // in the store any more.
354387 await check (outboxMessageFailFuture).completes ();
388+ checkNotNotified ();
355389 }));
356390
357391 test ('waitPeriodExpired -> (delete) because outbox message was taken' , () => awaitFakeAsync ((async ) async {
@@ -361,27 +395,33 @@ void main() {
361395 kSendMessageOfferRestoreWaitPeriod + Duration (seconds: 1 ));
362396 async .elapse (kSendMessageOfferRestoreWaitPeriod);
363397 checkState ().equals (OutboxMessageState .waitPeriodExpired);
398+ checkNotNotified (); // TODO twice (it appears; it offers restore)
364399
365400 store.takeOutboxMessage (store.outboxMessages.keys.single);
366401 check (store.outboxMessages).isEmpty ();
402+ checkNotNotified (); // TODO once (it disappears)
367403 }));
368404
369405 test ('failed -> (delete) because event received' , () => awaitFakeAsync ((async ) async {
370406 await prepareOutboxMessageToFailAfterDelay (Duration .zero);
371407 await check (outboxMessageFailFuture).throws ();
372408 checkState ().equals (OutboxMessageState .failed);
409+ checkNotNotified (); // TODO once (it appears, offering restore)
373410
374411 await receiveMessage ();
375412 check (store.outboxMessages).isEmpty ();
413+ checkNotifiedOnce ();
376414 }));
377415
378416 test ('failed -> (delete) because outbox message was taken' , () => awaitFakeAsync ((async ) async {
379417 await prepareOutboxMessageToFailAfterDelay (Duration .zero);
380418 await check (outboxMessageFailFuture).throws ();
381419 checkState ().equals (OutboxMessageState .failed);
420+ checkNotNotified (); // TODO once (it appears, offering restore)
382421
383422 store.takeOutboxMessage (store.outboxMessages.keys.single);
384423 check (store.outboxMessages).isEmpty ();
424+ checkNotNotified (); // TODO once (it disappears)
385425 }));
386426 });
387427
@@ -423,11 +463,13 @@ void main() {
423463 await check (store.sendMessage (
424464 destination: StreamDestination (stream.streamId, eg.t ('topic' )),
425465 content: 'content' )).throws ();
466+ checkNotNotified (); // TODO once (it appears, offering restore)
426467 }
427468
428469 final localMessageIds = store.outboxMessages.keys.toList ();
429470 store.takeOutboxMessage (localMessageIds.removeAt (5 ));
430471 check (store.outboxMessages).keys.deepEquals (localMessageIds);
472+ checkNotNotified (); // TODO once (it disappears)
431473 });
432474
433475 group ('reconcileMessages' , () {
0 commit comments