diff --git a/lib/deploy/stepFunctions/compileIamRole.js b/lib/deploy/stepFunctions/compileIamRole.js index c5f56760..864491be 100644 --- a/lib/deploy/stepFunctions/compileIamRole.js +++ b/lib/deploy/stepFunctions/compileIamRole.js @@ -407,6 +407,22 @@ function getLambdaPermissions(state) { }]; } +function getStateMachineArn(state) { + let stateMachineArn; + + if (state.Arguments) { + stateMachineArn = state.Arguments.StateMachineArn.trim().startsWith('{%') + ? '*' + : state.Arguments.StateMachineArn; + } else { + stateMachineArn = state.Parameters['StateMachineArn.$'] + ? '*' + : state.Parameters.StateMachineArn; + } + + return stateMachineArn; +} + function getStepFunctionsPermissions(state) { let stateMachineArn = state.Mode === 'DISTRIBUTED' ? { 'Fn::Sub': [ @@ -416,8 +432,7 @@ function getStepFunctionsPermissions(state) { } : null; if (!stateMachineArn) { - stateMachineArn = state.Parameters['StateMachineArn.$'] ? '*' - : state.Parameters.StateMachineArn; + stateMachineArn = getStateMachineArn(state); } return [{ @@ -449,8 +464,7 @@ function getStepFunctionsSDKPermissions(state) { } : null; if (!stateMachineArn) { - stateMachineArn = state.Parameters['StateMachineArn.$'] ? '*' - : state.Parameters.StateMachineArn; + stateMachineArn = getStateMachineArn(state); } return [{ diff --git a/lib/deploy/stepFunctions/compileIamRole.test.js b/lib/deploy/stepFunctions/compileIamRole.test.js index ab17a4a7..d9f76a2b 100644 --- a/lib/deploy/stepFunctions/compileIamRole.test.js +++ b/lib/deploy/stepFunctions/compileIamRole.test.js @@ -2874,219 +2874,447 @@ describe('#compileIamRole', () => { }]); }); - it('should give step functions permissions (too permissive, but mirrors console behaviour)', () => { - const stateMachineArn = 'arn:aws:states:us-east-1:123456789:stateMachine:HelloStateMachine'; - const genStateMachine = id => ({ - id, - definition: { - StartAt: 'A', - States: { - A: { - Type: 'Task', - Resource: 'arn:aws:states:::states:startExecution', - Parameters: { - StateMachineArn: stateMachineArn, - Input: {}, + describe('should give step functions permissions (too permissive, but mirrors console behaviour)', () => { + it('jsonpath', () => { + const stateMachineArn = 'arn:aws:states:us-east-1:123456789:stateMachine:HelloStateMachine'; + const genStateMachine = id => ({ + id, + definition: { + StartAt: 'A', + States: { + A: { + Type: 'Task', + Resource: 'arn:aws:states:::states:startExecution', + Parameters: { + StateMachineArn: stateMachineArn, + Input: {}, + }, + Next: 'B', }, - Next: 'B', - }, - B: { - Type: 'Task', - Resource: 'arn:aws:states:::states:startExecution.sync', - Parameters: { - StateMachineArn: stateMachineArn, - Input: {}, + B: { + Type: 'Task', + Resource: 'arn:aws:states:::states:startExecution.sync', + Parameters: { + StateMachineArn: stateMachineArn, + Input: {}, + }, + Next: 'C', }, - Next: 'C', - }, - C: { - Type: 'Task', - Resource: 'arn:aws:states:::states:startExecution.sync:2', - Parameters: { - StateMachineArn: stateMachineArn, - Input: {}, + C: { + Type: 'Task', + Resource: 'arn:aws:states:::states:startExecution.sync:2', + Parameters: { + StateMachineArn: stateMachineArn, + Input: {}, + }, + Next: 'D', }, - Next: 'D', - }, - D: { - Type: 'Task', - Resource: 'arn:aws:states:::states:startExecution.waitForTaskToken', - Parameters: { - StateMachineArn: stateMachineArn, - Input: {}, + D: { + Type: 'Task', + Resource: 'arn:aws:states:::states:startExecution.waitForTaskToken', + Parameters: { + StateMachineArn: stateMachineArn, + Input: {}, + }, + End: true, }, - End: true, }, }, - }, + }); + + serverless.service.stepFunctions = { + stateMachines: { + myStateMachine1: genStateMachine('StateMachine1'), + }, + }; + + serverlessStepFunctions.compileIamRole(); + const statements = serverlessStepFunctions.serverless.service + .provider.compiledCloudFormationTemplate.Resources.StateMachine1Role + .Properties.Policies[0].PolicyDocument.Statement; + + const stateMachinePermissions = statements.filter(s => _.isEqual(s.Action, ['states:StartExecution'])); + expect(stateMachinePermissions).to.have.lengthOf(1); + expect(stateMachinePermissions[0].Resource).to.deep.eq([stateMachineArn]); + + const executionPermissions = statements.filter(s => _.isEqual(s.Action, ['states:DescribeExecution', 'states:StopExecution'])); + expect(executionPermissions).to.have.lengthOf(1); + expect(executionPermissions[0].Resource).to.equal('*'); + + const eventPermissions = statements.filter(s => _.isEqual(s.Action, ['events:PutTargets', 'events:PutRule', 'events:DescribeRule'])); + expect(eventPermissions).to.have.lengthOf(1); + expect(eventPermissions[0].Resource).to.deep.eq([{ + 'Fn::Sub': [ + 'arn:${AWS::Partition}:events:${AWS::Region}:${AWS::AccountId}:rule/StepFunctionsGetEventsForStepFunctionsExecutionRule', + {}, + ], + }]); }); - serverless.service.stepFunctions = { - stateMachines: { - myStateMachine1: genStateMachine('StateMachine1'), - }, - }; + it('jsonata', () => { + const stateMachineArn = 'arn:aws:states:us-east-1:123456789:stateMachine:HelloStateMachine'; + const genStateMachine = id => ({ + id, + definition: { + QueryLanguage: 'JSONata', // JSONPath is default + StartAt: 'A', + States: { + A: { + Type: 'Task', + Resource: 'arn:aws:states:::states:startExecution', + Arguments: { + StateMachineArn: stateMachineArn, + Input: {}, + }, + Next: 'B', + }, + B: { + Type: 'Task', + Resource: 'arn:aws:states:::states:startExecution.sync', + Arguments: { + StateMachineArn: stateMachineArn, + Input: {}, + }, + Next: 'C', + }, + C: { + Type: 'Task', + Resource: 'arn:aws:states:::states:startExecution.sync:2', + Arguments: { + StateMachineArn: stateMachineArn, + Input: {}, + }, + Next: 'D', + }, + D: { + Type: 'Task', + Resource: 'arn:aws:states:::states:startExecution.waitForTaskToken', + Arguments: { + StateMachineArn: stateMachineArn, + Input: {}, + }, + End: true, + }, + }, + }, + }); - serverlessStepFunctions.compileIamRole(); - const statements = serverlessStepFunctions.serverless.service - .provider.compiledCloudFormationTemplate.Resources.StateMachine1Role - .Properties.Policies[0].PolicyDocument.Statement; + serverless.service.stepFunctions = { + stateMachines: { + myStateMachine1: genStateMachine('StateMachine1'), + }, + }; - const stateMachinePermissions = statements.filter(s => _.isEqual(s.Action, ['states:StartExecution'])); - expect(stateMachinePermissions).to.have.lengthOf(1); - expect(stateMachinePermissions[0].Resource).to.deep.eq([stateMachineArn]); + serverlessStepFunctions.compileIamRole(); + const statements = serverlessStepFunctions.serverless.service + .provider.compiledCloudFormationTemplate.Resources.StateMachine1Role + .Properties.Policies[0].PolicyDocument.Statement; - const executionPermissions = statements.filter(s => _.isEqual(s.Action, ['states:DescribeExecution', 'states:StopExecution'])); - expect(executionPermissions).to.have.lengthOf(1); - expect(executionPermissions[0].Resource).to.equal('*'); + const stateMachinePermissions = statements.filter(s => _.isEqual(s.Action, ['states:StartExecution'])); + expect(stateMachinePermissions).to.have.lengthOf(1); + expect(stateMachinePermissions[0].Resource).to.deep.eq([stateMachineArn]); - const eventPermissions = statements.filter(s => _.isEqual(s.Action, ['events:PutTargets', 'events:PutRule', 'events:DescribeRule'])); - expect(eventPermissions).to.have.lengthOf(1); - expect(eventPermissions[0].Resource).to.deep.eq([{ - 'Fn::Sub': [ - 'arn:${AWS::Partition}:events:${AWS::Region}:${AWS::AccountId}:rule/StepFunctionsGetEventsForStepFunctionsExecutionRule', - {}, - ], - }]); + const executionPermissions = statements.filter(s => _.isEqual(s.Action, ['states:DescribeExecution', 'states:StopExecution'])); + expect(executionPermissions).to.have.lengthOf(1); + expect(executionPermissions[0].Resource).to.equal('*'); + + const eventPermissions = statements.filter(s => _.isEqual(s.Action, ['events:PutTargets', 'events:PutRule', 'events:DescribeRule'])); + expect(eventPermissions).to.have.lengthOf(1); + expect(eventPermissions[0].Resource).to.deep.eq([{ + 'Fn::Sub': [ + 'arn:${AWS::Partition}:events:${AWS::Region}:${AWS::AccountId}:rule/StepFunctionsGetEventsForStepFunctionsExecutionRule', + {}, + ], + }]); + }); }); - it('should give step functions using sdk permissions (too permissive, but mirrors console behavior)', () => { - const stateMachineArn = 'arn:aws:states:us-east-1:123456789:stateMachine:HelloStateMachine'; - const genStateMachine = id => ({ - id, - definition: { - StartAt: 'A', - States: { - A: { - Type: 'Task', - Resource: 'arn:aws:states:::aws-sdk:sfn:startSyncExecution', - Parameters: { - StateMachineArn: stateMachineArn, - Input: {}, + describe('should give step functions using sdk permissions (too permissive, but mirrors console behavior)', () => { + it('jsonpath', () => { + const stateMachineArn = 'arn:aws:states:us-east-1:123456789:stateMachine:HelloStateMachine'; + const genStateMachine = id => ({ + id, + definition: { + StartAt: 'A', + States: { + A: { + Type: 'Task', + Resource: 'arn:aws:states:::aws-sdk:sfn:startSyncExecution', + Parameters: { + StateMachineArn: stateMachineArn, + Input: {}, + }, + End: true, }, - End: true, }, }, - }, + }); + + serverless.service.stepFunctions = { + stateMachines: { + myStateMachine1: genStateMachine('StateMachine1'), + }, + }; + + serverlessStepFunctions.compileIamRole(); + const statements = serverlessStepFunctions.serverless.service + .provider.compiledCloudFormationTemplate.Resources.StateMachine1Role + .Properties.Policies[0].PolicyDocument.Statement; + + const stateMachinePermissions = statements.filter(s => _.isEqual(s.Action, ['states:StartSyncExecution'])); + expect(stateMachinePermissions).to.have.lengthOf(1); + expect(stateMachinePermissions[0].Resource).to.deep.eq([stateMachineArn]); + + const executionPermissions = statements.filter(s => _.isEqual(s.Action, ['states:DescribeExecution', 'states:StopExecution'])); + expect(executionPermissions).to.have.lengthOf(1); + expect(executionPermissions[0].Resource).to.equal('*'); + + const eventPermissions = statements.filter(s => _.isEqual(s.Action, ['events:PutTargets', 'events:PutRule', 'events:DescribeRule'])); + expect(eventPermissions).to.have.lengthOf(1); + expect(eventPermissions[0].Resource).to.deep.eq([{ + 'Fn::Sub': [ + 'arn:${AWS::Partition}:events:${AWS::Region}:${AWS::AccountId}:rule/StepFunctionsGetEventsForStepFunctionsExecutionRule', + {}, + ], + }]); }); - serverless.service.stepFunctions = { - stateMachines: { - myStateMachine1: genStateMachine('StateMachine1'), - }, - }; + it('jsonata', () => { + const stateMachineArn = 'arn:aws:states:us-east-1:123456789:stateMachine:HelloStateMachine'; + const genStateMachine = id => ({ + id, + definition: { + QueryLanguage: 'JSONata', // JSONPath is default + StartAt: 'A', + States: { + A: { + Type: 'Task', + Resource: 'arn:aws:states:::aws-sdk:sfn:startSyncExecution', + Arguments: { + StateMachineArn: stateMachineArn, + Input: {}, + }, + End: true, + }, + }, + }, + }); - serverlessStepFunctions.compileIamRole(); - const statements = serverlessStepFunctions.serverless.service - .provider.compiledCloudFormationTemplate.Resources.StateMachine1Role - .Properties.Policies[0].PolicyDocument.Statement; + serverless.service.stepFunctions = { + stateMachines: { + myStateMachine1: genStateMachine('StateMachine1'), + }, + }; - const stateMachinePermissions = statements.filter(s => _.isEqual(s.Action, ['states:StartSyncExecution'])); - expect(stateMachinePermissions).to.have.lengthOf(1); - expect(stateMachinePermissions[0].Resource).to.deep.eq([stateMachineArn]); + serverlessStepFunctions.compileIamRole(); + const statements = serverlessStepFunctions.serverless.service + .provider.compiledCloudFormationTemplate.Resources.StateMachine1Role + .Properties.Policies[0].PolicyDocument.Statement; - const executionPermissions = statements.filter(s => _.isEqual(s.Action, ['states:DescribeExecution', 'states:StopExecution'])); - expect(executionPermissions).to.have.lengthOf(1); - expect(executionPermissions[0].Resource).to.equal('*'); + const stateMachinePermissions = statements.filter(s => _.isEqual(s.Action, ['states:StartSyncExecution'])); + expect(stateMachinePermissions).to.have.lengthOf(1); + expect(stateMachinePermissions[0].Resource).to.deep.eq([stateMachineArn]); - const eventPermissions = statements.filter(s => _.isEqual(s.Action, ['events:PutTargets', 'events:PutRule', 'events:DescribeRule'])); - expect(eventPermissions).to.have.lengthOf(1); - expect(eventPermissions[0].Resource).to.deep.eq([{ - 'Fn::Sub': [ - 'arn:${AWS::Partition}:events:${AWS::Region}:${AWS::AccountId}:rule/StepFunctionsGetEventsForStepFunctionsExecutionRule', - {}, - ], - }]); + const executionPermissions = statements.filter(s => _.isEqual(s.Action, ['states:DescribeExecution', 'states:StopExecution'])); + expect(executionPermissions).to.have.lengthOf(1); + expect(executionPermissions[0].Resource).to.equal('*'); + + const eventPermissions = statements.filter(s => _.isEqual(s.Action, ['events:PutTargets', 'events:PutRule', 'events:DescribeRule'])); + expect(eventPermissions).to.have.lengthOf(1); + expect(eventPermissions[0].Resource).to.deep.eq([{ + 'Fn::Sub': [ + 'arn:${AWS::Partition}:events:${AWS::Region}:${AWS::AccountId}:rule/StepFunctionsGetEventsForStepFunctionsExecutionRule', + {}, + ], + }]); + }); }); - it('should give step functions permission to * whenever StateMachineArn.$ is seen', () => { - const stateMachineArn = 'arn:aws:states:us-east-1:123456789:stateMachine:HelloStateMachine'; - const genStateMachine = id => ({ - id, - definition: { - StartAt: 'A', - States: { - A: { - Type: 'Task', - Resource: 'arn:aws:states:::states:startExecution', - Parameters: { - 'StateMachineArn.$': '$.arn', - Input: {}, + describe('should give step functions permission to * whenever StateMachineArn.$ (JSONPath) or {% $arn %} (JSONata) is seen', () => { + it('jsonpath', () => { + const stateMachineArn = 'arn:aws:states:us-east-1:123456789:stateMachine:HelloStateMachine'; + const genStateMachine = id => ({ + id, + definition: { + StartAt: 'A', + States: { + A: { + Type: 'Task', + Resource: 'arn:aws:states:::states:startExecution', + Parameters: { + 'StateMachineArn.$': '$.arn', + Input: {}, + }, + Next: 'B', }, - Next: 'B', - }, - B: { - Type: 'Task', - Resource: 'arn:aws:states:::states:startExecution.sync', - Parameters: { - StateMachineArn: stateMachineArn, - Input: {}, + B: { + Type: 'Task', + Resource: 'arn:aws:states:::states:startExecution.sync', + Parameters: { + StateMachineArn: stateMachineArn, + Input: {}, + }, + Next: 'C', }, - Next: 'C', - }, - C: { - Type: 'Task', - Resource: 'arn:aws:states:::states:startExecution.waitForTaskToken', - Parameters: { - StateMachineArn: stateMachineArn, - Input: {}, + C: { + Type: 'Task', + Resource: 'arn:aws:states:::states:startExecution.waitForTaskToken', + Parameters: { + StateMachineArn: stateMachineArn, + Input: {}, + }, + End: true, }, - End: true, }, }, - }, + }); + + serverless.service.stepFunctions = { + stateMachines: { + myStateMachine1: genStateMachine('StateMachine1'), + }, + }; + + serverlessStepFunctions.compileIamRole(); + const statements = serverlessStepFunctions.serverless.service + .provider.compiledCloudFormationTemplate.Resources.StateMachine1Role + .Properties.Policies[0].PolicyDocument.Statement; + + const stateMachinePermissions = statements.filter(s => _.includes(s.Action, 'states:StartExecution')); + expect(stateMachinePermissions).to.have.lengthOf(1); + expect(stateMachinePermissions[0].Resource).to.equal('*'); }); - serverless.service.stepFunctions = { - stateMachines: { - myStateMachine1: genStateMachine('StateMachine1'), - }, - }; + it('jsonata', () => { + const stateMachineArn = 'arn:aws:states:us-east-1:123456789:stateMachine:HelloStateMachine'; + const genStateMachine = id => ({ + id, + definition: { + QueryLanguage: 'JSONata', // JSONPath is default + StartAt: 'A', + States: { + A: { + Type: 'Task', + Resource: 'arn:aws:states:::states:startExecution', + Arguments: { + StateMachineArn: '{% $arn %}', + Input: {}, + }, + Next: 'B', + }, + B: { + Type: 'Task', + Resource: 'arn:aws:states:::states:startExecution.sync', + Arguments: { + StateMachineArn: stateMachineArn, + Input: {}, + }, + Next: 'C', + }, + C: { + Type: 'Task', + Resource: + 'arn:aws:states:::states:startExecution.waitForTaskToken', + Arguments: { + StateMachineArn: stateMachineArn, + Input: {}, + }, + End: true, + }, + }, + }, + }); - serverlessStepFunctions.compileIamRole(); - const statements = serverlessStepFunctions.serverless.service - .provider.compiledCloudFormationTemplate.Resources.StateMachine1Role - .Properties.Policies[0].PolicyDocument.Statement; + serverless.service.stepFunctions = { + stateMachines: { + myStateMachine1: genStateMachine('StateMachine1'), + }, + }; + + serverlessStepFunctions.compileIamRole(); + const statements = serverlessStepFunctions.serverless.service.provider + .compiledCloudFormationTemplate.Resources.StateMachine1Role + .Properties.Policies[0].PolicyDocument.Statement; - const stateMachinePermissions = statements.filter(s => _.includes(s.Action, 'states:StartExecution')); - expect(stateMachinePermissions).to.have.lengthOf(1); - expect(stateMachinePermissions[0].Resource).to.equal('*'); + const stateMachinePermissions = statements.filter(s => _.includes(s.Action, 'states:StartExecution')); + expect(stateMachinePermissions).to.have.lengthOf(1); + expect(stateMachinePermissions[0].Resource).to.equal('*'); + }); }); - it('should give step functions using sdk permission to * whenever StateMachineArn.$ is seen', () => { - const genStateMachine = id => ({ - id, - definition: { - StartAt: 'A', - States: { - A: { - Type: 'Task', - Resource: 'arn:aws:states:::aws-sdk:sfn:startSyncExecution', - Parameters: { - 'StateMachineArn.$': '$.arn', - Input: {}, + describe('should give step functions using sdk permission to * whenever StateMachineArn.$ (JSONPath) or {% $arn %} (JSONata) is seen', () => { + it('jsonpath', () => { + const genStateMachine = id => ({ + id, + definition: { + StartAt: 'A', + States: { + A: { + Type: 'Task', + Resource: 'arn:aws:states:::aws-sdk:sfn:startSyncExecution', + Parameters: { + 'StateMachineArn.$': '$.arn', + Input: {}, + }, + End: true, }, - End: true, }, }, - }, + }); + + serverless.service.stepFunctions = { + stateMachines: { + myStateMachine1: genStateMachine('StateMachine1'), + }, + }; + + serverlessStepFunctions.compileIamRole(); + const statements = serverlessStepFunctions.serverless.service + .provider.compiledCloudFormationTemplate.Resources.StateMachine1Role + .Properties.Policies[0].PolicyDocument.Statement; + + const stateMachinePermissions = statements.filter(s => _.includes(s.Action, 'states:StartSyncExecution')); + + expect(stateMachinePermissions).to.have.lengthOf(1); + expect(stateMachinePermissions[0].Resource).to.equal('*'); }); - serverless.service.stepFunctions = { - stateMachines: { - myStateMachine1: genStateMachine('StateMachine1'), - }, - }; + it('jsonata', () => { + const genStateMachine = id => ({ + id, + definition: { + QueryLanguage: 'JSONata', + StartAt: 'A', + States: { + A: { + Type: 'Task', + Resource: 'arn:aws:states:::aws-sdk:sfn:startSyncExecution', + Arguments: { + StateMachineArn: '{% $arn %}', + Input: {}, + }, + End: true, + }, + }, + }, + }); - serverlessStepFunctions.compileIamRole(); - const statements = serverlessStepFunctions.serverless.service - .provider.compiledCloudFormationTemplate.Resources.StateMachine1Role - .Properties.Policies[0].PolicyDocument.Statement; + serverless.service.stepFunctions = { + stateMachines: { + myStateMachine1: genStateMachine('StateMachine1'), + }, + }; + + serverlessStepFunctions.compileIamRole(); + const statements = serverlessStepFunctions.serverless.service + .provider.compiledCloudFormationTemplate.Resources.StateMachine1Role + .Properties.Policies[0].PolicyDocument.Statement; - const stateMachinePermissions = statements.filter(s => _.includes(s.Action, 'states:StartSyncExecution')); + const stateMachinePermissions = statements.filter(s => _.includes(s.Action, 'states:StartSyncExecution')); - expect(stateMachinePermissions).to.have.lengthOf(1); - expect(stateMachinePermissions[0].Resource).to.equal('*'); + expect(stateMachinePermissions).to.have.lengthOf(1); + expect(stateMachinePermissions[0].Resource).to.equal('*'); + }); }); it('should support Map state type', () => { diff --git a/lib/deploy/stepFunctions/compileStateMachines.test.js b/lib/deploy/stepFunctions/compileStateMachines.test.js index 1b17a39c..cfe5a5e9 100644 --- a/lib/deploy/stepFunctions/compileStateMachines.test.js +++ b/lib/deploy/stepFunctions/compileStateMachines.test.js @@ -16,7 +16,7 @@ describe('#compileStateMachines', () => { serverless.cli = new CLI(serverless); serverless.configSchemaHandler = { // eslint-disable-next-line no-unused-vars - defineTopLevelProperty: (propertyName, propertySchema) => {}, + defineTopLevelProperty: (propertyName, propertySchema) => { }, }; serverless.servicePath = true; serverless.service.service = 'step-functions'; @@ -1728,4 +1728,84 @@ describe('#compileStateMachines', () => { const stateMachineObj = JSON.parse(stateMachine.Properties.DefinitionString); expect(stateMachineObj.States).to.haveOwnProperty('One'); }); + + it('should compile with the new JSONata fields', () => { + serverless.service.stepFunctions = { + stateMachines: { + myStateMachine1: { + id: 'Test', + name: 'Test', + definition: { + Comment: 'Test JSONata features', + QueryLanguage: 'JSONata', + StartAt: 'Store inputs', + States: { + 'Store inputs': { + Type: 'Pass', + Next: 'Get Current Price', + Assign: { + desiredPrice: '{% $states.input.desired_price %}', + maximumWait: '{% $states.input.max_days %}', + }, + }, + 'Get Current Price': { + Type: 'Task', + QueryLanguage: 'JSONata', + Resource: 'arn:aws:states:::lambda:invoke', + Next: 'Output transformation', + Arguments: { + Payload: { + product: '{% $states.context.Execution.Input.product %}', + }, + FunctionName: 'arn:aws:lambda::123456789012:function:priceWatcher:$LATEST', + }, + Assign: { + currentPrice: '{% $states.result.Payload.current_price %}', + }, + }, + 'Output transformation': { + Type: 'Succeed', + Output: { + lastName: + "{% 'Last=>' & $states.input.customer.lastName %}", + orderValue: '{% $states.input.order.total %}', + }, + }, + }, + }, + }, + }, + }; + + serverlessStepFunctions.compileStateMachines(); + + const stateMachine = serverlessStepFunctions.serverless.service + .provider.compiledCloudFormationTemplate.Resources + .Test; + + expect(stateMachine.Properties.DefinitionString).not.to.haveOwnProperty('Fn::Sub'); + const stateMachineObj = JSON.parse(stateMachine.Properties.DefinitionString); + expect(stateMachineObj.States).to.haveOwnProperty('Store inputs'); + expect(stateMachineObj.States).to.haveOwnProperty('Get Current Price'); + expect(stateMachineObj.States).to.haveOwnProperty('Output transformation'); + + expect(stateMachineObj.QueryLanguage).to.equal('JSONata'); + expect(stateMachineObj.States['Store inputs'].Assign).to.deep.equal({ + desiredPrice: '{% $states.input.desired_price %}', + maximumWait: '{% $states.input.max_days %}', + }); + expect(stateMachineObj.States['Get Current Price'].Arguments).to.deep.equal({ + Payload: { + product: '{% $states.context.Execution.Input.product %}', + }, + FunctionName: 'arn:aws:lambda::123456789012:function:priceWatcher:$LATEST', + }); + expect(stateMachineObj.States['Get Current Price'].Assign).to.deep.equal({ + currentPrice: '{% $states.result.Payload.current_price %}', + }); + expect(stateMachineObj.States['Output transformation'].Output).to.deep.equal({ + lastName: "{% 'Last=>' & $states.input.customer.lastName %}", + orderValue: '{% $states.input.order.total %}', + }); + }); });