@@ -136,18 +136,40 @@ describe('CreateProductSpecComponent', () => {
136136
137137 it ( 'ngOnInit should configure steps with bundle enabled' , ( ) => {
138138 component . BUNDLE_ENABLED = true ;
139+ component . DATA_SPACE_ENABLED = false ;
139140 const initSpy = spyOn ( component , 'initPartyInfo' ) ;
140141 component . ngOnInit ( ) ;
141142 expect ( component . steps . length ) . toBe ( 9 ) ;
142143 expect ( component . steps ) . toContain ( 'Bundle' ) ;
144+ expect ( component . steps ) . not . toContain ( 'Dataspace Configuration' ) ;
143145 expect ( initSpy ) . toHaveBeenCalled ( ) ;
144146 } ) ;
145147
146148 it ( 'ngOnInit should configure steps without bundle' , ( ) => {
147149 component . BUNDLE_ENABLED = false ;
150+ component . DATA_SPACE_ENABLED = false ;
148151 component . ngOnInit ( ) ;
149152 expect ( component . steps . length ) . toBe ( 8 ) ;
150153 expect ( component . steps ) . not . toContain ( 'Bundle' ) ;
154+ expect ( component . steps ) . not . toContain ( 'Dataspace Configuration' ) ;
155+ } ) ;
156+
157+ it ( 'ngOnInit should configure steps with dataspace enabled and bundle enabled' , ( ) => {
158+ component . BUNDLE_ENABLED = true ;
159+ component . DATA_SPACE_ENABLED = true ;
160+ component . ngOnInit ( ) ;
161+ expect ( component . steps . length ) . toBe ( 10 ) ;
162+ expect ( component . steps ) . toContain ( 'Bundle' ) ;
163+ expect ( component . steps ) . toContain ( 'Dataspace Configuration' ) ;
164+ } ) ;
165+
166+ it ( 'ngOnInit should configure steps with dataspace enabled and no bundle' , ( ) => {
167+ component . BUNDLE_ENABLED = false ;
168+ component . DATA_SPACE_ENABLED = true ;
169+ component . ngOnInit ( ) ;
170+ expect ( component . steps . length ) . toBe ( 9 ) ;
171+ expect ( component . steps ) . not . toContain ( 'Bundle' ) ;
172+ expect ( component . steps ) . toContain ( 'Dataspace Configuration' ) ;
151173 } ) ;
152174
153175 it ( 'initPartyInfo should set partyId when logged directly' , ( ) => {
@@ -643,6 +665,36 @@ describe('CreateProductSpecComponent', () => {
643665 expect ( component . creatingChars ) . toEqual ( [ ] ) ;
644666 } ) ;
645667
668+ it ( 'refreshChars should use dataspace default type in dataspace step' , ( ) => {
669+ component . BUNDLE_ENABLED = false ;
670+ component . DATA_SPACE_ENABLED = true ;
671+ component . ngOnInit ( ) ;
672+ component . currentStep = 3 ;
673+ component . charTypeSelected = 'number' ;
674+
675+ component . refreshChars ( ) ;
676+
677+ expect ( component . charTypeSelected ) . toBe ( 'endpointUrl' ) ;
678+ } ) ;
679+
680+ it ( 'getFilteredCharacteristicsForCurrentStep should split default and dataspace characteristics' , ( ) => {
681+ component . BUNDLE_ENABLED = false ;
682+ component . DATA_SPACE_ENABLED = true ;
683+ component . ngOnInit ( ) ;
684+ component . prodChars = [
685+ { id : '1' , name : 'Latency' , valueType : 'string' } ,
686+ { id : '2' , name : 'Compliance: ISO 27001' , valueType : 'string' } ,
687+ { id : '3' , name : 'DCP endpoint' , valueType : 'endpointUrl' } ,
688+ { id : '4' , name : 'Policy' , valueType : 'authorizationPolicy' }
689+ ] as any ;
690+
691+ component . currentStep = 2 ;
692+ expect ( component . getFilteredCharacteristicsForCurrentStep ( ) . map ( char => char . name ) ) . toEqual ( [ 'Latency' ] ) ;
693+
694+ component . currentStep = 3 ;
695+ expect ( component . getFilteredCharacteristicsForCurrentStep ( ) . map ( char => char . name ) ) . toEqual ( [ 'DCP endpoint' , 'Policy' ] ) ;
696+ } ) ;
697+
646698 it ( 'removeClass and addClass should update className' , ( ) => {
647699 const elem = { className : 'a b c' } as HTMLElement ;
648700 component . removeClass ( elem , 'b' ) ;
@@ -737,6 +789,17 @@ describe('CreateProductSpecComponent', () => {
737789 expect ( component . creatingChars [ 1 ] . isDefault ) . toBeFalse ( ) ;
738790 } ) ;
739791
792+ it ( 'addCharValue should treat endpointUrl as text type' , ( ) => {
793+ component . charTypeSelected = 'endpointUrl' ;
794+ component . stringValue = 'https://example.org/api/dsp/2025-1' ;
795+
796+ component . addCharValue ( ) ;
797+
798+ expect ( component . creatingChars . length ) . toBe ( 1 ) ;
799+ expect ( component . creatingChars [ 0 ] . value as any ) . toBe ( 'https://example.org/api/dsp/2025-1' ) ;
800+ expect ( component . stringValue ) . toBe ( '' ) ;
801+ } ) ;
802+
740803 it ( 'addCharValue should add number values with units' , ( ) => {
741804 component . charTypeSelected = 'number' ;
742805 component . numberValue = '100' ;
@@ -822,6 +885,20 @@ describe('CreateProductSpecComponent', () => {
822885 expect ( component . creatingChars ) . toEqual ( [ ] ) ;
823886 } ) ;
824887
888+ it ( 'addCharValue should parse and add JSON values for targetSpecification' , ( ) => {
889+ component . charTypeSelected = 'targetSpecification' ;
890+ component . jsonValue = '{"@type":"AssetCollection","refinement":[]}' ;
891+
892+ component . addCharValue ( ) ;
893+
894+ expect ( component . creatingChars . length ) . toBe ( 1 ) ;
895+ expect ( component . creatingChars [ 0 ] . isDefault ) . toBeTrue ( ) ;
896+ expect ( component . creatingChars [ 0 ] . value as any ) . toEqual ( {
897+ '@type' : 'AssetCollection' ,
898+ refinement : [ ]
899+ } ) ;
900+ } ) ;
901+
825902 it ( 'removeCharValue and selectDefaultChar should manage created char values' , ( ) => {
826903 component . creatingChars = [
827904 { isDefault : true , value : 'A' } as any ,
@@ -911,6 +988,31 @@ describe('CreateProductSpecComponent', () => {
911988 expect ( ( component . prodChars [ 0 ] as any ) [ '@schemaLocation' ] ) . toContain ( 'policyCharacteristic.json' ) ;
912989 } ) ;
913990
991+ it ( 'saveChar should persist serviceConfiguration valueType without schema location' , ( ) => {
992+ component . charTypeSelected = 'serviceConfiguration' ;
993+ component . charsForm . patchValue ( { name : 'Service Configuration' , description : 'desc' } ) ;
994+ component . creatingChars = [ { isDefault : true , value : { defaultOidcScope : 'openid' } } as any ] ;
995+ component . isOptional = true ;
996+
997+ component . saveChar ( ) ;
998+
999+ expect ( component . prodChars . length ) . toBe ( 1 ) ;
1000+ expect ( ( component . prodChars [ 0 ] as any ) . valueType ) . toBe ( 'serviceConfiguration' ) ;
1001+ expect ( ( component . prodChars [ 0 ] as any ) [ '@schemaLocation' ] ) . toBeUndefined ( ) ;
1002+ expect ( component . prodChars . find ( char => char . name === 'Service Configuration - enabled' ) ) . toBeUndefined ( ) ;
1003+ } ) ;
1004+
1005+ it ( 'saveChar should persist endpointUrl valueType' , ( ) => {
1006+ component . charTypeSelected = 'endpointUrl' ;
1007+ component . charsForm . patchValue ( { name : 'DCP Endpoint' , description : 'desc' } ) ;
1008+ component . creatingChars = [ { isDefault : true , value : 'https://example.org/api' } as any ] ;
1009+
1010+ component . saveChar ( ) ;
1011+
1012+ expect ( component . prodChars . length ) . toBe ( 1 ) ;
1013+ expect ( ( component . prodChars [ 0 ] as any ) . valueType ) . toBe ( 'endpointUrl' ) ;
1014+ } ) ;
1015+
9141016 it ( 'deleteChar should remove characteristic and its related enabled one' , ( ) => {
9151017 const detectSpy = spyOn ( ( component as any ) . cdr , 'detectChanges' ) ;
9161018 component . prodChars = [
@@ -1002,6 +1104,36 @@ describe('CreateProductSpecComponent', () => {
10021104 expect ( component . productSpecToCreate ?. productSpecCharacteristic ?. some ( ( c : any ) => c . name === 'B' ) ) . toBeTrue ( ) ;
10031105 } ) ;
10041106
1107+ it ( 'showFinish should include self attestation even when it is not in prodChars' , ( ) => {
1108+ component . partyId = 'party-1' ;
1109+ component . generalForm . patchValue ( {
1110+ name : 'My Product' ,
1111+ description : 'Desc' ,
1112+ version : '1.0' ,
1113+ brand : 'Brand' ,
1114+ number : 'PN-1'
1115+ } ) ;
1116+ component . selectedISOS = [ ] ;
1117+ component . additionalISOS = [ ] ;
1118+ component . prodRelationships = [ ] ;
1119+ component . prodAttachments = [ ] ;
1120+ component . selectedResourceSpecs = [ ] ;
1121+ component . selectedServiceSpecs = [ ] ;
1122+ component . prodChars = [ { id : 'char-1' , name : 'Feature' , productSpecCharacteristicValue : [ { value : 'x' } ] } as any ] ;
1123+ component . selfAtt = {
1124+ id : 'self-att-1' ,
1125+ name : 'Compliance:SelfAtt' ,
1126+ productSpecCharacteristicValue : [ { isDefault : true , value : 'https://self-att' } ]
1127+ } ;
1128+
1129+ component . showFinish ( ) ;
1130+
1131+ const selfAtt = component . productSpecToCreate ?. productSpecCharacteristic ?. find ( ( c : any ) => c . name === 'Compliance:SelfAtt' ) ;
1132+ const selfAttValue = ( selfAtt as any ) ?. productSpecCharacteristicValue ?. [ 0 ] ?. value ;
1133+ expect ( selfAtt ) . toBeDefined ( ) ;
1134+ expect ( selfAttValue ) . toBe ( 'https://self-att' ) ;
1135+ } ) ;
1136+
10051137 it ( 'createProduct should call API and go back on success' , ( ) => {
10061138 const backSpy = spyOn ( component , 'goBack' ) ;
10071139 component . productSpecToCreate = { name : 'Prod' } as any ;
0 commit comments