@@ -13,10 +13,21 @@ import {
1313 send ,
1414 start ,
1515 accumulate ,
16+ onceStateChangesTo ,
1617} from "./index" ;
1718
1819test ( "node version " + process . version , ( ) => { } ) ;
1920
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+
2031const fetch = jest . fn ( ) ;
2132beforeEach ( fetch . mockClear ) ;
2233
@@ -449,18 +460,35 @@ describe("Switch", () => {
449460 machine . next ( "FLICK" ) ;
450461 expect ( machine . current ) . toEqual ( "ON" ) ;
451462 expect ( eventListener ) . toHaveBeenCalledTimes ( 1 ) ;
452- expect ( eventListener ) . toHaveBeenLastCalledWith ( expect . objectContaining ( { type : "StateChanged" } ) ) ;
463+ expect ( eventListener ) . toHaveBeenLastCalledWith ( expect . objectContaining ( { type : "StateChanged" , value : "ON" } ) ) ;
453464
454465 machine . next ( "FLICK" ) ;
455466 expect ( machine . current ) . toEqual ( "OFF" ) ;
456467 expect ( eventListener ) . toHaveBeenCalledTimes ( 2 ) ;
468+ expect ( eventListener ) . toHaveBeenLastCalledWith ( expect . objectContaining ( { type : "StateChanged" , value : "OFF" } ) ) ;
457469
458470 machine . signal . removeEventListener ( "StateChanged" , eventListener ) ;
459471
460472 machine . next ( "FLICK" ) ;
461473 expect ( machine . current ) . toEqual ( "ON" ) ;
462474 expect ( eventListener ) . toHaveBeenCalledTimes ( 2 ) ;
463475 } ) ;
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+ } )
464492} ) ;
465493
466494describe ( "Switch with symbol messages" , ( ) => {
@@ -496,6 +524,71 @@ describe("Switch with symbol messages", () => {
496524 } ) ;
497525} ) ;
498526
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+
499592describe ( "Wrapping AbortController as a state machine" , ( ) => {
500593 function AbortSender ( controller : AbortController ) {
501594 function * initial ( ) {
0 commit comments