What is the best way to check the value of a Reference type in a CDK stack

I have successfully created resources using the aws cdk library. I am now facing an issue with testing a stack that contains multiple resources. When testing a single resource, everything works fine, but I'm unsure how to test a stack with multiple resources.

Here is the code used to create the 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
    });
}

When attempting to test the stack, the following code fails due to a reference within the stack:

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' }");
});

The error received is:

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)

Any assistance on resolving this issue would be greatly appreciated. Alternatively, is there a way to test a specific property for a resource type?

Answer №1

In my exploration, I have identified various approaches for testing property references in code. Surprisingly, there appears to be a lack of documented best practices in this area. This could be due to the fact that, for the most part, testing such implementation details may not be necessary.

Approach 1: Export the source Construct from its Stack and then resolve its Token value.

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

Approach 2: Similar to the first approach, but utilizing escape hatches instead of field export to obtain the queue reference.

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

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

Approach 3: Locate the name of the queue resource within 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'],},
});

Answer №2

When you utilize the new Capture() method, you can effectively test various properties related to a specific resource type, output, mapping, and more as specified in the AWS documentation.

Check out the example below that demonstrates how it can be used for testing purposes.

describe.each(['env1', 'env2'])('Testing the allowed %s Parameter Store resource', env => {
  const nestedStack = createTestStack(env);
  it(`should conform to the specified name pattern`, () => {
    // given
    const template = Template.fromStack(nestedStack);
    const nameCapture = new Capture();  // one capture per value
    const valueCapture = new Capture(); 

    // when
    template.hasResourceProperties('AWS::SSM::Parameter', {
      Name: nameCapture,
      Value: valueCapture
    });

    // then
    expect(nameCapture.asString()).toEqual(`/${env}/allowed/demo`);
    expect(valueCapture.asString()).toMatch(<regExPatternHere>);
  });

Take a look at this code snippet utilizing Capture()

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);
      const nameCapture = new Capture;
      const valueCapture = new Capture;
      const typeCapture = new Capture;

      template.hasResourceProperties(ResourceTypes.SSM_PARAM_TYPE,
        "{ 
        Name: nameCapture, 
        Value: valueCapture,
        Type: typeCapture 
        ");

        //run test here on individual values if desired 
      });

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Tips for utilizing the 'crypto' module within Angular2?

After running the command for module installation: npm install --save crypto I attempted to import it into my component like this: import { createHmac } from "crypto"; However, I encountered the following error: ERROR in -------------- (4,28): Canno ...

Injecting Dependencies in Angular 2 Without Using the Constructor

Exploring DI in Angular 2 has led me to implement a REST-Client using generic subtypes for concrete Datatypes like this: class RESTClient<T>{ constructor() { var inj = ReflectiveInjector.resolveAndCreate([HTTP_PROVIDERS]); this. ...

What could be causing my NextJS application to not recognize the _document.tsx file?

Seeking assistance in understanding why my _document.tsx is not loading properly within my nextJS application. My Attempts So Far I have been diligently following the NextJS documentation for creating a custom _document.js. Despite my efforts, I am unable ...

Accessing Child Properties in Parent Component using Typescript

New to the world of Typescript! Imagine having a component called TitleSubtitle that consists of both a Title and a Subtitle component. The Title component comes with props: interface TitleProps { text: string; } The Subtitle component also has props ...

Dismiss the necessity of imports in Angular

I am facing an issue with using a library in Angular, specifically the cubing npm package. This library is designed to run in both the browser and node environments, with specific code for each. I want it to run in the browser, but when compiling with Angu ...

The data type '{ [key: string]: number; }' cannot be assigned to type 'T'

I’m working with a complex TypeScript type and trying to manage it within a function. Here’s what I have: type T = { a: number } | { b: number } function func(k: 'a' | 'b', v: number) { // error message below const t: T = { ...

Are there problems with the response values of functions that can handle varying object interfaces?

Currently in the process of developing a command line blackjack app with Node and Typescript, even though I am relatively new to Typescript. My main challenge lies in implementing interfaces for player and dealer objects, as well as creating functions that ...

Tips for retrieving information from a Vuetify modal window

Is it possible to retrieve data from a dialog in the VueJS Vuetify framework? Specifically, how can I access the username or password entered in the NewUserPopup.vue dialog from app.vue? App.vue = main template NewUserPopup.vue = Dialog template imported ...

Struggled with the implementation of a customized Angular filter pipe

I have recently developed a custom filter type to sort the notes-list in my application, with each note containing a 'title' and 'message'. Although there are no errors, I am facing issues as the pipe doesn't seem to be working pr ...

The Observable merge operation encountered an error: it cannot access the 'apply' property of an undefined value

I am currently working on setting up a sorted DataTable in an angular application, and while implementing it using this example, I encountered the following error: ERROR TypeError: Cannot read property 'apply' of undefined at TableDataSource ...

Implement dynamic validation in Angular 4 based on specific conditions

I am looking to implement Angular 4 validation dynamically based on specific conditions within a Reactive form. Here is the scenario: There is a radio button with options: A: yes B: no If the user selects "yes", a textbox (formControlName="your_name") wil ...

Guide to accessing a menu through Long press or Right click in Angular2

I recently started experimenting with angular 2 and I am trying to figure out how to create a menu that opens with multiple options on both mobile and desktop devices. What I'm looking for is a way to trigger the opening of a menu when a long hold or ...

What is causing the "excessive stack depth" error in this JSX code?

Exploring Next.js' TypeScript (4.2.3) functionality, I am utilizing it to compile the React component provided below. const Component = (): JSX.Element => { const categories = ['Fruit', 'Vegetables']; return ( <ul> ...

Tips for properly importing types from external dependencies in TypeScript

I am facing an issue with handling types in my project. The structure is such that I have packageA -> packageB-v1 -> packageC-v1, and I need to utilize a type declared in packageC-v1 within packageA. All the packages are custom-made TypeScript packa ...

What is the importance of moving prop types into a type or interface in React components?

Consider the scenario where I have a functional component: const MyText = ({ value }) => ( <div className="my-fancy-text">{value}</div> ); Now, when utilizing Typescript, I face the need to introduce typing. A straightforward ...

Angular 13: Issue with displaying lazy loaded module containing multiple outlets in a component

Angular version ^13.3.9 Challenge Encountering an issue when utilizing multiple outlets and attempting to render them in a lazy module with the Angular router. The routes are being mapped correctly, but the outlet itself is not being displayed. Sequence ...

Tips on avoiding issues with the backslash character in Typescript

Can someone help me with creating a regular expression in Typescript that can match the decimal separator character followed by a sequence of zeros in a string? I have tried to come up with an expression as shown below: /\.0+\b/g However, since ...

Ways to prevent scrolling in Angular 6 when no content is available

I am developing an angular 6 application where I have scrollable divs containing: HTML: <button class="lefty paddle" id="left-button"> PREVIOUS </button> <div class="container"> <div class="inner" style="background:red">< ...

Ways to utilize the useRef method within the useContext hook while implementing Typescript

Struggling to incorporate useRef into my global Next.js useContext function while utilizing TypeScript. Attempted approach and encountered errors: interface tripAttributes{ tripTitle: string } const initialTripState: tripAttributes = { tripTitle ...

Modifying the return type of an observable using the map operator

I have been investigating how to modify the return type of an Observable. My current framework is Angular 5. Let's take a look at this example: public fetchButterflyData(): Observable<Butterfly[]> { return http.get<Larva[]>('u ...