AWS CDK unit test failing - jest ts

Viewed 2360

I created an AWS CDK app in Typescript that creates an IAM Role. Here is my code:

export class AccountCreatorIamRoleStack extends cdk.Stack {
    public create(): iam.Role {
        const iamRole = some logic to create iam role goes here;
        return iamRole;
    }
}

I have confirmed that this code works by creating an IAM Role like this:

var roleCreator = new AccountCreatorIamRoleStack(app, 'AccountCreatorIamRoleStack');
roleCreator.create();

However, when I run this jest unit test:

test('Test IAM Role Created', () => {
  const app = new cdk.App();
  // WHEN
  var stack = new AccountCreatorIamRoleStack(app, 'TestAccountCreatorIamRoleStack').create()
  // THEN
  expectCDK(stack).to(haveResource("AWS::IAM::Role"));
});

It fails with the following error:

 FAIL  test/account-creation-iam-role-stack.test.ts
  ✕ Test IAM Role Created (32 ms)

  ● Test IAM Role Created

    None of 0 resources matches resource 'AWS::IAM::Role' with {
      "$anything": true
    }.

      16 |   var stack = new AccountCreatorIamRoleStack(app, 'TestAccountCreatorIamRoleStack').create()
      17 |   // THEN
    > 18 |   expectCDK(stack).to(haveResource("AWS::IAM::Role"));
     |                    ^
      19 | });

      at HaveResourceAssertion.assertOrThrow (node_modules/@aws-cdk/assert/lib/assertions/have-resource.ts:100:13)
      at StackInspector._to (node_modules/@aws-cdk/assert/lib/inspector.ts:25:15)
      at StackInspector.to (node_modules/@aws-cdk/assert/lib/inspector.ts:15:14)
      at Object.<anonymous> (test/account-creation-iam-role-stack.test.ts:18:20)

I can see it is pointing to something on that line, but what exactly is it pointing to that it thinks is an error? Thoughts?

2 Answers

Your code is making an assertion that AWS::IAM::Role has "VisibilityTimeout": 300 but it doesn't have such attribute. It should pass for haveResource("AWS::IAM::Role") alone (without additional properties) when your code is actually creating it.

Here are the current attributes on IAM Role: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iam-role.html

{
  "Type" : "AWS::IAM::Role",
  "Properties" : {
      "AssumeRolePolicyDocument" : Json,
      "Description" : String,
      "ManagedPolicyArns" : [ String, ... ],
      "MaxSessionDuration" : Integer,
      "Path" : String,
      "PermissionsBoundary" : String,
      "Policies" : [ Policy, ... ],
      "RoleName" : String,
      "Tags" : [ Tag, ... ]
    }
}```

What you should use, when just trying to identify if a resource is created, is countResources:

expectCDK(stack).to(countResources('AWS::IAM::Role', 1));

When using haveResource it is expecting an object to compare it to. Since you are not providing an object to compare, this will fail. Also, this check is pointless if you are not checking the object expectancy and you should use countResources instead.

This is an example of using haveResource for object expectancy:

test('Verify IAM AssumeRole', () => {
  expectCDK(stack).to(
    haveResource('AWS::IAM::Role', {
      AssumeRolePolicyDocument: {
        Statement: [
          {
            Action: 'sts:AssumeRole',
            Effect: 'Allow',
            Principal: {
              Service: [
                'codestar.amazonaws.com',
              ],
            },
          },
        ],
      },
      RoleName: 'some-name-for-assume-role',
    }),
  );
});

You also have haveResourceLike which can be helpful for partials or you can even do more with using arrayWith(objectLike({...}))

An example of this:

// ECR Auth token Access
expectCDK(stack).to(
  haveResourceLike('AWS::IAM::Policy', {
    PolicyDocument: {
      Statement: arrayWith(
        objectLike({
          Action: 'ecr:GetAuthorizationToken',
          Effect: 'Allow',
          Resource: '*',
        }),
      ),
    },
  }),
);

As for your issue where it is pointing to the stack, this is because the stack has no matching resources for what you are expecting. It points to the stack as this is what is being tested and it's there (a bit misleadingly) to indicate that the stack may be the issue. Although it seems your issue is just that you are using the wrong method to test with.

Also, the error messages need a bit of work. They really aren't that helpful and many are misleading. Numerous times I have run into:

TypeError: Converting circular structure to JSON

When using object expectancy. Normally this is because a value does not match but the error is completely useless... I cannot count how many times this has caused me a headache...

Reference: https://www.npmjs.com/package/@aws-cdk/assert

Related