How to test Reference type value in cdk stack?

Viewed 773

I am using aws cdk library to create resource and was able to create resources succuessfully. Now want to test this generated statck. Again if its single resources then able to test it fine but when stack has more than one resources then don't how to rest that.

Following is code to create resources.

constructor(scope: cdk.Construct, id: string, props: CIAMSQSProps = {} ) {
    super(scope, id);

    const queue = new sqs.Queue(this, id, {
      queueName: props.queueName!,
    });
    
    let ssmParamters = new CreateSSMParamaters(this, id, {
      envName: props.envName!,
      envValue: sqsQueue.queueUrl
    });
}

Following is the code for testing and it fails because stack contains reference.

test('Test SSM Parameter', () => {
  const app = new App();
  const sqsStack = new TestSQS(app, 'test-sqs-stack', {
    queueName: 'TestQueue',
    envName: 'TestQueue',
  });

  const template = Template.fromStack(sqsStack);
  template.hasResourceProperties(ResourceTypes.SSM_PARAM_TYPE, "{ Name: 'TestQueue', Value: 'TestQueue', Type: 'String' }");
});

Following is the error.

Template has 1 resources with type AWS::SSM::Parameter, but none match as expected.
    The closest result is:
      {
        "Type": "AWS::SSM::Parameter",
        "Properties": {
          "Type": "String",
          "Value": {
            "Ref": "testsqsstackEDC1E09E"
          },
          "Name": "TestQueue"
        }
      }
    with the following mismatches:
        Expected type string but received object at /Properties (using objectLike matcher)

can someone help me on this? Or is there any way to test specific property for resource type?

1 Answers

I have found several options to test property references. I have not seen any documented best practice on this topic. Perhaps this is because, in most cases, we need not test such implementation details.

Option 1: Export the source Construct from its Stack. Resolve its Token value.

template.hasResourceProperties('AWS::SSM::Parameter', {
  Value: stack.resolve(stack.queue.queueName),
});

Option 2: As above, but use escape hatches instead of field export to get the queue reference.

const childQueue = stack.node.tryFindChild('MyQueue') as sqs.Queue;

template.hasResourceProperties('AWS::SSM::Parameter', {
  Value: stack.resolve(childQueue.queueName),
});

Option 3: Find the queue resource's name in the template.

const queues = template.findResources('AWS::SQS::Queue');
expect(Object.keys(queues)).toHaveLength(1);
const resolvedQueueName = Object.keys(queues)[0];

template.hasResourceProperties('AWS::SSM::Parameter', {
  Value: { 'Fn::GetAtt': [resolvedQueueName, 'QueueName'],},
});
Related