awscdkassertionsalpha

package module
v2.0.0-rc.24 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 13, 2021 License: Apache-2.0 Imports: 4 Imported by: 0

README

Assertions


The APIs of higher level constructs in this module are experimental and under active development. They are subject to non-backward compatible changes or removal in any future version. These are not subject to the Semantic Versioning model and breaking changes will be announced in the release notes. This means that while you may use them, you may need to update your source code when upgrading to a newer version of this package.


Functions for writing test asserting against CDK applications, with focus on CloudFormation templates.

The Template class includes a set of methods for writing assertions against CloudFormation templates. Use one of the Template.fromXxx() static methods to create an instance of this class.

To create Template from CDK stack, start off with:

import { Stack } from '@aws-cdk/core';
import { Template } from '@aws-cdk/assertions';

const stack = new Stack(/* ... */);
// ...
const template = Template.fromStack(stack);

Alternatively, assertions can be run on an existing CloudFormation template -

const templateJson = '{ "Resources": ... }'; /* The CloudFormation template as JSON serialized string. */
const template = Template.fromString(templateJson);

Full Template Match

The simplest assertion would be to assert that the template matches a given template.

const expected = {
  Resources: {
    Type: 'Foo::Bar',
    Properties: {
      Baz: 'Qux',
    },
  },
};

template.templateMatches(expected);

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. See Special Matchers for details on how to change this.

Snapshot testing is a common technique to store a snapshot of the output and compare it during future changes. Since CloudFormation templates are human readable, they are a good target for åßsnapshot testing.

The toJSON() method on the Template can be used to produce a well formatted JSON of the CloudFormation template that can be used as a snapshot.

See Snapshot Testing in Jest and Snapshot Testing in Java.

Counting Resources

This module allows asserting the number of resources of a specific type found in a template.

template.resourceCountIs('Foo::Bar', 2);

Resource Matching & Retrieval

Beyond resource counting, the module also allows asserting that a resource with specific properties are present.

The following code asserts that the Properties section of a resource of type Foo::Bar contains the specified properties -

const expected = {
  Foo: 'Bar',
  Baz: 5,
  Qux: [ 'Waldo', 'Fred' ],
};
template.hasResourceProperties('Foo::Bar', expected);

Alternatively, if you would like to assert the entire resource definition, you can use the hasResource() API.

const expected = {
  Properties: { Foo: 'Bar' },
  DependsOn: [ 'Waldo', 'Fred' ],
};
template.hasResource('Foo::Bar', expected);

Beyond assertions, the module provides APIs to retrieve matching resources. The findResources() API is complementary to the hasResource() API, except, instead of asserting its presence, it returns the set of matching resources.

By default, the hasResource() and hasResourceProperties() APIs perform deep partial object matching. This behavior can be configured using matchers. See subsequent section on special matchers.

Output and Mapping sections

The module allows you to assert that the CloudFormation template contains an Output that matches specific properties. The following code asserts that a template contains an Output with a logicalId of Foo and the specified properties -

const expected = {
  Value: 'Bar',
  Export: { Name: 'ExportBaz' },
};
template.hasOutput('Foo', expected);

If you want to match against all Outputs in the template, use * as the logicalId.

const expected = {
  Value: 'Bar',
  Export: { Name: 'ExportBaz' },
};
template.hasOutput('*', expected);

findOutputs() will return a set of outputs that match the logicalId and props, and you can use the '*' special case as well.

const expected = {
  Value: 'Fred',
};
const result = template.findOutputs('*', expected);
expect(result.Foo).toEqual({ Value: 'Fred', Description: 'FooFred' });
expect(result.Bar).toEqual({ Value: 'Fred', Description: 'BarFred' });

The APIs hasMapping() and findMappings() provide similar functionalities.

Special Matchers

The expectation provided to the hasXxx(), findXxx() and templateMatches() APIs, besides carrying literal values, as seen in the above examples, also accept special matchers.

They are available as part of the Match class.

Object Matchers

The Match.objectLike() API can be used to assert that the target is a superset object of the provided pattern. This API will perform a deep partial match on the target. Deep partial matching is where objects are matched partially recursively. At each level, the list of keys in the target is a subset of the provided pattern.

// Given a template -
// {
//   "Resources": {
//     "MyBar": {
//       "Type": "Foo::Bar",
//       "Properties": {
//         "Fred": {
//           "Wobble": "Flob",
//           "Bob": "Cat"
//         }
//       }
//     }
//   }
// }

// The following will NOT throw an assertion error
const expected = {
  Fred: Match.objectLike({
    Wobble: 'Flob',
  }),
};
template.hasResourceProperties('Foo::Bar', expected);

// The following will throw an assertion error
const unexpected = {
  Fred: Match.objectLike({
    Brew: 'Coffee',
  }),
}
template.hasResourceProperties('Foo::Bar', unexpected);

The Match.objectEquals() API can be used to assert a target as a deep exact match.

Presence and Absence

