@@ -9,6 +9,7 @@ export const resolveTo = resolveIn(0)
99export const rejectIn = ms => err =>
1010 new Promise ( ( resolve , reject ) => setTimeout ( reject , ms , new Error ( err ) ) )
1111export const rejectTo = rejectIn ( 0 )
12+ export const sleep = ms => resolveIn ( ms ) ( )
1213
1314export const common = Async => ( ) => {
1415 test ( "passes `data`, `error`, metadata and methods as render props" , async ( ) => {
@@ -99,22 +100,22 @@ export const withPromise = Async => () => {
99100 test ( "invokes `onResolve` callback when the promise resolves" , async ( ) => {
100101 const onResolve = jest . fn ( )
101102 render ( < Async promise = { resolveTo ( "ok" ) } onResolve = { onResolve } /> )
102- await resolveTo ( )
103+ await sleep ( 10 )
103104 expect ( onResolve ) . toHaveBeenCalledWith ( "ok" )
104105 } )
105106
106107 test ( "invokes `onReject` callback when the promise rejects" , async ( ) => {
107108 const onReject = jest . fn ( )
108109 render ( < Async promise = { rejectTo ( "err" ) } onReject = { onReject } /> )
109- await resolveTo ( )
110+ await sleep ( 10 )
110111 expect ( onReject ) . toHaveBeenCalledWith ( new Error ( "err" ) )
111112 } )
112113
113114 test ( "cancels a pending promise when unmounted" , async ( ) => {
114115 const onResolve = jest . fn ( )
115116 const { unmount } = render ( < Async promise = { resolveTo ( "ok" ) } onResolve = { onResolve } /> )
116117 unmount ( )
117- await resolveTo ( )
118+ await sleep ( 10 )
118119 expect ( onResolve ) . not . toHaveBeenCalled ( )
119120 } )
120121
@@ -124,7 +125,7 @@ export const withPromise = Async => () => {
124125 const onResolve = jest . fn ( )
125126 const { rerender } = render ( < Async promise = { promise1 } onResolve = { onResolve } /> )
126127 rerender ( < Async promise = { promise2 } onResolve = { onResolve } /> )
127- await resolveTo ( )
128+ await sleep ( 10 )
128129 expect ( onResolve ) . not . toHaveBeenCalledWith ( "one" )
129130 expect ( onResolve ) . toHaveBeenCalledWith ( "two" )
130131 } )
@@ -133,7 +134,7 @@ export const withPromise = Async => () => {
133134 const onResolve = jest . fn ( )
134135 const { rerender } = render ( < Async promise = { resolveTo ( ) } onResolve = { onResolve } /> )
135136 rerender ( < Async onResolve = { onResolve } /> )
136- await resolveTo ( )
137+ await sleep ( 10 )
137138 expect ( onResolve ) . not . toHaveBeenCalled ( )
138139 } )
139140
@@ -191,14 +192,14 @@ export const withPromiseFn = (Async, abortCtrl) => () => {
191192 test ( "invokes `onResolve` callback when the promise resolves" , async ( ) => {
192193 const onResolve = jest . fn ( )
193194 render ( < Async promiseFn = { ( ) => resolveTo ( "ok" ) } onResolve = { onResolve } /> )
194- await resolveTo ( )
195+ await sleep ( 10 )
195196 expect ( onResolve ) . toHaveBeenCalledWith ( "ok" )
196197 } )
197198
198199 test ( "invokes `onReject` callback when the promise rejects" , async ( ) => {
199200 const onReject = jest . fn ( )
200201 render ( < Async promiseFn = { ( ) => rejectTo ( "err" ) } onReject = { onReject } /> )
201- await resolveTo ( )
202+ await sleep ( 10 )
202203 expect ( onReject ) . toHaveBeenCalledWith ( new Error ( "err" ) )
203204 } )
204205
@@ -280,7 +281,7 @@ export const withPromiseFn = (Async, abortCtrl) => () => {
280281 const onResolve = jest . fn ( )
281282 const { unmount } = render ( < Async promiseFn = { ( ) => resolveTo ( "ok" ) } onResolve = { onResolve } /> )
282283 unmount ( )
283- await resolveTo ( )
284+ await sleep ( 10 )
284285 expect ( onResolve ) . not . toHaveBeenCalled ( )
285286 expect ( abortCtrl . abort ) . toHaveBeenCalledTimes ( 1 )
286287 } )
@@ -291,7 +292,7 @@ export const withPromiseFn = (Async, abortCtrl) => () => {
291292 const onResolve = jest . fn ( )
292293 const { rerender } = render ( < Async promiseFn = { promiseFn1 } onResolve = { onResolve } /> )
293294 rerender ( < Async promiseFn = { promiseFn2 } onResolve = { onResolve } /> )
294- await resolveTo ( )
295+ await sleep ( 10 )
295296 expect ( onResolve ) . not . toHaveBeenCalledWith ( "one" )
296297 expect ( onResolve ) . toHaveBeenCalledWith ( "two" )
297298 expect ( abortCtrl . abort ) . toHaveBeenCalledTimes ( 1 )
@@ -301,15 +302,15 @@ export const withPromiseFn = (Async, abortCtrl) => () => {
301302 const onResolve = jest . fn ( )
302303 const { rerender } = render ( < Async promiseFn = { ( ) => resolveTo ( ) } onResolve = { onResolve } /> )
303304 rerender ( < Async onResolve = { onResolve } /> )
304- await resolveTo ( )
305+ await sleep ( 10 )
305306 expect ( onResolve ) . not . toHaveBeenCalled ( )
306307 expect ( abortCtrl . abort ) . toHaveBeenCalledTimes ( 1 )
307308 } )
308309
309310 test ( "does not run `promiseFn` on mount when `initialValue` is provided" , async ( ) => {
310311 const promiseFn = jest . fn ( ) . mockReturnValue ( resolveTo ( ) )
311312 render ( < Async promiseFn = { promiseFn } initialValue = { { } } /> )
312- await resolveTo ( )
313+ await sleep ( 10 )
313314 expect ( promiseFn ) . not . toHaveBeenCalled ( )
314315 } )
315316
@@ -415,3 +416,81 @@ export const withDeferFn = (Async, abortCtrl) => () => {
415416 await waitForElement ( ( ) => getByText ( "done" ) )
416417 } )
417418}
419+
420+ export const withReducer = Async => ( ) => {
421+ test ( "receives state, action and the original reducer" , async ( ) => {
422+ const promise = resolveTo ( "done" )
423+ const reducer = jest . fn ( ( state , action , asyncReducer ) => asyncReducer ( state , action ) )
424+ const { getByText } = render (
425+ < Async promise = { promise } reducer = { reducer } >
426+ { ( { data } ) => data || null }
427+ </ Async >
428+ )
429+ await waitForElement ( ( ) => getByText ( "done" ) )
430+ expect ( reducer ) . toHaveBeenCalledWith (
431+ expect . objectContaining ( { status : expect . any ( String ) } ) ,
432+ expect . objectContaining ( { type : expect . any ( String ) } ) ,
433+ expect . any ( Function )
434+ )
435+ } )
436+
437+ test ( "allows overriding state updates" , async ( ) => {
438+ const promise = resolveTo ( "done" )
439+ const reducer = ( state , action , asyncReducer ) => {
440+ if ( action . type === "fulfill" ) action . payload = "cool"
441+ return asyncReducer ( state , action )
442+ }
443+ const { getByText } = render (
444+ < Async promise = { promise } reducer = { reducer } >
445+ { ( { data } ) => data || null }
446+ </ Async >
447+ )
448+ await waitForElement ( ( ) => getByText ( "cool" ) )
449+ } )
450+ }
451+
452+ export const withDispatcher = Async => ( ) => {
453+ test ( "receives action, the original dispatch method and options" , async ( ) => {
454+ const promise = resolveTo ( "done" )
455+ const dispatcher = jest . fn ( ( action , dispatch ) => dispatch ( action ) )
456+ const props = { promise, dispatcher }
457+ const { getByText } = render ( < Async { ...props } > { ( { data } ) => data || null } </ Async > )
458+ await waitForElement ( ( ) => getByText ( "done" ) )
459+ expect ( dispatcher ) . toHaveBeenCalledWith (
460+ expect . objectContaining ( { type : expect . any ( String ) } ) ,
461+ expect . any ( Function ) ,
462+ expect . objectContaining ( props )
463+ )
464+ } )
465+
466+ test ( "allows overriding actions before dispatch" , async ( ) => {
467+ const promise = resolveTo ( "done" )
468+ const dispatcher = ( action , dispatch ) => {
469+ if ( action . type === "fulfill" ) action . payload = "cool"
470+ dispatch ( action )
471+ }
472+ const { getByText } = render (
473+ < Async promise = { promise } dispatcher = { dispatcher } >
474+ { ( { data } ) => data || null }
475+ </ Async >
476+ )
477+ await waitForElement ( ( ) => getByText ( "cool" ) )
478+ } )
479+
480+ test ( "allows dispatching additional actions" , async ( ) => {
481+ const promise = resolveTo ( "done" )
482+ const customAction = { type : "custom" }
483+ const dispatcher = ( action , dispatch ) => {
484+ dispatch ( action )
485+ dispatch ( customAction )
486+ }
487+ const reducer = jest . fn ( ( state , action , asyncReducer ) => asyncReducer ( state , action ) )
488+ const { getByText } = render (
489+ < Async promise = { promise } dispatcher = { dispatcher } reducer = { reducer } >
490+ { ( { data } ) => data || null }
491+ </ Async >
492+ )
493+ await waitForElement ( ( ) => getByText ( "done" ) )
494+ expect ( reducer ) . toHaveBeenCalledWith ( expect . anything ( ) , customAction , expect . anything ( ) )
495+ } )
496+ }
0 commit comments