@@ -1231,6 +1231,12 @@ describe('invokeSequence', () => {
12311231} )
12321232
12331233describe ( 'runDev' , ( ) => {
1234+ const originalEnv = process . env
1235+
1236+ afterEach ( ( ) => {
1237+ process . env = { ...originalEnv }
1238+ } )
1239+
12341240 test ( 'no front end, no back end' , async ( ) => {
12351241 const actionPath = fixturePath ( 'actions/successNoReturnAction.js' )
12361242 const config = createConfig ( {
@@ -1253,6 +1259,53 @@ describe('runDev', () => {
12531259 expect ( Object . keys ( actionUrls ) . length ) . toEqual ( 0 )
12541260 } )
12551261
1262+ test ( 'parses IMS_OAUTH_S2S environment variable' , async ( ) => {
1263+ const imsAuthData = { access_token : 'test-token' , org_id : 'test-org' }
1264+ process . env . IMS_OAUTH_S2S = JSON . stringify ( imsAuthData )
1265+
1266+ const actionPath = fixturePath ( 'actions/successNoReturnAction.js' )
1267+ const config = createConfig ( {
1268+ hasFrontend : false ,
1269+ hasBackend : true ,
1270+ packageName : 'mypackage' ,
1271+ actions : {
1272+ myaction : {
1273+ function : actionPath
1274+ }
1275+ }
1276+ } )
1277+ const runOptions = createRunOptions ( { cert : 'my-cert' , key : 'my-key' } )
1278+ const hookRunner = ( ) => { }
1279+ const { actionUrls, serverCleanup } = await runDev ( runOptions , config , hookRunner )
1280+
1281+ await serverCleanup ( )
1282+ // Verify runDev completes successfully when IMS_OAUTH_S2S env var is set with valid JSON
1283+ expect ( Object . keys ( actionUrls ) . length ) . toBeGreaterThan ( 0 )
1284+ } )
1285+
1286+ test ( 'handles invalid IMS_OAUTH_S2S JSON gracefully' , async ( ) => {
1287+ process . env . IMS_OAUTH_S2S = 'not-valid-json'
1288+
1289+ const actionPath = fixturePath ( 'actions/successNoReturnAction.js' )
1290+ const config = createConfig ( {
1291+ hasFrontend : false ,
1292+ hasBackend : true ,
1293+ packageName : 'mypackage' ,
1294+ actions : {
1295+ myaction : {
1296+ function : actionPath
1297+ }
1298+ }
1299+ } )
1300+ const runOptions = createRunOptions ( { cert : 'my-cert' , key : 'my-key' } )
1301+ const hookRunner = ( ) => { }
1302+ const { actionUrls, serverCleanup } = await runDev ( runOptions , config , hookRunner )
1303+
1304+ await serverCleanup ( )
1305+ // Verify runDev completes successfully even when IMS_OAUTH_S2S contains invalid JSON
1306+ expect ( Object . keys ( actionUrls ) . length ) . toBeGreaterThan ( 0 )
1307+ } )
1308+
12561309 test ( 'no front end, has back end' , async ( ) => {
12571310 const actionPath = fixturePath ( 'actions/successNoReturnAction.js' )
12581311 const config = createConfig ( {
@@ -1706,6 +1759,101 @@ describe('invokeAction', () => {
17061759 statusCode : 400
17071760 } )
17081761 } )
1762+
1763+ describe ( 'include-ims-credentials annotation' , ( ) => {
1764+ const rtLib = jest . requireActual ( '@adobe/aio-lib-runtime' )
1765+ let getIncludeIMSCredentialsAnnotationInputsSpy
1766+
1767+ beforeEach ( ( ) => {
1768+ getIncludeIMSCredentialsAnnotationInputsSpy = jest . spyOn ( rtLib . utils , 'getIncludeIMSCredentialsAnnotationInputs' )
1769+ } )
1770+
1771+ afterEach ( ( ) => {
1772+ getIncludeIMSCredentialsAnnotationInputsSpy . mockRestore ( )
1773+ } )
1774+
1775+ test ( 'adds IMS credentials to params when getIncludeIMSCredentialsAnnotationInputs returns inputs' , async ( ) => {
1776+ const packageName = 'foo'
1777+ const actionPath = fixturePath ( 'actions/successReturnAction.js' )
1778+ const actionLoader = createActionLoader ( actionPath )
1779+
1780+ const action = {
1781+ function : actionPath ,
1782+ annotations : {
1783+ 'include-ims-credentials' : true
1784+ }
1785+ }
1786+ const actionParams = { existingParam : 'value' }
1787+ const actionName = 'a'
1788+ const actionConfig = {
1789+ [ packageName ] : {
1790+ actions : {
1791+ [ actionName ] : action
1792+ }
1793+ }
1794+ }
1795+
1796+ // Mock the function to return IMS credentials
1797+ const mockImsInputs = {
1798+ __ims_oauth_s2s : { client_id : 'mock-access-token' , org_id : 'mock-org-id' } ,
1799+ __ims_env : 'stage'
1800+ }
1801+ getIncludeIMSCredentialsAnnotationInputsSpy . mockReturnValue ( mockImsInputs )
1802+
1803+ const actionRequestContext = {
1804+ contextActionLoader : actionLoader ,
1805+ contextItem : action ,
1806+ contextItemParams : actionParams ,
1807+ contextItemName : actionName ,
1808+ packageName,
1809+ actionConfig
1810+ }
1811+ const response = await invokeAction ( { actionRequestContext, logger : mockLogger } )
1812+
1813+ expect ( getIncludeIMSCredentialsAnnotationInputsSpy ) . toHaveBeenCalledWith ( action , expect . anything ( ) )
1814+ expect ( actionParams . __ims_oauth_s2s ) . toEqual ( { client_id : 'mock-access-token' , org_id : 'mock-org-id' } )
1815+ expect ( actionParams . __ims_env ) . toEqual ( 'stage' )
1816+ expect ( actionParams . existingParam ) . toEqual ( 'value' )
1817+ expect ( mockLogger . debug ) . toHaveBeenCalledWith ( `Added IMS credentials to action params for action '${ actionName } '.` )
1818+ expect ( response . statusCode ) . toEqual ( 200 )
1819+ } )
1820+
1821+ test ( 'does not add IMS credentials when getIncludeIMSCredentialsAnnotationInputs returns null' , async ( ) => {
1822+ const packageName = 'foo'
1823+ const actionPath = fixturePath ( 'actions/successReturnAction.js' )
1824+ const actionLoader = createActionLoader ( actionPath )
1825+
1826+ const action = { function : actionPath }
1827+ const actionParams = { existingParam : 'value' }
1828+ const actionName = 'a'
1829+ const actionConfig = {
1830+ [ packageName ] : {
1831+ actions : {
1832+ [ actionName ] : action
1833+ }
1834+ }
1835+ }
1836+
1837+ // Mock the function to return null (no annotation or no IMS auth object)
1838+ getIncludeIMSCredentialsAnnotationInputsSpy . mockReturnValue ( null )
1839+
1840+ const actionRequestContext = {
1841+ contextActionLoader : actionLoader ,
1842+ contextItem : action ,
1843+ contextItemParams : actionParams ,
1844+ contextItemName : actionName ,
1845+ packageName,
1846+ actionConfig
1847+ }
1848+ const response = await invokeAction ( { actionRequestContext, logger : mockLogger } )
1849+
1850+ expect ( getIncludeIMSCredentialsAnnotationInputsSpy ) . toHaveBeenCalledWith ( action , expect . anything ( ) )
1851+ expect ( actionParams . __ow_ims_access_token ) . toBeUndefined ( )
1852+ expect ( actionParams . __ow_ims_org_id ) . toBeUndefined ( )
1853+ expect ( actionParams . existingParam ) . toEqual ( 'value' )
1854+ expect ( response . statusCode ) . toEqual ( 200 )
1855+ } )
1856+ } )
17091857} )
17101858
17111859describe ( 'defaultActionLoader' , ( ) => {
0 commit comments