1+ import 'dart:async' ;
12import 'dart:io' ;
23import 'dart:math' ;
34import 'dart:typed_data' ;
@@ -32,6 +33,10 @@ void main() {
3233 env2.closeAndDelete ();
3334 });
3435
36+ waitUntilLoggedIn (SyncClient client) {
37+ expect (waitUntil (() => client.state () == SyncState .loggedIn), isTrue);
38+ }
39+
3540 // lambda to easily create clients in the test below
3641 SyncClient createClient (Store s) =>
3742 Sync .client (s, 'ws://127.0.0.1:$serverPort ' , SyncCredentials .none ());
@@ -40,7 +45,7 @@ void main() {
4045 SyncClient loggedInClient (Store s) {
4146 final client = createClient (s);
4247 client.start ();
43- expect ( waitUntil (() => client. state () == SyncState .loggedIn), isTrue );
48+ waitUntilLoggedIn ( client);
4449 return client;
4550 }
4651
@@ -215,7 +220,7 @@ void main() {
215220 await server.online ();
216221 client.start ();
217222
218- expect ( waitUntil (() => client. state () == SyncState .loggedIn), isTrue );
223+ waitUntilLoggedIn ( client);
219224 await yieldExecution ();
220225 expect (events, equals ([SyncConnectionEvent .connected]));
221226 expect (events2, equals ([SyncConnectionEvent .connected]));
@@ -237,7 +242,7 @@ void main() {
237242 await server.start (keepDb: true );
238243 await server.online ();
239244
240- expect ( waitUntil (() => client. state () == SyncState .loggedIn), isTrue );
245+ waitUntilLoggedIn ( client);
241246 await yieldExecution ();
242247
243248 expect (
@@ -270,7 +275,7 @@ void main() {
270275
271276 client.setCredentials (SyncCredentials .none ());
272277
273- expect ( waitUntil (() => client. state () == SyncState .loggedIn), isTrue );
278+ waitUntilLoggedIn ( client);
274279 await yieldExecution ();
275280 expect (
276281 events,
@@ -283,21 +288,51 @@ void main() {
283288 test ('SyncClient listeners: completion' , () async {
284289 await server.online ();
285290 final client = loggedInClient (store);
291+ addTearDown (() {
292+ client.close ();
293+ });
286294 final box = env.store.box <TestEntitySynced >();
287295 final box2 = env2.store.box <TestEntitySynced >();
288296 expect (box.isEmpty (), isTrue);
289- int id = box.put (TestEntitySynced (value: 100 ));
297+ // Do multiple changes to verify only a single completion event is sent
298+ // after all changes are received.
299+ box.put (TestEntitySynced (value: 1 ));
300+ box.put (TestEntitySynced (value: 100 ));
290301
291302 // Note: wait for the client to finish sending to the server.
292303 // There's currently no other way to recognize this.
293304 sleep (const Duration (milliseconds: 100 ));
294- client.close ();
295305
296- final client2 = loggedInClient (env2.store);
297- await client2.completionEvents.first.timeout (defaultTimeout);
298- client2.close ();
306+ final client2 = createClient (env2.store);
307+ addTearDown (() {
308+ client2.close ();
309+ });
310+ final Completer firstEvent = Completer ();
311+ var receivedEvents = 0 ;
312+ final subscription = client2.completionEvents.listen ((event) {
313+ if (! firstEvent.isCompleted) {
314+ firstEvent.complete ();
315+ }
316+ receivedEvents++ ;
317+ });
299318
300- expect (box2.get (id)! .value, 100 );
319+ client2.start ();
320+ waitUntilLoggedIn (client2);
321+
322+ // Yield and wait for the first event...
323+ await firstEvent.future.timeout (defaultTimeout);
324+ // ...and some more on any additional events (should be none)
325+ await Future .delayed (Duration (milliseconds: 200 ));
326+ expect (receivedEvents, 1 );
327+ // Note: the ID just happens to be the same as the box was unused
328+ expect (box2.get (2 )! .value, 100 );
329+
330+ // Do another change
331+ box.put (TestEntitySynced (value: 200 ));
332+ // Yield and wait for event(s) to come in
333+ await Future .delayed (Duration (milliseconds: 200 ));
334+ await subscription.cancel ();
335+ expect (receivedEvents, 2 );
301336 });
302337
303338 test ('SyncClient listeners: changes' , () async {
@@ -415,9 +450,13 @@ class SyncServer {
415450 await httpClient.get ('127.0.0.1' , _port! , '' );
416451 break ;
417452 } on SocketException catch (e) {
418- // only retry if "connection refused"
419- if (e.osError! .errorCode != 111 ) rethrow ;
420- await Future <void >.delayed (const Duration (milliseconds: 1 ));
453+ // Only retry if "Connection refused" (not using error codes as they
454+ // differ by platform).
455+ if (e.osError! .message.contains ('Connection refused' )) {
456+ await Future <void >.delayed (const Duration (milliseconds: 1 ));
457+ } else {
458+ rethrow ;
459+ }
421460 }
422461 }
423462 httpClient.close (force: true );
0 commit comments