The Match.absent() matcher can be used to specify that a specific value should not exist on the target. This can be used within Match.objectLike() or outside of any matchers.

// Given a template -
// {
//   "Resources": {
//     "MyBar": {
//       "Type": "Foo::Bar",
//       "Properties": {
//         "Fred": {
//           "Wobble": "Flob",
//         }
//       }
//     }
//   }
// }

// The following will NOT throw an assertion error
const expected = {
  Fred: Match.objectLike({
    Bob: Match.absent(),
  }),
};
template.hasResourceProperties('Foo::Bar', expected);

// The following will throw an assertion error
const unexpected = {
  Fred: Match.objectLike({
    Wobble: Match.absent(),
  }),
};
template.hasResourceProperties('Foo::Bar', unexpected);

The Match.anyValue() matcher can be used to specify that a specific value should be found at the location. This matcher will fail if when the target location has null-ish values (i.e., null or undefined).

This matcher can be combined with any of the other matchers.

// Given a template -
// {
//   "Resources": {
//     "MyBar": {
//       "Type": "Foo::Bar",
//       "Properties": {
//         "Fred": {
//           "Wobble": ["Flob", "Flib"],
//         }
//       }
//     }
//   }
// }

// The following will NOT throw an assertion error
const expected = {
  Fred: {
    Wobble: [Match.anyValue(), "Flip"],
  },
};
template.hasResourceProperties('Foo::Bar', expected);

// The following will throw an assertion error
const unexpected = {
  Fred: {
    Wimble: Match.anyValue(),
  },
};
template.hasResourceProperties('Foo::Bar', unexpected);
Array Matchers

The Match.arrayWith() API can be used to assert that the target is equal to or a subset of the provided pattern array. This API will perform subset match on the target.

// Given a template -
// {
//   "Resources": {
//     "MyBar": {
//       "Type": "Foo::Bar",
//       "Properties": {
//         "Fred": ["Flob", "Cat"]
//       }
//     }
//   }
// }

// The following will NOT throw an assertion error
const expected = {
  Fred: Match.arrayWith(['Flob']),
};
template.hasResourceProperties('Foo::Bar', expected);

// The following will throw an assertion error
const unexpected = Match.objectLike({
  Fred: Match.arrayWith(['Wobble']),
});
template.hasResourceProperties('Foo::Bar', unexpected);

Note: The list of items in the pattern array should be in order as they appear in the target array. Out of order will be recorded as a match failure.

Alternatively, the Match.arrayEquals() API can be used to assert that the target is exactly equal to the pattern array.

Not Matcher

The not matcher inverts the search pattern and matches all patterns in the path that does not match the pattern specified.

// Given a template -
// {
//   "Resources": {
//     "MyBar": {
//       "Type": "Foo::Bar",
//       "Properties": {
//         "Fred": ["Flob", "Cat"]
//       }
//     }
//   }
// }

// The following will NOT throw an assertion error
const expected = {
  Fred: Match.not(['Flob']),
};
template.hasResourceProperties('Foo::Bar', expected);

// The following will throw an assertion error
const unexpected = Match.objectLike({
  Fred: Match.not(['Flob', 'Cat']),
});
template.hasResourceProperties('Foo::Bar', unexpected);
Serialized JSON

Often, we find that some CloudFormation Resource types declare properties as a string, but actually expect JSON serialized as a string. For example, the BuildSpec property of AWS::CodeBuild::Project, the Definition property of AWS::StepFunctions::StateMachine, to name a couple.

The Match.serializedJson() matcher allows deep matching within a stringified JSON.

// Given a template -
// {
//   "Resources": {
//     "MyBar": {
//       "Type": "Foo::Bar",
//       "Properties": {
//         "Baz": "{ \"Fred\": [\"Waldo\", \"Willow\"] }"
//       }
//     }
//   }
// }

// The following will NOT throw an assertion error
const expected = {
  Baz: Match.serializedJson({
    Fred: Match.arrayWith(["Waldo"]),
  }),
};
template.hasResourceProperties('Foo::Bar', expected);

// The following will throw an assertion error
const unexpected = {
  Baz: Match.serializedJson({
    Fred: ["Waldo", "Johnny"],
  }),
};
template.hasResourceProperties('Foo::Bar', unexpected);

Capturing Values

This matcher APIs documented above allow capturing values in the matching entry (Resource, Output, Mapping, etc.). The following code captures a string from a matching resource.

// Given a template -
// {
//   "Resources": {
//     "MyBar": {
//       "Type": "Foo::Bar",
//       "Properties": {
//         "Fred": ["Flob", "Cat"],
//         "Waldo": ["Qix", "Qux"],
//       }
//     }
//   }
// }

const fredCapture = new Capture();
const waldoCapture = new Capture();
const expected = {
  Fred: fredCapture,
  Waldo: ["Qix", waldoCapture],
}
template.hasResourceProperties('Foo::Bar', expected);

fredCapture.asArray(); // returns ["Flob", "Cat"]
waldoCapture.asString(); // returns "Qux"

Documentation

Overview

