@@ -847,3 +847,223 @@ describe('getFilesCountWithExtension', () => {
847847 ] )
848848 } )
849849} )
850+
851+ describe ( 'rewriteActionUrlInEntities' , ( ) => {
852+ const RuntimeLib = require ( '@adobe/aio-lib-runtime' )
853+
854+ beforeEach ( ( ) => {
855+ RuntimeLib . utils . getActionUrls = jest . fn ( )
856+ } )
857+
858+ afterEach ( ( ) => {
859+ jest . clearAllMocks ( )
860+ } )
861+
862+ test ( 'should rewrite action URLs with URLs from manifest' , async ( ) => {
863+ const entities = {
864+ actions : [
865+ { name : 'action1' , url : 'old-url-1' } ,
866+ { name : 'action2' , url : 'old-url-2' }
867+ ]
868+ }
869+ const config = {
870+ actions : { devRemote : false }
871+ }
872+ const mockActionUrls = {
873+ action1 : 'https://example.com/api/v1/web/action1' ,
874+ action2 : 'https://example.com/api/v1/web/action2'
875+ }
876+
877+ RuntimeLib . utils . getActionUrls . mockReturnValue ( mockActionUrls )
878+
879+ const result = await appHelper . rewriteActionUrlInEntities ( { entities, config } )
880+
881+ expect ( RuntimeLib . utils . getActionUrls ) . toHaveBeenCalledWith ( config , false )
882+ expect ( result . actions ) . toEqual ( [
883+ { name : 'action1' , url : 'https://example.com/api/v1/web/action1' } ,
884+ { name : 'action2' , url : 'https://example.com/api/v1/web/action2' }
885+ ] )
886+ } )
887+
888+ test ( 'should use devRemote flag when calling getActionUrls' , async ( ) => {
889+ const entities = { actions : [ ] }
890+ const config = {
891+ actions : { devRemote : true }
892+ }
893+
894+ RuntimeLib . utils . getActionUrls . mockReturnValue ( { } )
895+
896+ await appHelper . rewriteActionUrlInEntities ( { entities, config } )
897+
898+ expect ( RuntimeLib . utils . getActionUrls ) . toHaveBeenCalledWith ( config , true )
899+ } )
900+
901+ test ( 'should preserve original action when no URL found in manifest' , async ( ) => {
902+ const entities = {
903+ actions : [
904+ { name : 'action1' , url : 'original-url' } ,
905+ { name : 'action2' , url : 'another-original-url' }
906+ ]
907+ }
908+ const config = {
909+ actions : { devRemote : false }
910+ }
911+ const mockActionUrls = {
912+ action1 : 'https://example.com/api/v1/web/action1'
913+ // action2 is missing from manifest URLs
914+ }
915+
916+ RuntimeLib . utils . getActionUrls . mockReturnValue ( mockActionUrls )
917+
918+ const result = await appHelper . rewriteActionUrlInEntities ( { entities, config } )
919+
920+ expect ( result . actions ) . toEqual ( [
921+ { name : 'action1' , url : 'https://example.com/api/v1/web/action1' } ,
922+ { name : 'action2' , url : 'another-original-url' } // Original URL preserved
923+ ] )
924+ } )
925+
926+ test ( 'should handle entities with no actions array' , async ( ) => {
927+ const entities = { }
928+ const config = {
929+ actions : { devRemote : false }
930+ }
931+
932+ RuntimeLib . utils . getActionUrls . mockReturnValue ( { } )
933+
934+ const result = await appHelper . rewriteActionUrlInEntities ( { entities, config } )
935+
936+ expect ( result . actions ) . toBeUndefined ( )
937+ expect ( RuntimeLib . utils . getActionUrls ) . toHaveBeenCalledWith ( config , false )
938+ } )
939+
940+ test ( 'should handle entities with undefined actions' , async ( ) => {
941+ const entities = { actions : undefined }
942+ const config = {
943+ actions : { devRemote : false }
944+ }
945+
946+ RuntimeLib . utils . getActionUrls . mockReturnValue ( { } )
947+
948+ const result = await appHelper . rewriteActionUrlInEntities ( { entities, config } )
949+
950+ expect ( result . actions ) . toBeUndefined ( )
951+ } )
952+
953+ test ( 'should handle empty actions array' , async ( ) => {
954+ const entities = { actions : [ ] }
955+ const config = {
956+ actions : { devRemote : false }
957+ }
958+
959+ RuntimeLib . utils . getActionUrls . mockReturnValue ( { } )
960+
961+ const result = await appHelper . rewriteActionUrlInEntities ( { entities, config } )
962+
963+ expect ( result . actions ) . toEqual ( [ ] )
964+ } )
965+
966+ test ( 'should create deep copy and not mutate original entities' , async ( ) => {
967+ const originalEntities = {
968+ actions : [
969+ { name : 'action1' , url : 'original-url' , otherProp : 'value' }
970+ ] ,
971+ otherProp : 'test'
972+ }
973+ const config = {
974+ actions : { devRemote : false }
975+ }
976+ const mockActionUrls = {
977+ action1 : 'https://example.com/api/v1/web/action1'
978+ }
979+
980+ RuntimeLib . utils . getActionUrls . mockReturnValue ( mockActionUrls )
981+
982+ const result = await appHelper . rewriteActionUrlInEntities ( { entities : originalEntities , config } )
983+
984+ // Original should be unchanged
985+ expect ( originalEntities . actions [ 0 ] . url ) . toBe ( 'original-url' )
986+ expect ( originalEntities . otherProp ) . toBe ( 'test' )
987+
988+ // Result should have the new URL
989+ expect ( result . actions [ 0 ] . url ) . toBe ( 'https://example.com/api/v1/web/action1' )
990+ expect ( result . actions [ 0 ] . otherProp ) . toBe ( 'value' )
991+ expect ( result . otherProp ) . toBe ( 'test' )
992+
993+ // Should be different objects
994+ expect ( result ) . not . toBe ( originalEntities )
995+ expect ( result . actions ) . not . toBe ( originalEntities . actions )
996+ expect ( result . actions [ 0 ] ) . not . toBe ( originalEntities . actions [ 0 ] )
997+ } )
998+
999+ test ( 'should preserve all other action properties' , async ( ) => {
1000+ const entities = {
1001+ actions : [
1002+ {
1003+ name : 'action1' ,
1004+ url : 'old-url' ,
1005+ version : '1.0.0' ,
1006+ annotations : { 'web-export' : true } ,
1007+ parameters : { key : 'value' } ,
1008+ exec : { kind : 'nodejs:18' }
1009+ }
1010+ ]
1011+ }
1012+ const config = {
1013+ actions : { devRemote : false }
1014+ }
1015+ const mockActionUrls = {
1016+ action1 : 'https://example.com/api/v1/web/action1'
1017+ }
1018+
1019+ RuntimeLib . utils . getActionUrls . mockReturnValue ( mockActionUrls )
1020+
1021+ const result = await appHelper . rewriteActionUrlInEntities ( { entities, config } )
1022+
1023+ expect ( result . actions [ 0 ] ) . toEqual ( {
1024+ name : 'action1' ,
1025+ url : 'https://example.com/api/v1/web/action1' ,
1026+ version : '1.0.0' ,
1027+ annotations : { 'web-export' : true } ,
1028+ parameters : { key : 'value' } ,
1029+ exec : { kind : 'nodejs:18' }
1030+ } )
1031+ } )
1032+
1033+ test ( 'should handle empty action URLs from manifest' , async ( ) => {
1034+ const entities = {
1035+ actions : [
1036+ { name : 'action1' , url : 'original-url' }
1037+ ]
1038+ }
1039+ const config = {
1040+ actions : { devRemote : false }
1041+ }
1042+
1043+ RuntimeLib . utils . getActionUrls . mockReturnValue ( { } ) // Empty object
1044+
1045+ const result = await appHelper . rewriteActionUrlInEntities ( { entities, config } )
1046+
1047+ expect ( result . actions [ 0 ] . url ) . toBe ( 'original-url' ) // Should preserve original
1048+ } )
1049+
1050+ test ( 'should handle null/undefined URL from manifest' , async ( ) => {
1051+ const entities = {
1052+ actions : [
1053+ { name : 'action1' , url : 'original-url' }
1054+ ]
1055+ }
1056+ const config = {
1057+ actions : { devRemote : false }
1058+ }
1059+ const mockActionUrls = {
1060+ action1 : null // Null URL
1061+ }
1062+
1063+ RuntimeLib . utils . getActionUrls . mockReturnValue ( mockActionUrls )
1064+
1065+ const result = await appHelper . rewriteActionUrlInEntities ( { entities, config } )
1066+
1067+ expect ( result . actions [ 0 ] . url ) . toBe ( 'original-url' ) // Should preserve original when URL is falsy
1068+ } )
1069+ } )
0 commit comments