@@ -18,6 +18,7 @@ import {
1818 CaaSApi_CMSInputTextArea ,
1919 CaaSApi_CMSInputToggle ,
2020 CaaSApi_Content2Section ,
21+ CaaSApi_DataEntries ,
2122 CaaSApi_FSCatalog ,
2223 CaaSApi_FSDataset ,
2324 CaaSApi_FSIndex ,
@@ -701,6 +702,28 @@ describe('CaaSMapper', () => {
701702 expect ( mapper . mapDataEntries ) . not . toHaveBeenCalled ( )
702703 expect ( mapper . registerReferencedItem ) . not . toHaveBeenCalled ( )
703704 } )
705+ it ( 'should return null and not register a reference if the DatasetReference target has a null identifier (broken reference)' , async ( ) => {
706+ const api = createApi ( )
707+ const mapper = new CaaSMapper ( api , 'de' , { } , createLogger ( ) )
708+ mapper . registerReferencedItem = jest . fn ( )
709+ const entry = createDatasetReference ( )
710+ ; ( entry . value as any ) . target . identifier = null
711+ await expect (
712+ mapper . mapDataEntry ( entry , createPath ( ) )
713+ ) . resolves . toBeNull ( )
714+ expect ( mapper . registerReferencedItem ) . not . toHaveBeenCalled ( )
715+ } )
716+ it ( 'should return null and not register a reference if the DatasetReference target itself is null (broken reference)' , async ( ) => {
717+ const api = createApi ( )
718+ const mapper = new CaaSMapper ( api , 'de' , { } , createLogger ( ) )
719+ mapper . registerReferencedItem = jest . fn ( )
720+ const entry = createDatasetReference ( )
721+ ; ( entry . value as any ) . target = null
722+ await expect (
723+ mapper . mapDataEntry ( entry , createPath ( ) )
724+ ) . resolves . toBeNull ( )
725+ expect ( mapper . registerReferencedItem ) . not . toHaveBeenCalled ( )
726+ } )
704727 } )
705728
706729 describe ( 'CMS_INPUT_TOGGLE' , ( ) => {
@@ -929,6 +952,30 @@ describe('CaaSMapper', () => {
929952 entry . value ! . remoteProject
930953 )
931954 } )
955+ it ( 'should return null and not register a reference on Media entries with a null identifier (broken reference)' , async ( ) => {
956+ const api = createApi ( )
957+ const mapper = new CaaSMapper ( api , 'de' , { } , createLogger ( ) )
958+ mapper . registerReferencedItem = jest . fn ( )
959+ const path = createPath ( )
960+ const entry : CaaSApi_FSReference = {
961+ name : faker . lorem . word ( ) ,
962+ value : {
963+ fsType : 'Media' ,
964+ name : faker . lorem . word ( ) ,
965+ identifier : null as any ,
966+ uid : faker . lorem . word ( ) ,
967+ uidType : 'MEDIASTORE_LEAF' ,
968+ url : faker . lorem . word ( ) ,
969+ mediaType : 'PICTURE' ,
970+ remoteProject : 'main' ,
971+ } as any ,
972+ fsType : 'FS_REFERENCE' ,
973+ }
974+ await expect (
975+ mapper . mapDataEntry ( entry , path )
976+ ) . resolves . toBeNull ( )
977+ expect ( mapper . registerReferencedItem ) . not . toHaveBeenCalled ( )
978+ } )
932979 it ( 'should handle PageRef & GCAPage separately' , async ( ) => {
933980 const api = createApi ( )
934981 const mapper = new CaaSMapper ( api , 'de' , { } , createLogger ( ) )
@@ -971,6 +1018,27 @@ describe('CaaSMapper', () => {
9711018 expectedGCARef
9721019 )
9731020 } )
1021+ it ( 'should return null on PageRef/GCAPage entries with a null identifier (broken reference)' , async ( ) => {
1022+ const api = createApi ( )
1023+ const mapper = new CaaSMapper ( api , 'de' , { } , createLogger ( ) )
1024+ const path = createPath ( )
1025+ const entry : CaaSApi_FSReference = {
1026+ name : faker . lorem . word ( ) ,
1027+ value : {
1028+ fsType : 'PageRef' ,
1029+ name : faker . lorem . word ( ) ,
1030+ identifier : null as any ,
1031+ uid : faker . lorem . word ( ) ,
1032+ uidType : 'SITESTORE_LEAF' ,
1033+ url : faker . lorem . word ( ) ,
1034+ remoteProject : 'remote-project' ,
1035+ } ,
1036+ fsType : 'FS_REFERENCE' ,
1037+ }
1038+ await expect ( mapper . mapDataEntry ( entry , path ) ) . resolves . toBeNull ( )
1039+ entry . value ! . fsType = 'GCAPage'
1040+ await expect ( mapper . mapDataEntry ( entry , path ) ) . resolves . toBeNull ( )
1041+ } )
9741042 it ( 'should return corrupted entries as-is' , async ( ) => {
9751043 const api = createApi ( )
9761044 const mapper = new CaaSMapper ( api , 'de' , { } , createLogger ( ) )
@@ -1170,6 +1238,57 @@ describe('CaaSMapper', () => {
11701238 { }
11711239 )
11721240 } )
1241+ // Regression test for CAAS-2680: a single broken Media reference anywhere in
1242+ // an element used to throw synchronously (unifyId -> null.indexOf) and reject
1243+ // the whole document. It must now be skipped (mapped to null) while the rest
1244+ // of the element is returned normally. Uses the real mapper (no mocks) so an
1245+ // unguarded null identifier would actually throw here.
1246+ it ( 'should skip a broken/null Media reference and still return the rest of the element' , async ( ) => {
1247+ const mapper = new CaaSMapper ( createApi ( ) , 'de' , { } , createLogger ( ) )
1248+ const entries = {
1249+ headline : {
1250+ fsType : 'CMS_INPUT_TEXT' ,
1251+ name : 'headline' ,
1252+ value : 'Weihnachtssocken' ,
1253+ } ,
1254+ brokenImage : {
1255+ fsType : 'FS_REFERENCE' ,
1256+ name : 'brokenImage' ,
1257+ value : {
1258+ fsType : 'Media' ,
1259+ name : faker . lorem . word ( ) ,
1260+ identifier : null as any ,
1261+ uid : '01_221021_4f3_weihnachtssocken_stage_b_1' ,
1262+ uidType : 'MEDIASTORE_LEAF' ,
1263+ url : faker . lorem . word ( ) ,
1264+ mediaType : 'PICTURE' ,
1265+ remoteProject : 'main' ,
1266+ } ,
1267+ } ,
1268+ validImage : {
1269+ fsType : 'FS_REFERENCE' ,
1270+ name : 'validImage' ,
1271+ value : {
1272+ fsType : 'Media' ,
1273+ name : faker . lorem . word ( ) ,
1274+ identifier : faker . string . uuid ( ) ,
1275+ uid : faker . lorem . word ( ) ,
1276+ uidType : 'MEDIASTORE_LEAF' ,
1277+ url : faker . lorem . word ( ) ,
1278+ mediaType : 'PICTURE' ,
1279+ } ,
1280+ } ,
1281+ } as any as CaaSApi_DataEntries
1282+
1283+ const result = await mapper . mapDataEntries ( entries , createPath ( ) )
1284+
1285+ // the broken reference is dropped, not thrown
1286+ expect ( result . brokenImage ) . toBeNull ( )
1287+ // the rest of the element survives
1288+ expect ( result . headline ) . toBe ( 'Weihnachtssocken' )
1289+ expect ( result . validImage ) . not . toBeNull ( )
1290+ expect ( typeof result . validImage ) . toBe ( 'string' )
1291+ } )
11731292 } )
11741293
11751294 describe ( 'mapSection' , ( ) => {
0 commit comments