An assertion library for use with CDK Apps

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Capture_IsMatcher

func Capture_IsMatcher(x interface{}) *bool

Check whether the provided object is a subtype of the `IMatcher`. Experimental.

func Matcher_IsMatcher

func Matcher_IsMatcher(x interface{}) *bool

Check whether the provided object is a subtype of the `IMatcher`. Experimental.

func NewCapture_Override

func NewCapture_Override(c Capture)

Experimental.

func NewMatchResult_Override

func NewMatchResult_Override(m MatchResult, target interface{})

Experimental.

func NewMatch_Override

func NewMatch_Override(m Match)

Experimental.

func NewMatcher_Override

func NewMatcher_Override(m Matcher)

Experimental.

Types

type Capture

type Capture interface {
	Matcher
	Name() *string
	AsArray() *[]interface{}
	AsBoolean() *bool
	AsNumber() *float64
	AsObject() *map[string]interface{}
	AsString() *string
	Test(actual interface{}) MatchResult
}

Capture values while matching templates.

Using an instance of this class within a Matcher will capture the matching value. The `as*()` APIs on the instance can be used to get the captured value. Experimental.

func NewCapture

func NewCapture() Capture

Experimental.

type Match

type Match interface {
}

Partial and special matching during template assertions. Experimental.

type MatchResult

type MatchResult interface {
	FailCount() *float64
	Target() interface{}
	Compose(id *string, inner MatchResult) MatchResult
	HasFailed() *bool
	Push(matcher Matcher, path *[]*string, message *string) MatchResult
	ToHumanStrings() *[]*string
}

The result of `Match.test()`. Experimental.

func NewMatchResult

func NewMatchResult(target interface{}) MatchResult

Experimental.

type Matcher

type Matcher interface {
	Name() *string
	Test(actual interface{}) MatchResult
}

Represents a matcher that can perform special data matching capabilities between a given pattern and a target. Experimental.

func Match_Absent

func Match_Absent() Matcher

Use this matcher in the place of a field's value, if the field must not be present. Experimental.

func Match_AnyValue

func Match_AnyValue() Matcher

Matches any non-null value at the target. Experimental.

func Match_ArrayEquals

func Match_ArrayEquals(pattern *[]interface{}) Matcher

Matches the specified pattern with the array found in the same relative path of the target.

The set of elements (or matchers) must match exactly and in order. Experimental.

func Match_ArrayWith

func Match_ArrayWith(pattern *[]interface{}) Matcher

Matches the specified pattern with the array found in the same relative path of the target.

The set of elements (or matchers) must be in the same order as would be found. Experimental.

func Match_Exact

func Match_Exact(pattern interface{}) Matcher

Deep exact matching of the specified pattern to the target. Experimental.

func Match_Not

func Match_Not(pattern interface{}) Matcher

Matches any target which does NOT follow the specified pattern. Experimental.

func Match_ObjectEquals

func Match_ObjectEquals(pattern *map[string]interface{}) Matcher

Matches the specified pattern to an object found in the same relative path of the target.

The keys and their values (or matchers) must match exactly with the target. Experimental.

func Match_ObjectLike

func Match_ObjectLike(pattern *map[string]interface{}) Matcher

Matches the specified pattern to an object found in the same relative path of the target.

The keys and their values (or matchers) must be present in the target but the target can be a superset. Experimental.

func Match_SerializedJson

func Match_SerializedJson(pattern interface{}) Matcher

Matches any string-encoded JSON and applies the specified pattern after parsing it. Experimental.

type Template

type Template interface {
	FindMappings(logicalId *string, props interface{}) *map[string]*map[string]interface{}
	FindOutputs(logicalId *string, props interface{}) *map[string]*map[string]interface{}
	FindResources(type_ *string, props interface{}) *map[string]*map[string]interface{}
	HasMapping(logicalId *string, props interface{})
	HasOutput(logicalId *string, props interface{})
	HasResource(type_ *string, props interface{})
	HasResourceProperties(type_ *string, props interface{})
	ResourceCountIs(type_ *string, count *float64)
	TemplateMatches(expected interface{})
	ToJSON() *map[string]interface{}
}

Suite of assertions that can be run on a CDK stack.

Typically used, as part of unit tests, to validate that the rendered CloudFormation template has expected resources and properties. Experimental.

func Template_FromJSON

func Template_FromJSON(template *map[string]interface{}) Template

Base your assertions from an existing CloudFormation template formatted as an in-memory JSON object. Experimental.

func Template_FromStack

func Template_FromStack(stack awscdk.Stack) Template

Base your assertions on the CloudFormation template synthesized by a CDK `Stack`. Experimental.

func Template_FromString

func Template_FromString(template *string) Template

Base your assertions from an existing CloudFormation template formatted as a JSON string. Experimental.

Directories

Path Synopsis
Package jsii contains the functionaility needed for jsii packages to initialize their dependencies and themselves.
Package jsii contains the functionaility needed for jsii packages to initialize their dependencies and themselves.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL