@@ -4,7 +4,14 @@ import {
44 DocumentDefinitionType ,
55 DocumentType ,
66} from '../../models/datamapper/document' ;
7- import { ChooseItem , FieldItem , MappingTree , OtherwiseItem , ValueSelector } from '../../models/datamapper/mapping' ;
7+ import {
8+ ChooseItem ,
9+ FieldItem ,
10+ ForEachItem ,
11+ MappingTree ,
12+ OtherwiseItem ,
13+ ValueSelector ,
14+ } from '../../models/datamapper/mapping' ;
815import {
916 ChoiceFieldNodeData ,
1017 DocumentNodeData ,
@@ -53,6 +60,38 @@ describe('MappingActionService / choice field mappings', () => {
5360 } as unknown as typeof baseField ;
5461 }
5562
63+ function createMockCollectionChoiceField ( members : { name : string } [ ] , selectedMemberIndex ?: number ) {
64+ const baseField = sourceDoc . fields [ 0 ] ;
65+ const memberFields = members . map ( ( m ) => ( {
66+ ...baseField ,
67+ name : m . name ,
68+ displayName : m . name ,
69+ fields : [ ] ,
70+ isChoice : false ,
71+ maxOccurs : 1 ,
72+ } ) ) ;
73+ return {
74+ ...baseField ,
75+ name : '__choice__' ,
76+ displayName : 'choice' ,
77+ isChoice : true ,
78+ wrapperKind : 'choice' as const ,
79+ selectedMemberIndex,
80+ fields : memberFields ,
81+ maxOccurs : 'unbounded' as const ,
82+ } as unknown as typeof baseField ;
83+ }
84+
85+ function createMockCollectionField ( ) {
86+ const baseField = targetDoc . fields [ 0 ] ;
87+ return {
88+ ...baseField ,
89+ name : 'collectionField' ,
90+ displayName : 'collectionField' ,
91+ maxOccurs : 'unbounded' as const ,
92+ } as unknown as typeof baseField ;
93+ }
94+
5695 describe ( 'engageMapping with choice source' , ( ) => {
5796 let localTargetDocNode : TargetDocumentNodeData ;
5897
@@ -443,4 +482,120 @@ describe('MappingActionService / choice field mappings', () => {
443482 expect ( nestedDirect1Item . nodePath . pathSegments ) . not . toContain ( freshInnerChoice . id ) ;
444483 } ) ;
445484 } ) ;
485+
486+ describe ( 'collection choice wrapper mappings (S2 scenario)' , ( ) => {
487+ let localTargetDocNode : TargetDocumentNodeData ;
488+
489+ beforeEach ( ( ) => {
490+ localTargetDocNode = new TargetDocumentNodeData ( targetDoc , tree ) ;
491+ } ) ;
492+
493+ it ( 'should create ForEachItem wrapping ChooseItem when mapping collection choice wrapper to collection field' , ( ) => {
494+ const collectionChoiceField = createMockCollectionChoiceField ( [ { name : 'email' } , { name : 'phone' } ] ) ;
495+ const choiceNode = new ChoiceFieldNodeData ( sourceDocNode , collectionChoiceField ) ;
496+ const collectionTargetField = createMockCollectionField ( ) ;
497+ const targetFieldNode = new TargetFieldNodeData ( localTargetDocNode , collectionTargetField ) ;
498+
499+ MappingActionService . engageMapping ( tree , choiceNode , targetFieldNode ) ;
500+
501+ expect ( tree . children . length ) . toEqual ( 1 ) ;
502+ const targetFieldItem = tree . children [ 0 ] ;
503+ expect ( targetFieldItem ) . toBeInstanceOf ( FieldItem ) ;
504+ expect ( targetFieldItem . children . length ) . toEqual ( 1 ) ;
505+
506+ const forEachItem = targetFieldItem . children [ 0 ] ;
507+ expect ( forEachItem ) . toBeInstanceOf ( ForEachItem ) ;
508+ expect ( forEachItem . children . length ) . toEqual ( 1 ) ;
509+
510+ const chooseItem = forEachItem . children [ 0 ] as ChooseItem ;
511+ expect ( chooseItem ) . toBeInstanceOf ( ChooseItem ) ;
512+ expect ( chooseItem . when . length ) . toEqual ( 2 ) ;
513+ expect ( chooseItem . otherwise ) . toBeInstanceOf ( OtherwiseItem ) ;
514+ } ) ;
515+
516+ it ( 'ForEachItem expression should be the XPath of the collection choice wrapper' , ( ) => {
517+ const collectionChoiceField = createMockCollectionChoiceField ( [ { name : 'email' } , { name : 'phone' } ] ) ;
518+ const choiceNode = new ChoiceFieldNodeData ( sourceDocNode , collectionChoiceField ) ;
519+ const collectionTargetField = createMockCollectionField ( ) ;
520+ const targetFieldNode = new TargetFieldNodeData ( localTargetDocNode , collectionTargetField ) ;
521+
522+ MappingActionService . engageMapping ( tree , choiceNode , targetFieldNode ) ;
523+
524+ const forEachItem = tree . children [ 0 ] . children [ 0 ] as ForEachItem ;
525+ // ForEachItem expression should be set (XPath to the collection choice wrapper)
526+ expect ( forEachItem . expression ) . toBeTruthy ( ) ;
527+ expect ( forEachItem . expression . length ) . toBeGreaterThan ( 0 ) ;
528+ } ) ;
529+
530+ it ( 'WhenItem expressions inside ForEachItem should reference the choice members' , ( ) => {
531+ const collectionChoiceField = createMockCollectionChoiceField ( [ { name : 'email' } , { name : 'phone' } ] ) ;
532+ const choiceNode = new ChoiceFieldNodeData ( sourceDocNode , collectionChoiceField ) ;
533+ const collectionTargetField = createMockCollectionField ( ) ;
534+ const targetFieldNode = new TargetFieldNodeData ( localTargetDocNode , collectionTargetField ) ;
535+
536+ MappingActionService . engageMapping ( tree , choiceNode , targetFieldNode ) ;
537+
538+ const forEachItem = tree . children [ 0 ] . children [ 0 ] as ForEachItem ;
539+ const chooseItem = forEachItem . children [ 0 ] as ChooseItem ;
540+ // WhenItem test expressions reference the choice members
541+ expect ( chooseItem . when [ 0 ] . expression ) . toContain ( 'email' ) ;
542+ expect ( chooseItem . when [ 1 ] . expression ) . toContain ( 'phone' ) ;
543+ // WhenItem value selectors should have paths to the members
544+ const emailSelector = chooseItem . when [ 0 ] . children . find ( ( c ) => c instanceof ValueSelector ) as ValueSelector ;
545+ const phoneSelector = chooseItem . when [ 1 ] . children . find ( ( c ) => c instanceof ValueSelector ) as ValueSelector ;
546+ expect ( emailSelector . expression ) . toContain ( 'email' ) ;
547+ expect ( phoneSelector . expression ) . toContain ( 'phone' ) ;
548+ } ) ;
549+
550+ it ( 'should create only ChooseItem (no ForEachItem) when mapping collection choice wrapper to non-collection field (S1)' , ( ) => {
551+ const collectionChoiceField = createMockCollectionChoiceField ( [ { name : 'email' } , { name : 'phone' } ] ) ;
552+ const choiceNode = new ChoiceFieldNodeData ( sourceDocNode , collectionChoiceField ) ;
553+ const nonCollectionTargetField = targetDoc . fields [ 0 ] ; // maxOccurs = 1
554+ const targetFieldNode = new TargetFieldNodeData ( localTargetDocNode , nonCollectionTargetField ) ;
555+
556+ MappingActionService . engageMapping ( tree , choiceNode , targetFieldNode ) ;
557+
558+ expect ( tree . children . length ) . toEqual ( 1 ) ;
559+ const targetFieldItem = tree . children [ 0 ] ;
560+ expect ( targetFieldItem ) . toBeInstanceOf ( FieldItem ) ;
561+ expect ( targetFieldItem . children . length ) . toEqual ( 1 ) ;
562+
563+ const chooseItem = targetFieldItem . children [ 0 ] ;
564+ expect ( chooseItem ) . toBeInstanceOf ( ChooseItem ) ;
565+ expect ( chooseItem ) . not . toBeInstanceOf ( ForEachItem ) ;
566+ expect ( ( chooseItem as ChooseItem ) . when . length ) . toEqual ( 2 ) ;
567+ } ) ;
568+
569+ it ( 'should create only ChooseItem when mapping non-collection choice wrapper to collection field' , ( ) => {
570+ const nonCollectionChoiceField = createMockChoiceField ( [ { name : 'email' } , { name : 'phone' } ] ) ;
571+ const choiceNode = new ChoiceFieldNodeData ( sourceDocNode , nonCollectionChoiceField ) ;
572+ const collectionTargetField = createMockCollectionField ( ) ;
573+ const targetFieldNode = new TargetFieldNodeData ( localTargetDocNode , collectionTargetField ) ;
574+
575+ MappingActionService . engageMapping ( tree , choiceNode , targetFieldNode ) ;
576+
577+ expect ( tree . children . length ) . toEqual ( 1 ) ;
578+ const targetFieldItem = tree . children [ 0 ] ;
579+ expect ( targetFieldItem ) . toBeInstanceOf ( FieldItem ) ;
580+ expect ( targetFieldItem . children . length ) . toEqual ( 1 ) ;
581+
582+ const chooseItem = targetFieldItem . children [ 0 ] ;
583+ expect ( chooseItem ) . toBeInstanceOf ( ChooseItem ) ;
584+ expect ( chooseItem ) . not . toBeInstanceOf ( ForEachItem ) ;
585+ } ) ;
586+
587+ it ( 'should not create duplicate ForEachItem when mapping the same collection choice source twice' , ( ) => {
588+ const collectionChoiceField = createMockCollectionChoiceField ( [ { name : 'email' } , { name : 'phone' } ] ) ;
589+ const choiceNode = new ChoiceFieldNodeData ( sourceDocNode , collectionChoiceField ) ;
590+ const collectionTargetField = createMockCollectionField ( ) ;
591+ const targetFieldNode = new TargetFieldNodeData ( localTargetDocNode , collectionTargetField ) ;
592+
593+ MappingActionService . engageMapping ( tree , choiceNode , targetFieldNode ) ;
594+ MappingActionService . engageMapping ( tree , choiceNode , targetFieldNode ) ;
595+
596+ const targetFieldItem = tree . children [ 0 ] ;
597+ const forEachItems = targetFieldItem . children . filter ( ( c ) => c instanceof ForEachItem ) ;
598+ expect ( forEachItems . length ) . toEqual ( 1 ) ;
599+ } ) ;
600+ } ) ;
446601} ) ;
0 commit comments