@@ -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