@@ -6,9 +6,15 @@ import { CoreAdminContext } from '../../core';
66
77import { testDataProvider } from '../../dataProvider' ;
88import { useStore } from '../../store/useStore' ;
9- import { useListParams , getQuery , getNumberOrDefault } from './useListParams' ;
9+ import {
10+ useListParams ,
11+ getQuery ,
12+ getNumberOrDefault ,
13+ ListParamsOptions ,
14+ } from './useListParams' ;
1015import { SORT_DESC , SORT_ASC } from './queryReducer' ;
1116import { TestMemoryRouter } from '../../routing' ;
17+ import { memoryStore } from '../../store' ;
1218
1319describe ( 'useListParams' , ( ) => {
1420 describe ( 'getQuery' , ( ) => {
@@ -360,11 +366,16 @@ describe('useListParams', () => {
360366 } ) ;
361367 } ) ;
362368 describe ( 'useListParams' , ( ) => {
363- const Component = ( { disableSyncWithLocation = false } ) => {
364- const [ { page } , { setPage } ] = useListParams ( {
365- resource : 'posts' ,
366- disableSyncWithLocation,
367- } ) ;
369+ const Component = ( {
370+ disableSyncWithLocation = false ,
371+ ...options
372+ } : Partial < ListParamsOptions > ) => {
373+ const [ { page, perPage, sort, order, filter } , { setPage } ] =
374+ useListParams ( {
375+ resource : 'posts' ,
376+ disableSyncWithLocation,
377+ ...options ,
378+ } ) ;
368379
369380 const handleClick = ( ) => {
370381 setPage ( 10 ) ;
@@ -373,6 +384,10 @@ describe('useListParams', () => {
373384 return (
374385 < >
375386 < p > page: { page } </ p >
387+ < p > perPage: { perPage } </ p >
388+ < p > sort: { sort } </ p >
389+ < p > order: { order } </ p >
390+ < p > filter: { JSON . stringify ( filter ) } </ p >
376391 < button onClick = { handleClick } > update</ button >
377392 </ >
378393 ) ;
@@ -495,6 +510,71 @@ describe('useListParams', () => {
495510 } ) ;
496511 } ) ;
497512
513+ it ( 'should synchronize location with store when sync is enabled' , async ( ) => {
514+ let location ;
515+ let storeValue ;
516+ const StoreReader = ( ) => {
517+ const [ value ] = useStore ( 'posts.listParams' ) ;
518+ React . useEffect ( ( ) => {
519+ storeValue = value ;
520+ } , [ value ] ) ;
521+ return null ;
522+ } ;
523+ render (
524+ < TestMemoryRouter
525+ locationCallback = { l => {
526+ location = l ;
527+ } }
528+ >
529+ < CoreAdminContext
530+ dataProvider = { testDataProvider ( ) }
531+ store = { memoryStore ( {
532+ 'posts.listParams' : {
533+ sort : 'id' ,
534+ order : 'ASC' ,
535+ page : 10 ,
536+ perPage : 10 ,
537+ filter : { } ,
538+ } ,
539+ } ) }
540+ >
541+ < Component />
542+ < StoreReader />
543+ </ CoreAdminContext >
544+ </ TestMemoryRouter >
545+ ) ;
546+
547+ await waitFor ( ( ) => {
548+ expect ( storeValue ) . toEqual ( {
549+ sort : 'id' ,
550+ order : 'ASC' ,
551+ page : 10 ,
552+ perPage : 10 ,
553+ filter : { } ,
554+ } ) ;
555+ } ) ;
556+
557+ await waitFor ( ( ) => {
558+ expect ( location ) . toEqual (
559+ expect . objectContaining ( {
560+ hash : '' ,
561+ key : expect . any ( String ) ,
562+ state : null ,
563+ pathname : '/' ,
564+ search :
565+ '?' +
566+ stringify ( {
567+ filter : JSON . stringify ( { } ) ,
568+ sort : 'id' ,
569+ order : 'ASC' ,
570+ page : 10 ,
571+ perPage : 10 ,
572+ } ) ,
573+ } )
574+ ) ;
575+ } ) ;
576+ } ) ;
577+
498578 it ( 'should not synchronize parameters with location and store when sync is not enabled' , async ( ) => {
499579 let location ;
500580 let storeValue ;
@@ -540,6 +620,191 @@ describe('useListParams', () => {
540620 expect ( storeValue ) . toBeUndefined ( ) ;
541621 } ) ;
542622
623+ it ( 'should not synchronize location with store if the location already contains parameters' , async ( ) => {
624+ let location ;
625+ render (
626+ < TestMemoryRouter
627+ initialEntries = { [
628+ {
629+ search :
630+ '?' +
631+ stringify ( {
632+ filter : JSON . stringify ( { } ) ,
633+ sort : 'id' ,
634+ order : 'ASC' ,
635+ page : 5 ,
636+ perPage : 10 ,
637+ } ) ,
638+ } ,
639+ ] }
640+ locationCallback = { l => {
641+ location = l ;
642+ } }
643+ >
644+ < CoreAdminContext
645+ dataProvider = { testDataProvider ( ) }
646+ store = { memoryStore ( {
647+ 'posts.listParams' : {
648+ sort : 'id' ,
649+ order : 'ASC' ,
650+ page : 10 ,
651+ perPage : 10 ,
652+ filter : { } ,
653+ } ,
654+ } ) }
655+ >
656+ < Component />
657+ </ CoreAdminContext >
658+ </ TestMemoryRouter >
659+ ) ;
660+
661+ await waitFor ( ( ) => {
662+ expect ( location ) . toEqual (
663+ expect . objectContaining ( {
664+ hash : '' ,
665+ key : expect . any ( String ) ,
666+ state : null ,
667+ pathname : '/' ,
668+ search :
669+ '?' +
670+ stringify ( {
671+ filter : JSON . stringify ( { } ) ,
672+ sort : 'id' ,
673+ order : 'ASC' ,
674+ page : 5 ,
675+ perPage : 10 ,
676+ } ) ,
677+ } )
678+ ) ;
679+ } ) ;
680+ } ) ;
681+
682+ it ( 'should not synchronize location with store if the store parameters are the defaults' , async ( ) => {
683+ let location ;
684+ render (
685+ < TestMemoryRouter
686+ locationCallback = { l => {
687+ location = l ;
688+ } }
689+ >
690+ < CoreAdminContext dataProvider = { testDataProvider ( ) } >
691+ < Component />
692+ </ CoreAdminContext >
693+ </ TestMemoryRouter >
694+ ) ;
695+
696+ // Let React do its thing
697+ await new Promise ( resolve => setTimeout ( resolve , 0 ) ) ;
698+
699+ await waitFor ( ( ) => {
700+ expect ( location ) . toEqual (
701+ expect . objectContaining ( {
702+ hash : '' ,
703+ key : expect . any ( String ) ,
704+ state : null ,
705+ pathname : '/' ,
706+ search : '' ,
707+ } )
708+ ) ;
709+ } ) ;
710+ } ) ;
711+
712+ it ( 'should not synchronize location with store if the store parameters are the custom defaults provided to the hook' , async ( ) => {
713+ let location ;
714+ render (
715+ < TestMemoryRouter
716+ locationCallback = { l => {
717+ location = l ;
718+ } }
719+ >
720+ < CoreAdminContext dataProvider = { testDataProvider ( ) } >
721+ < Component
722+ perPage = { 5 }
723+ sort = { { field : 'title' , order : 'DESC' } }
724+ />
725+ </ CoreAdminContext >
726+ </ TestMemoryRouter >
727+ ) ;
728+
729+ // Let React do its thing
730+ await new Promise ( resolve => setTimeout ( resolve , 0 ) ) ;
731+
732+ // The list is using the default set on the component
733+ await screen . findByText ( 'perPage: 5' ) ;
734+ await screen . findByText ( 'sort: title' ) ;
735+ await screen . findByText ( 'order: DESC' ) ;
736+
737+ // The location is the default for the list (no query parameters)
738+ await waitFor ( ( ) => {
739+ expect ( location ) . toEqual (
740+ expect . objectContaining ( {
741+ hash : '' ,
742+ key : expect . any ( String ) ,
743+ state : null ,
744+ pathname : '/' ,
745+ search : '' ,
746+ } )
747+ ) ;
748+ } ) ;
749+ } ) ;
750+
751+ it ( 'should not synchronize location with store when sync is not enabled' , async ( ) => {
752+ let location ;
753+ let storeValue ;
754+ const StoreReader = ( ) => {
755+ const [ value ] = useStore ( 'posts.listParams' ) ;
756+ React . useEffect ( ( ) => {
757+ storeValue = value ;
758+ } , [ value ] ) ;
759+ return null ;
760+ } ;
761+ render (
762+ < TestMemoryRouter
763+ locationCallback = { l => {
764+ location = l ;
765+ } }
766+ >
767+ < CoreAdminContext
768+ dataProvider = { testDataProvider ( ) }
769+ store = { memoryStore ( {
770+ 'posts.listParams' : {
771+ sort : 'id' ,
772+ order : 'ASC' ,
773+ page : 10 ,
774+ perPage : 10 ,
775+ filter : { } ,
776+ } ,
777+ } ) }
778+ >
779+ < Component disableSyncWithLocation />
780+ < StoreReader />
781+ </ CoreAdminContext >
782+ </ TestMemoryRouter >
783+ ) ;
784+
785+ await waitFor ( ( ) => {
786+ expect ( storeValue ) . toEqual ( {
787+ sort : 'id' ,
788+ order : 'ASC' ,
789+ page : 10 ,
790+ perPage : 10 ,
791+ filter : { } ,
792+ } ) ;
793+ } ) ;
794+
795+ await waitFor ( ( ) => {
796+ expect ( location ) . toEqual (
797+ expect . objectContaining ( {
798+ hash : '' ,
799+ key : expect . any ( String ) ,
800+ state : null ,
801+ pathname : '/' ,
802+ search : '' ,
803+ } )
804+ ) ;
805+ } ) ;
806+ } ) ;
807+
543808 it ( 'should synchronize parameters with store when sync is not enabled and storeKey is passed' , async ( ) => {
544809 let storeValue ;
545810 const Component = ( {
0 commit comments