javascripttypescriptaws-cdk

Assert that Template.fromStack() contains resources with specified logical ids


I'm refactoring a cdk stack in ts that has hit the resource limit. Since it contains stateful resources, I want to be sure that the refactored stack refers to the same resources, and not new resources, which could trigger undesirable outcomes, such as orphaning or deletion.

To address this, I'm looking to write a unit test that asserts that the template generated from a stack contains resources with a given set of logical ids. I've seen ways to assert that resources with given properties exist, but not that resources with given ids exist.

How can I check that a stack contains resources with given logicalIds? I want to do something like the below:


describe('MyStack', () => {
  test('synthesizes with expected logical IDs', () => {
    const app = new cdk.App();
    const stack = new MyStack(app, 'MyStackDev', {
      deploymentEnvironment: 'dev',
    });

    const template = Template.fromStack(stack);

    const expectedLogicalIds = [
      apiGatewayDev,
      lambdaDev,
      webSocketLambdaDev,
      devLambdaWithConcurrentProvisioning,
      neptuneBastionHostDev,
      neptuneClusterDev,
      auroraClusterDev,
      sevenndevimages,
      sevenndevprivate,
      sparkQueryLogs,
      shareLinks,
      webSocketInstances,
      flowInteractionLog,
    ];

    expectedLogicalIds.forEach((logicalId) => {
      // NOTE: if I need to apply the type, then I'll need to do some more work
      //       to make sure the right type is matched with the right logical id
      //       either way, I don't expect it to work as written because I don't
      //       believe this is proper usage of hasResourceProperties, as the 
      //       logical id is actually the key of the resource object
      expect(
        template.hasResourceProperties('AWS::Lambda::Function', { LogicalId: logicalId }),
      ).toBeTruthy();
    });
  });
});

Solution

  • I would argue you do need to make sure the resource type matches as well if you want to be safe.

    You can use .templateMatches() to check the logical IDs:

    expect(
      template.templateMatches({
        Resources: {
          // This is your logical ID, which is the key of the resource object
          [lambdaDev]: {
            Type: "AWS::Lambda::Function",
          },
        },
      }),
    ).toBeTruthy();
    

    This will work, because you can specify a subset of the template. From the docs:

    By default, the templateMatches() API will use the an 'object-like' comparison, which means that it will allow for the actual template to be a superset of the given expectation.