@@ -505,6 +505,197 @@ describe('<SimpleFormIterator />', () => {
505505 expect ( screen . queryAllByLabelText ( 'ra.action.remove' ) . length ) . toBe ( 1 ) ;
506506 } ) ;
507507
508+ it ( 'should not reuse removed values for nested sources when adding a new item' , async ( ) => {
509+ render (
510+ < Wrapper >
511+ < SimpleForm
512+ record = { {
513+ id : 1 ,
514+ venueList : [
515+ {
516+ venue : 'Madison Square Garden, New York' ,
517+ details : {
518+ stageManagerId : '101' ,
519+ ticketTier : null ,
520+ language : null ,
521+ } ,
522+ } ,
523+ {
524+ venue : 'Wembley Stadium, London' ,
525+ details : {
526+ stageManagerId : '102' ,
527+ ticketTier : 'premium' ,
528+ language : 'en' ,
529+ } ,
530+ } ,
531+ {
532+ venue : 'Tokyo Dome, Tokyo' ,
533+ details : {
534+ stageManagerId : '103' ,
535+ ticketTier : 'vip' ,
536+ language : 'ja' ,
537+ } ,
538+ } ,
539+ ] ,
540+ } }
541+ >
542+ < ArrayInput source = "venueList" >
543+ < SimpleFormIterator >
544+ < TextInput source = "venue" label = "Venue" />
545+ < TextInput
546+ source = "details.stageManagerId"
547+ label = "Stage Manager ID"
548+ />
549+ < TextInput
550+ source = "details.ticketTier"
551+ label = "Ticket Tier"
552+ />
553+ < TextInput
554+ source = "details.language"
555+ label = "Language"
556+ />
557+ </ SimpleFormIterator >
558+ </ ArrayInput >
559+ </ SimpleForm >
560+ </ Wrapper >
561+ ) ;
562+
563+ await waitFor ( ( ) => {
564+ expect (
565+ screen
566+ . queryAllByLabelText ( 'Stage Manager ID' )
567+ . map (
568+ inputElement => ( inputElement as HTMLInputElement ) . value
569+ )
570+ ) . toEqual ( [ '101' , '102' , '103' ] ) ;
571+ } ) ;
572+
573+ const lastItem = screen
574+ . queryAllByLabelText ( 'Venue' ) [ 2 ]
575+ . closest ( 'li' ) as HTMLElement ;
576+ const removeLastButton = getByLabelText (
577+ lastItem ,
578+ 'ra.action.remove'
579+ ) . closest ( 'button' ) as HTMLButtonElement ;
580+
581+ fireEvent . click ( removeLastButton ) ;
582+ await waitFor ( ( ) => {
583+ expect ( screen . queryAllByLabelText ( 'Venue' ) . length ) . toEqual ( 2 ) ;
584+ } ) ;
585+
586+ fireEvent . click (
587+ screen
588+ . getByLabelText ( 'ra.action.add' )
589+ . closest ( 'button' ) as HTMLButtonElement
590+ ) ;
591+
592+ await waitFor ( ( ) => {
593+ expect ( screen . queryAllByLabelText ( 'Venue' ) . length ) . toEqual ( 3 ) ;
594+ } ) ;
595+
596+ expect (
597+ screen
598+ . queryAllByLabelText ( 'Stage Manager ID' )
599+ . map ( inputElement => ( inputElement as HTMLInputElement ) . value )
600+ ) . toEqual ( [ '101' , '102' , '' ] ) ;
601+ expect (
602+ screen
603+ . queryAllByLabelText ( 'Ticket Tier' )
604+ . map ( inputElement => ( inputElement as HTMLInputElement ) . value )
605+ ) . toEqual ( [ '' , 'premium' , '' ] ) ;
606+ expect (
607+ screen
608+ . queryAllByLabelText ( 'Language' )
609+ . map ( inputElement => ( inputElement as HTMLInputElement ) . value )
610+ ) . toEqual ( [ '' , 'en' , '' ] ) ;
611+ } ) ;
612+
613+ it ( 'should create nested null defaults for nested sources when adding a new item' , async ( ) => {
614+ const save = jest . fn ( ) ;
615+
616+ render (
617+ < Wrapper >
618+ < SimpleForm
619+ onSubmit = { save }
620+ record = { {
621+ id : 1 ,
622+ venueList : [
623+ {
624+ venue : 'Tokyo Dome, Tokyo' ,
625+ details : {
626+ stageManagerId : '103' ,
627+ ticketTier : 'vip' ,
628+ language : 'ja' ,
629+ } ,
630+ } ,
631+ ] ,
632+ } }
633+ >
634+ < ArrayInput source = "venueList" >
635+ < SimpleFormIterator >
636+ < TextInput source = "venue" label = "Venue" />
637+ < TextInput
638+ source = "details.stageManagerId"
639+ label = "Stage Manager ID"
640+ />
641+ < TextInput
642+ source = "details.ticketTier"
643+ label = "Ticket Tier"
644+ />
645+ < TextInput
646+ source = "details.language"
647+ label = "Language"
648+ />
649+ </ SimpleFormIterator >
650+ </ ArrayInput >
651+ </ SimpleForm >
652+ </ Wrapper >
653+ ) ;
654+
655+ const firstItem = screen
656+ . queryAllByLabelText ( 'Venue' ) [ 0 ]
657+ . closest ( 'li' ) as HTMLElement ;
658+ const removeFirstButton = getByLabelText (
659+ firstItem ,
660+ 'ra.action.remove'
661+ ) . closest ( 'button' ) as HTMLButtonElement ;
662+
663+ fireEvent . click ( removeFirstButton ) ;
664+ await waitFor ( ( ) => {
665+ expect ( screen . queryAllByLabelText ( 'Venue' ) . length ) . toEqual ( 0 ) ;
666+ } ) ;
667+
668+ fireEvent . click (
669+ screen
670+ . getByLabelText ( 'ra.action.add' )
671+ . closest ( 'button' ) as HTMLButtonElement
672+ ) ;
673+
674+ await waitFor ( ( ) => {
675+ expect ( screen . queryAllByLabelText ( 'Venue' ) . length ) . toEqual ( 1 ) ;
676+ } ) ;
677+
678+ fireEvent . click ( screen . getByText ( 'ra.action.save' ) ) ;
679+
680+ await waitFor ( ( ) => {
681+ expect ( save ) . toHaveBeenCalled ( ) ;
682+ } ) ;
683+
684+ expect ( save . mock . calls [ 0 ] [ 0 ] ) . toEqual ( {
685+ id : 1 ,
686+ venueList : [
687+ {
688+ venue : null ,
689+ details : {
690+ stageManagerId : null ,
691+ ticketTier : null ,
692+ language : null ,
693+ } ,
694+ } ,
695+ ] ,
696+ } ) ;
697+ } ) ;
698+
508699 it ( 'should remove children row on remove button click' , async ( ) => {
509700 const emails = [ { email : 'foo@bar.com' } , { email : 'bar@foo.com' } ] ;
510701
0 commit comments