# Assertions
<!--BEGIN STABILITY BANNER-->---

> 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](https://semver.org/) 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.
---
<!--END STABILITY BANNER-->
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:
```python
# Example automatically generated. See https://github.com/aws/jsii/issues/826
from aws_cdk.core import Stack
from aws_cdk.assertions import Template
stack = Stack()
# ...
template = Template.from_stack(stack)
```
Alternatively, assertions can be run on an existing CloudFormation template -
```python
# Example automatically generated. See https://github.com/aws/jsii/issues/826
template_json = "{ \"Resources\": ... }"# The CloudFormation template as JSON serialized string.
template = Template.from_string(template_json)
```
## Full Template Match
The simplest assertion would be to assert that the template matches a given
template.
```python
# Example automatically generated. See https://github.com/aws/jsii/issues/826
expected = {
"Resources": {
"Type": "Foo::Bar",
"Properties": {
"Baz": "Qux"
}
}
}
template.template_matches(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](#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](https://jestjs.io/docs/snapshot-testing) and [Snapshot
Testing in Java](https://json-snapshot.github.io/).
## Counting Resources
This module allows asserting the number of resources of a specific type found
in a template.
```python
# Example automatically generated. See https://github.com/aws/jsii/issues/826
template.resource_count_is("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 -
```python
# Example automatically generated. See https://github.com/aws/jsii/issues/826
expected = {
"Foo": "Bar",
"Baz": 5,
"Qux": ["Waldo", "Fred"]
}
template.has_resource_properties("Foo::Bar", expected)
```
Alternatively, if you would like to assert the entire resource definition, you
can use the `hasResource()` API.
```python
# Example automatically generated. See https://github.com/aws/jsii/issues/826
expected = {
"Properties": {"Foo": "Bar"},
"DependsOn": ["Waldo", "Fred"]
}
template.has_resource("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](#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 -
```python
# Example automatically generated. See https://github.com/aws/jsii/issues/826
expected = {
"Value": "Bar",
"Export": {"Name": "ExportBaz"}
}
template.has_output("Foo", expected)
```
If you want to match against all Outputs in the template, use `*` as the `logicalId`.
```python
# Example automatically generated. See https://github.com/aws/jsii/issues/826
expected = {
"Value": "Bar",
"Export": {"Name": "ExportBaz"}
}
template.has_output("*", expected)
```
`findOutputs()` will return a set of outputs that match the `logicalId` and `props`,
and you can use the `'*'` special case as well.
```python
# Example automatically generated. See https://github.com/aws/jsii/issues/826
expected = {
"Value": "Fred"
}
result = template.find_outputs("*", expected)
expect(result.Foo).to_equal({"Value": "Fred", "Description": "FooFred"})
expect(result.Bar).to_equal({"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.
```python
# Example automatically generated. See https://github.com/aws/jsii/issues/826
# Given a template -
# {
# "Resources": {
# "MyBar": {
# "Type": "Foo::Bar",
# "Properties": {
# "Fred": {
# "Wobble": "Flob",
# "Bob": "Cat"
# }
# }
# }
# }
# }
# The following will NOT throw an assertion error
expected = {
"Fred": Match.object_like({
"Wobble": "Flob"
})
}
template.has_resource_properties("Foo::Bar", expected)
# The following will throw an assertion error
unexpected = {
"Fred": Match.object_like({
"Brew": "Coffee"
})
}
template.has_resource_properties("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.
```python
# Example automatically generated. See https://github.com/aws/jsii/issues/826
# Given a template -
# {
# "Resources": {
# "MyBar": {
# "Type": "Foo::Bar",
# "Properties": {
# "Fred": {
# "Wobble": "Flob",
# }
# }
# }
# }
# }
# The following will NOT throw an assertion error
expected = {
"Fred": Match.object_like({
"Bob": Match.absent()
})
}
template.has_resource_properties("Foo::Bar", expected)
# The following will throw an assertion error
unexpected = {
"Fred": Match.object_like({
"Wobble": Match.absent()
})
}
template.has_resource_properties("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.
```python
# Example automatically generated. See https://github.com/aws/jsii/issues/826
# Given a template -
# {
# "Resources": {
# "MyBar": {
# "Type": "Foo::Bar",
# "Properties": {
# "Fred": {
# "Wobble": ["Flob", "Flib"],
# }
# }
# }
# }
# }
# The following will NOT throw an assertion error
expected = {
"Fred": {
"Wobble": [Match.any_value(), "Flip"]
}
}
template.has_resource_properties("Foo::Bar", expected)
# The following will throw an assertion error
unexpected = {
"Fred": {
"Wimble": Match.any_value()
}
}
template.has_resource_properties("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.
```python
# Example automatically generated. See https://github.com/aws/jsii/issues/826
# Given a template -
# {
# "Resources": {
# "MyBar": {
# "Type": "Foo::Bar",
# "Properties": {
# "Fred": ["Flob", "Cat"]
# }
# }
# }
# }
# The following will NOT throw an assertion error
expected = {
"Fred": Match.array_with(["Flob"])
}
template.has_resource_properties("Foo::Bar", expected)
# The following will throw an assertion error
unexpected = Match.object_like({
"Fred": Match.array_with(["Wobble"])
})
template.has_resource_properties("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.
```python
# Example automatically generated. See https://github.com/aws/jsii/issues/826
# Given a template -
# {
# "Resources": {
# "MyBar": {
# "Type": "Foo::Bar",
# "Properties": {
# "Fred": ["Flob", "Cat"]
# }
# }
# }
# }
# The following will NOT throw an assertion error
expected = {
"Fred": Match.not(["Flob"])
}
template.has_resource_properties("Foo::Bar", expected)
# The following will throw an assertion error
unexpected = Match.object_like({
"Fred": Match.not(["Flob", "Cat"])
})
template.has_resource_properties("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`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-codebuild-project-source.html#cfn-codebuild-project-source-buildspec),
the [`Definition` property of `AWS::StepFunctions::StateMachine`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-definition),
to name a couple.
The `Match.serializedJson()` matcher allows deep matching within a stringified JSON.
```python
# Example automatically generated. See https://github.com/aws/jsii/issues/826
# Given a template -
# {
# "Resources": {
# "MyBar": {
# "Type": "Foo::Bar",
# "Properties": {
# "Baz": "{ \"Fred\": [\"Waldo\", \"Willow\"] }"
# }
# }
# }
# }
# The following will NOT throw an assertion error
expected = {
"Baz": Match.serialized_json({
"Fred": Match.array_with(["Waldo"])
})
}
template.has_resource_properties("Foo::Bar", expected)
# The following will throw an assertion error
unexpected = {
"Baz": Match.serialized_json({
"Fred": ["Waldo", "Johnny"]
})
}
template.has_resource_properties("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.
```python
# Example automatically generated. See https://github.com/aws/jsii/issues/826
# Given a template -
# {
# "Resources": {
# "MyBar": {
# "Type": "Foo::Bar",
# "Properties": {
# "Fred": ["Flob", "Cat"],
# "Waldo": ["Qix", "Qux"],
# }
# }
# }
# }
fred_capture = Capture()
waldo_capture = Capture()
expected = {
"Fred": fred_capture,
"Waldo": ["Qix", waldo_capture]
}
template.has_resource_properties("Foo::Bar", expected)
fred_capture.as_array()# returns ["Flob", "Cat"]
waldo_capture.as_string()
```