@@ -505,6 +505,193 @@ 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 removeLastButton = getByLabelText (
574+ // @ts -ignore
575+ screen . queryAllByLabelText ( 'Venue' ) [ 2 ] . closest ( 'li' ) ,
576+ 'ra.action.remove'
577+ ) . closest ( 'button' ) as HTMLButtonElement ;
578+
579+ fireEvent . click ( removeLastButton ) ;
580+ await waitFor ( ( ) => {
581+ expect ( screen . queryAllByLabelText ( 'Venue' ) . length ) . toEqual ( 2 ) ;
582+ } ) ;
583+
584+ fireEvent . click (
585+ screen
586+ . getByLabelText ( 'ra.action.add' )
587+ . closest ( 'button' ) as HTMLButtonElement
588+ ) ;
589+
590+ await waitFor ( ( ) => {
591+ expect ( screen . queryAllByLabelText ( 'Venue' ) . length ) . toEqual ( 3 ) ;
592+ } ) ;
593+
594+ expect (
595+ screen
596+ . queryAllByLabelText ( 'Stage Manager ID' )
597+ . map ( inputElement => ( inputElement as HTMLInputElement ) . value )
598+ ) . toEqual ( [ '101' , '102' , '' ] ) ;
599+ expect (
600+ screen
601+ . queryAllByLabelText ( 'Ticket Tier' )
602+ . map ( inputElement => ( inputElement as HTMLInputElement ) . value )
603+ ) . toEqual ( [ '' , 'premium' , '' ] ) ;
604+ expect (
605+ screen
606+ . queryAllByLabelText ( 'Language' )
607+ . map ( inputElement => ( inputElement as HTMLInputElement ) . value )
608+ ) . toEqual ( [ '' , 'en' , '' ] ) ;
609+ } ) ;
610+
611+ it ( 'should create nested null defaults for nested sources when adding a new item' , async ( ) => {
612+ const save = jest . fn ( ) ;
613+
614+ render (
615+ < Wrapper >
616+ < SimpleForm
617+ onSubmit = { save }
618+ record = { {
619+ id : 1 ,
620+ venueList : [
621+ {
622+ venue : 'Tokyo Dome, Tokyo' ,
623+ details : {
624+ stageManagerId : '103' ,
625+ ticketTier : 'vip' ,
626+ language : 'ja' ,
627+ } ,
628+ } ,
629+ ] ,
630+ } }
631+ >
632+ < ArrayInput source = "venueList" >
633+ < SimpleFormIterator >
634+ < TextInput source = "venue" label = "Venue" />
635+ < TextInput
636+ source = "details.stageManagerId"
637+ label = "Stage Manager ID"
638+ />
639+ < TextInput
640+ source = "details.ticketTier"
641+ label = "Ticket Tier"
642+ />
643+ < TextInput
644+ source = "details.language"
645+ label = "Language"
646+ />
647+ </ SimpleFormIterator >
648+ </ ArrayInput >
649+ </ SimpleForm >
650+ </ Wrapper >
651+ ) ;
652+
653+ const removeFirstButton = getByLabelText (
654+ // @ts -ignore
655+ screen . queryAllByLabelText ( 'Venue' ) [ 0 ] . closest ( 'li' ) ,
656+ 'ra.action.remove'
657+ ) . closest ( 'button' ) as HTMLButtonElement ;
658+
659+ fireEvent . click ( removeFirstButton ) ;
660+ await waitFor ( ( ) => {
661+ expect ( screen . queryAllByLabelText ( 'Venue' ) . length ) . toEqual ( 0 ) ;
662+ } ) ;
663+
664+ fireEvent . click (
665+ screen
666+ . getByLabelText ( 'ra.action.add' )
667+ . closest ( 'button' ) as HTMLButtonElement
668+ ) ;
669+
670+ await waitFor ( ( ) => {
671+ expect ( screen . queryAllByLabelText ( 'Venue' ) . length ) . toEqual ( 1 ) ;
672+ } ) ;
673+
674+ fireEvent . click ( screen . getByText ( 'ra.action.save' ) ) ;
675+
676+ await waitFor ( ( ) => {
677+ expect ( save ) . toHaveBeenCalled ( ) ;
678+ } ) ;
679+
680+ expect ( save . mock . calls [ 0 ] [ 0 ] ) . toEqual ( {
681+ id : 1 ,
682+ venueList : [
683+ {
684+ venue : null ,
685+ details : {
686+ stageManagerId : null ,
687+ ticketTier : null ,
688+ language : null ,
689+ } ,
690+ } ,
691+ ] ,
692+ } ) ;
693+ } ) ;
694+
508695 it ( 'should remove children row on remove button click' , async ( ) => {
509696 const emails = [ { email : 'foo@bar.com' } , { email : 'bar@foo.com' } ] ;
510697
0 commit comments