@@ -13,10 +13,21 @@ import {
13
13
send ,
14
14
start ,
15
15
accumulate ,
16
+ onceStateChangesTo ,
16
17
} from "./index" ;
17
18
18
19
test ( "node version " + process . version , ( ) => { } ) ;
19
20
21
+ function useEach ( work : ( ) => ( ) => void ) {
22
+ let cleanup : null | ( ( ) => void ) = null ;
23
+ beforeEach ( ( ) => {
24
+ cleanup = work ( ) ;
25
+ } )
26
+ afterEach ( ( ) => {
27
+ cleanup ?. call ( null ) ;
28
+ } ) ;
29
+ }
30
+
20
31
const fetch = jest . fn ( ) ;
21
32
beforeEach ( fetch . mockClear ) ;
22
33
@@ -449,18 +460,35 @@ describe("Switch", () => {
449
460
machine . next ( "FLICK" ) ;
450
461
expect ( machine . current ) . toEqual ( "ON" ) ;
451
462
expect ( eventListener ) . toHaveBeenCalledTimes ( 1 ) ;
452
- expect ( eventListener ) . toHaveBeenLastCalledWith ( expect . objectContaining ( { type : "StateChanged" } ) ) ;
463
+ expect ( eventListener ) . toHaveBeenLastCalledWith ( expect . objectContaining ( { type : "StateChanged" , value : "ON" } ) ) ;
453
464
454
465
machine . next ( "FLICK" ) ;
455
466
expect ( machine . current ) . toEqual ( "OFF" ) ;
456
467
expect ( eventListener ) . toHaveBeenCalledTimes ( 2 ) ;
468
+ expect ( eventListener ) . toHaveBeenLastCalledWith ( expect . objectContaining ( { type : "StateChanged" , value : "OFF" } ) ) ;
457
469
458
470
machine . signal . removeEventListener ( "StateChanged" , eventListener ) ;
459
471
460
472
machine . next ( "FLICK" ) ;
461
473
expect ( machine . current ) . toEqual ( "ON" ) ;
462
474
expect ( eventListener ) . toHaveBeenCalledTimes ( 2 ) ;
463
475
} ) ;
476
+
477
+ it ( "can produce a promise that resolves when state changes to ON" , async ( ) => {
478
+ const machine = start ( Switch ) ;
479
+
480
+ const whenPromiseResolves = jest . fn ( ) ;
481
+ const aborter = new AbortController ( ) ;
482
+ const onPromise = onceStateChangesTo ( machine , "ON" , aborter . signal )
483
+ onPromise . then ( whenPromiseResolves )
484
+
485
+ await null ;
486
+ expect ( whenPromiseResolves ) . toHaveBeenCalledTimes ( 0 ) ;
487
+
488
+ machine . next ( "FLICK" ) ;
489
+ await null ;
490
+ expect ( whenPromiseResolves ) . toHaveBeenCalledTimes ( 1 ) ;
491
+ } )
464
492
} ) ;
465
493
466
494
describe ( "Switch with symbol messages" , ( ) => {
@@ -496,6 +524,71 @@ describe("Switch with symbol messages", () => {
496
524
} ) ;
497
525
} ) ;
498
526
527
+ describe ( "Wrapping navigator online as a state machine" , ( ) => {
528
+ function * OfflineStatus ( ) {
529
+ yield listenTo ( window , "online" ) ;
530
+ yield listenTo ( window , "offline" ) ;
531
+ yield on ( "online" , compound ( Online ) ) ;
532
+ yield on ( "offline" , compound ( Offline ) ) ;
533
+
534
+ function * Online ( ) { }
535
+ function * Offline ( ) { }
536
+
537
+ return function * Pending ( ) {
538
+ yield cond ( navigator . onLine , Online ) ;
539
+ yield always ( Offline ) ;
540
+ }
541
+ }
542
+
543
+ describe ( "when online" , ( ) => {
544
+ useEach ( ( ) => {
545
+ const spy = jest . spyOn ( navigator , 'onLine' , 'get' ) . mockReturnValue ( true ) ;
546
+ return ( ) => spy . mockRestore ( ) ;
547
+ } ) ;
548
+
549
+ it ( "is immediately in Online state" , ( ) => {
550
+ const machine = start ( OfflineStatus ) ;
551
+ expect ( machine . current ) . toEqual ( "Online" ) ;
552
+ expect ( machine . changeCount ) . toEqual ( 0 ) ;
553
+ } ) ;
554
+
555
+ it ( "reacts to offline & online events" , ( ) => {
556
+ const machine = start ( OfflineStatus ) ;
557
+ window . dispatchEvent ( new Event ( 'offline' ) )
558
+ expect ( machine . current ) . toEqual ( "Offline" ) ;
559
+ expect ( machine . changeCount ) . toEqual ( 1 ) ;
560
+
561
+ window . dispatchEvent ( new Event ( 'online' ) )
562
+ expect ( machine . current ) . toEqual ( "Online" ) ;
563
+ expect ( machine . changeCount ) . toEqual ( 2 ) ;
564
+ } ) ;
565
+ } ) ;
566
+
567
+ describe ( "when offline" , ( ) => {
568
+ useEach ( ( ) => {
569
+ const spy = jest . spyOn ( navigator , 'onLine' , 'get' ) . mockReturnValue ( false ) ;
570
+ return ( ) => spy . mockRestore ( ) ;
571
+ } ) ;
572
+
573
+ it ( "is immediately in Offline state" , ( ) => {
574
+ const machine = start ( OfflineStatus ) ;
575
+ expect ( machine . current ) . toEqual ( "Offline" ) ;
576
+ expect ( machine . changeCount ) . toEqual ( 0 ) ;
577
+ } ) ;
578
+
579
+ it ( "reacts to online & offline events" , ( ) => {
580
+ const machine = start ( OfflineStatus ) ;
581
+ window . dispatchEvent ( new Event ( 'online' ) )
582
+ expect ( machine . current ) . toEqual ( "Online" ) ;
583
+ expect ( machine . changeCount ) . toEqual ( 1 ) ;
584
+
585
+ window . dispatchEvent ( new Event ( 'offline' ) )
586
+ expect ( machine . current ) . toEqual ( "Offline" ) ;
587
+ expect ( machine . changeCount ) . toEqual ( 2 ) ;
588
+ } ) ;
589
+ } ) ;
590
+ } ) ;
591
+
499
592
describe ( "Wrapping AbortController as a state machine" , ( ) => {
500
593
function AbortSender ( controller : AbortController ) {
501
594
function * initial ( ) {
0 commit comments