# Assertions
<!--BEGIN STABILITY BANNER-->---
![cdk-constructs: Stable](https://img.shields.io/badge/cdk--constructs-stable-success.svg?style=for-the-badge)
---
<!--END STABILITY BANNER-->
If you're migrating from the old `assert` library, the migration guide can be found in
[our GitHub repository](https://github.com/aws/aws-cdk/blob/master/packages/@aws-cdk/assertions/MIGRATING.md).
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
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
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
template.template_matches({
"Resources": {
"BarLogicalId": {
"Type": "Foo::Bar",
"Properties": {
"Baz": "Qux"
}
}
}
})
```
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
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
template.has_resource_properties("Foo::Bar", {
"Foo": "Bar",
"Baz": 5,
"Qux": ["Waldo", "Fred"]
})
```
Alternatively, if you would like to assert the entire resource definition, you
can use the `hasResource()` API.
```python
template.has_resource("Foo::Bar", {
"Properties": {"Foo": "Bar"},
"DependsOn": ["Waldo", "Fred"]
})
```
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
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
template.has_output("*", {
"Value": "Bar",
"Export": {"Name": "ExportBaz"}
})
```
`findOutputs()` will return a set of outputs that match the `logicalId` and `props`,
and you can use the `'*'` special case as well.
```python
result = template.find_outputs("*", {"Value": "Fred"})
expect(result.Foo).to_equal({"Value": "Fred", "Description": "FooFred"})
expect(result.Bar).to_equal({"Value": "Fred", "Description": "BarFred"})
```
The APIs `hasMapping()`, `findMappings()`, `hasCondition()`, and `hasCondtions()` 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
# Given a template -
# {
# "Resources": {
# "MyBar": {
# "Type": "Foo::Bar",
# "Properties": {
# "Fred": {
# "Wobble": "Flob",
# "Bob": "Cat"
# }
# }
# }
# }
# }
# The following will NOT throw an assertion error
template.has_resource_properties("Foo::Bar", {
"Fred": Match.object_like({
"Wobble": "Flob"
})
})
# The following will throw an assertion error
template.has_resource_properties("Foo::Bar", {
"Fred": Match.object_like({
"Brew": "Coffee"
})
})
```
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
# Given a template -
# {
# "Resources": {
# "MyBar": {
# "Type": "Foo::Bar",
# "Properties": {
# "Fred": {
# "Wobble": "Flob",
# }
# }
# }
# }
# }
# The following will NOT throw an assertion error
template.has_resource_properties("Foo::Bar", {
"Fred": Match.object_like({
"Bob": Match.absent()
})
})
# The following will throw an assertion error
template.has_resource_properties("Foo::Bar", {
"Fred": Match.object_like({
"Wobble": Match.absent()
})
})
```
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
# Given a template -
# {
# "Resources": {
# "MyBar": {
# "Type": "Foo::Bar",
# "Properties": {
# "Fred": {
# "Wobble": ["Flob", "Flib"],
# }
# }
# }
# }
# }
# The following will NOT throw an assertion error
template.has_resource_properties("Foo::Bar", {
"Fred": {
"Wobble": [Match.any_value(), Match.any_value()]
}
})
# The following will throw an assertion error
template.has_resource_properties("Foo::Bar", {
"Fred": {
"Wimble": Match.any_value()
}
})
```
### 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
# Given a template -
# {
# "Resources": {
# "MyBar": {
# "Type": "Foo::Bar",
# "Properties": {
# "Fred": ["Flob", "Cat"]
# }
# }
# }
# }
# The following will NOT throw an assertion error
template.has_resource_properties("Foo::Bar", {
"Fred": Match.array_with(["Flob"])
})
# The following will throw an assertion error
template.has_resource_properties("Foo::Bar", Match.object_like({
"Fred": Match.array_with(["Wobble"])
}))
```
*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.
### String Matchers
The `Match.stringLikeRegexp()` API can be used to assert that the target matches the
provided regular expression.
```python
# Given a template -
# {
# "Resources": {
# "MyBar": {
# "Type": "Foo::Bar",
# "Properties": {
# "Template": "const includeHeaders = true;"
# }
# }
# }
# }
# The following will NOT throw an assertion error
template.has_resource_properties("Foo::Bar", {
"Template": Match.string_like_regexp("includeHeaders = (true|false)")
})
# The following will throw an assertion error
template.has_resource_properties("Foo::Bar", {
"Template": Match.string_like_regexp("includeHeaders = null")
})
```
### Not Matcher
The not matcher inverts the search pattern and matches all patterns in the path that does
not match the pattern specified.
```python
# Given a template -
# {
# "Resources": {
# "MyBar": {
# "Type": "Foo::Bar",
# "Properties": {
# "Fred": ["Flob", "Cat"]
# }
# }
# }
# }
# The following will NOT throw an assertion error
template.has_resource_properties("Foo::Bar", {
"Fred": Match.not(["Flob"])
})
# The following will throw an assertion error
template.has_resource_properties("Foo::Bar", Match.object_like({
"Fred": Match.not(["Flob", "Cat"])
}))
```
### 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
# Given a template -
# {
# "Resources": {
# "MyBar": {
# "Type": "Foo::Bar",
# "Properties": {
# "Baz": "{ \"Fred\": [\"Waldo\", \"Willow\"] }"
# }
# }
# }
# }
# The following will NOT throw an assertion error
template.has_resource_properties("Foo::Bar", {
"Baz": Match.serialized_json({
"Fred": Match.array_with(["Waldo"])
})
})
# The following will throw an assertion error
template.has_resource_properties("Foo::Bar", {
"Baz": Match.serialized_json({
"Fred": ["Waldo", "Johnny"]
})
})
```
## Capturing Values
The 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
# Given a template -
# {
# "Resources": {
# "MyBar": {
# "Type": "Foo::Bar",
# "Properties": {
# "Fred": ["Flob", "Cat"],
# "Waldo": ["Qix", "Qux"],
# }
# }
# }
# }
fred_capture = Capture()
waldo_capture = Capture()
template.has_resource_properties("Foo::Bar", {
"Fred": fred_capture,
"Waldo": ["Qix", waldo_capture]
})
fred_capture.as_array() # returns ["Flob", "Cat"]
waldo_capture.as_string()
```
With captures, a nested pattern can also be specified, so that only targets
that match the nested pattern will be captured. This pattern can be literals or
further Matchers.
```python
# Given a template -
# {
# "Resources": {
# "MyBar1": {
# "Type": "Foo::Bar",
# "Properties": {
# "Fred": ["Flob", "Cat"],
# }
# }
# "MyBar2": {
# "Type": "Foo::Bar",
# "Properties": {
# "Fred": ["Qix", "Qux"],
# }
# }
# }
# }
capture = Capture(Match.array_with(["Cat"]))
template.has_resource_properties("Foo::Bar", {
"Fred": capture
})
capture.as_array()
```
When multiple resources match the given condition, each `Capture` defined in
the condition will capture all matching values. They can be paged through using
the `next()` API. The following example illustrates this -
```python
# Given a template -
# {
# "Resources": {
# "MyBar": {
# "Type": "Foo::Bar",
# "Properties": {
# "Fred": "Flob",
# }
# },
# "MyBaz": {
# "Type": "Foo::Bar",
# "Properties": {
# "Fred": "Quib",
# }
# }
# }
# }
fred_capture = Capture()
template.has_resource_properties("Foo::Bar", {
"Fred": fred_capture
})
fred_capture.as_string() # returns "Flob"
fred_capture.next() # returns true
fred_capture.as_string()
```
## Asserting Annotations
In addition to template matching, we provide an API for annotation matching.
[Annotations](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.Annotations.html)
can be added via the [Aspects](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.Aspects.html)
API. You can learn more about Aspects [here](https://docs.aws.amazon.com/cdk/v2/guide/aspects.html).
Say you have a `MyAspect` and a `MyStack` that uses `MyAspect`:
```python
import aws_cdk.core as cdk
from constructs import Construct, IConstruct
class MyAspect(cdk.IAspect):
def visit(self, node):
if node instanceof cdk.CfnResource && node.cfn_resource_type == "Foo::Bar":
self.error(node, "we do not want a Foo::Bar resource")
def error(self, node, message):
cdk.Annotations.of(node).add_error(message)
class MyStack(cdk.Stack):
def __init__(self, scope, id):
super().__init__(scope, id)
stack = cdk.Stack()
cdk.CfnResource(stack, "Foo",
type="Foo::Bar",
properties={
"Fred": "Thud"
}
)
cdk.Aspects.of(stack).add(MyAspect())
```
We can then assert that the stack contains the expected Error:
```python
# import { Annotations } from '@aws-cdk/assertions';
Annotations.from_stack(stack).has_error("/Default/Foo", "we do not want a Foo::Bar resource")
```
Here are the available APIs for `Annotations`:
* `hasError()`, `hasNoError()`, and `findError()`
* `hasWarning()`, `hasNoWarning()`, and `findWarning()`
* `hasInfo()`, `hasNoInfo()`, and `findInfo()`
The corresponding `findXxx()` API is complementary to the `hasXxx()` API, except instead
of asserting its presence, it returns the set of matching messages.
In addition, this suite of APIs is compatable with `Matchers` for more fine-grained control.
For example, the following assertion works as well:
```python
Annotations.from_stack(stack).has_error("/Default/Foo",
Match.string_like_regexp(".*Foo::Bar.*"))
```
Raw data
{
"_id": null,
"home_page": "https://github.com/aws/aws-cdk",
"name": "aws-cdk.assertions",
"maintainer": "",
"docs_url": null,
"requires_python": "~=3.7",
"maintainer_email": "",
"keywords": "",
"author": "Amazon Web Services",
"author_email": "",
"download_url": "https://files.pythonhosted.org/packages/8d/98/15ed2e1c3c2791ad6d81320aaa70ada5bf11c6d38c10541466a7fc6bd01f/aws-cdk.assertions-1.203.0.tar.gz",
"platform": null,
"description": "# Assertions\n\n<!--BEGIN STABILITY BANNER-->---\n\n\n![cdk-constructs: Stable](https://img.shields.io/badge/cdk--constructs-stable-success.svg?style=for-the-badge)\n\n---\n<!--END STABILITY BANNER-->\n\nIf you're migrating from the old `assert` library, the migration guide can be found in\n[our GitHub repository](https://github.com/aws/aws-cdk/blob/master/packages/@aws-cdk/assertions/MIGRATING.md).\n\nFunctions for writing test asserting against CDK applications, with focus on CloudFormation templates.\n\nThe `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.\n\nTo create `Template` from CDK stack, start off with:\n\n```python\nfrom aws_cdk.core import Stack\nfrom aws_cdk.assertions import Template\n\nstack = Stack()\n# ...\ntemplate = Template.from_stack(stack)\n```\n\nAlternatively, assertions can be run on an existing CloudFormation template -\n\n```python\ntemplate_json = \"{ \\\"Resources\\\": ... }\" # The CloudFormation template as JSON serialized string.\ntemplate = Template.from_string(template_json)\n```\n\n## Full Template Match\n\nThe simplest assertion would be to assert that the template matches a given\ntemplate.\n\n```python\ntemplate.template_matches({\n \"Resources\": {\n \"BarLogicalId\": {\n \"Type\": \"Foo::Bar\",\n \"Properties\": {\n \"Baz\": \"Qux\"\n }\n }\n }\n})\n```\n\nBy default, the `templateMatches()` API will use the an 'object-like' comparison,\nwhich means that it will allow for the actual template to be a superset of the\ngiven expectation. See [Special Matchers](#special-matchers) for details on how\nto change this.\n\nSnapshot testing is a common technique to store a snapshot of the output and\ncompare it during future changes. Since CloudFormation templates are human readable,\nthey are a good target for snapshot testing.\n\nThe `toJSON()` method on the `Template` can be used to produce a well formatted JSON\nof the CloudFormation template that can be used as a snapshot.\n\nSee [Snapshot Testing in Jest](https://jestjs.io/docs/snapshot-testing) and [Snapshot\nTesting in Java](https://json-snapshot.github.io/).\n\n## Counting Resources\n\nThis module allows asserting the number of resources of a specific type found\nin a template.\n\n```python\ntemplate.resource_count_is(\"Foo::Bar\", 2)\n```\n\n## Resource Matching & Retrieval\n\nBeyond resource counting, the module also allows asserting that a resource with\nspecific properties are present.\n\nThe following code asserts that the `Properties` section of a resource of type\n`Foo::Bar` contains the specified properties -\n\n```python\ntemplate.has_resource_properties(\"Foo::Bar\", {\n \"Foo\": \"Bar\",\n \"Baz\": 5,\n \"Qux\": [\"Waldo\", \"Fred\"]\n})\n```\n\nAlternatively, if you would like to assert the entire resource definition, you\ncan use the `hasResource()` API.\n\n```python\ntemplate.has_resource(\"Foo::Bar\", {\n \"Properties\": {\"Foo\": \"Bar\"},\n \"DependsOn\": [\"Waldo\", \"Fred\"]\n})\n```\n\nBeyond assertions, the module provides APIs to retrieve matching resources.\nThe `findResources()` API is complementary to the `hasResource()` API, except,\ninstead of asserting its presence, it returns the set of matching resources.\n\nBy default, the `hasResource()` and `hasResourceProperties()` APIs perform deep\npartial object matching. This behavior can be configured using matchers.\nSee subsequent section on [special matchers](#special-matchers).\n\n## Output and Mapping sections\n\nThe module allows you to assert that the CloudFormation template contains an Output\nthat matches specific properties. The following code asserts that a template contains\nan Output with a `logicalId` of `Foo` and the specified properties -\n\n```python\nexpected = {\n \"Value\": \"Bar\",\n \"Export\": {\"Name\": \"ExportBaz\"}\n}\ntemplate.has_output(\"Foo\", expected)\n```\n\nIf you want to match against all Outputs in the template, use `*` as the `logicalId`.\n\n```python\ntemplate.has_output(\"*\", {\n \"Value\": \"Bar\",\n \"Export\": {\"Name\": \"ExportBaz\"}\n})\n```\n\n`findOutputs()` will return a set of outputs that match the `logicalId` and `props`,\nand you can use the `'*'` special case as well.\n\n```python\nresult = template.find_outputs(\"*\", {\"Value\": \"Fred\"})\nexpect(result.Foo).to_equal({\"Value\": \"Fred\", \"Description\": \"FooFred\"})\nexpect(result.Bar).to_equal({\"Value\": \"Fred\", \"Description\": \"BarFred\"})\n```\n\nThe APIs `hasMapping()`, `findMappings()`, `hasCondition()`, and `hasCondtions()` provide similar functionalities.\n\n## Special Matchers\n\nThe expectation provided to the `hasXxx()`, `findXxx()` and `templateMatches()`\nAPIs, besides carrying literal values, as seen in the above examples, also accept\nspecial matchers.\n\nThey are available as part of the `Match` class.\n\n### Object Matchers\n\nThe `Match.objectLike()` API can be used to assert that the target is a superset\nobject of the provided pattern.\nThis API will perform a deep partial match on the target.\nDeep partial matching is where objects are matched partially recursively. At each\nlevel, the list of keys in the target is a subset of the provided pattern.\n\n```python\n# Given a template -\n# {\n# \"Resources\": {\n# \"MyBar\": {\n# \"Type\": \"Foo::Bar\",\n# \"Properties\": {\n# \"Fred\": {\n# \"Wobble\": \"Flob\",\n# \"Bob\": \"Cat\"\n# }\n# }\n# }\n# }\n# }\n\n# The following will NOT throw an assertion error\ntemplate.has_resource_properties(\"Foo::Bar\", {\n \"Fred\": Match.object_like({\n \"Wobble\": \"Flob\"\n })\n})\n\n# The following will throw an assertion error\ntemplate.has_resource_properties(\"Foo::Bar\", {\n \"Fred\": Match.object_like({\n \"Brew\": \"Coffee\"\n })\n})\n```\n\nThe `Match.objectEquals()` API can be used to assert a target as a deep exact\nmatch.\n\n### Presence and Absence\n\nThe `Match.absent()` matcher can be used to specify that a specific\nvalue should not exist on the target. This can be used within `Match.objectLike()`\nor outside of any matchers.\n\n```python\n# Given a template -\n# {\n# \"Resources\": {\n# \"MyBar\": {\n# \"Type\": \"Foo::Bar\",\n# \"Properties\": {\n# \"Fred\": {\n# \"Wobble\": \"Flob\",\n# }\n# }\n# }\n# }\n# }\n\n# The following will NOT throw an assertion error\ntemplate.has_resource_properties(\"Foo::Bar\", {\n \"Fred\": Match.object_like({\n \"Bob\": Match.absent()\n })\n})\n\n# The following will throw an assertion error\ntemplate.has_resource_properties(\"Foo::Bar\", {\n \"Fred\": Match.object_like({\n \"Wobble\": Match.absent()\n })\n})\n```\n\nThe `Match.anyValue()` matcher can be used to specify that a specific value should be found\nat the location. This matcher will fail if when the target location has null-ish values\n(i.e., `null` or `undefined`).\n\nThis matcher can be combined with any of the other matchers.\n\n```python\n# Given a template -\n# {\n# \"Resources\": {\n# \"MyBar\": {\n# \"Type\": \"Foo::Bar\",\n# \"Properties\": {\n# \"Fred\": {\n# \"Wobble\": [\"Flob\", \"Flib\"],\n# }\n# }\n# }\n# }\n# }\n\n# The following will NOT throw an assertion error\ntemplate.has_resource_properties(\"Foo::Bar\", {\n \"Fred\": {\n \"Wobble\": [Match.any_value(), Match.any_value()]\n }\n})\n\n# The following will throw an assertion error\ntemplate.has_resource_properties(\"Foo::Bar\", {\n \"Fred\": {\n \"Wimble\": Match.any_value()\n }\n})\n```\n\n### Array Matchers\n\nThe `Match.arrayWith()` API can be used to assert that the target is equal to or a subset\nof the provided pattern array.\nThis API will perform subset match on the target.\n\n```python\n# Given a template -\n# {\n# \"Resources\": {\n# \"MyBar\": {\n# \"Type\": \"Foo::Bar\",\n# \"Properties\": {\n# \"Fred\": [\"Flob\", \"Cat\"]\n# }\n# }\n# }\n# }\n\n# The following will NOT throw an assertion error\ntemplate.has_resource_properties(\"Foo::Bar\", {\n \"Fred\": Match.array_with([\"Flob\"])\n})\n\n# The following will throw an assertion error\ntemplate.has_resource_properties(\"Foo::Bar\", Match.object_like({\n \"Fred\": Match.array_with([\"Wobble\"])\n}))\n```\n\n*Note:* The list of items in the pattern array should be in order as they appear in the\ntarget array. Out of order will be recorded as a match failure.\n\nAlternatively, the `Match.arrayEquals()` API can be used to assert that the target is\nexactly equal to the pattern array.\n\n### String Matchers\n\nThe `Match.stringLikeRegexp()` API can be used to assert that the target matches the\nprovided regular expression.\n\n```python\n# Given a template -\n# {\n# \"Resources\": {\n# \"MyBar\": {\n# \"Type\": \"Foo::Bar\",\n# \"Properties\": {\n# \"Template\": \"const includeHeaders = true;\"\n# }\n# }\n# }\n# }\n\n# The following will NOT throw an assertion error\ntemplate.has_resource_properties(\"Foo::Bar\", {\n \"Template\": Match.string_like_regexp(\"includeHeaders = (true|false)\")\n})\n\n# The following will throw an assertion error\ntemplate.has_resource_properties(\"Foo::Bar\", {\n \"Template\": Match.string_like_regexp(\"includeHeaders = null\")\n})\n```\n\n### Not Matcher\n\nThe not matcher inverts the search pattern and matches all patterns in the path that does\nnot match the pattern specified.\n\n```python\n# Given a template -\n# {\n# \"Resources\": {\n# \"MyBar\": {\n# \"Type\": \"Foo::Bar\",\n# \"Properties\": {\n# \"Fred\": [\"Flob\", \"Cat\"]\n# }\n# }\n# }\n# }\n\n# The following will NOT throw an assertion error\ntemplate.has_resource_properties(\"Foo::Bar\", {\n \"Fred\": Match.not([\"Flob\"])\n})\n\n# The following will throw an assertion error\ntemplate.has_resource_properties(\"Foo::Bar\", Match.object_like({\n \"Fred\": Match.not([\"Flob\", \"Cat\"])\n}))\n```\n\n### Serialized JSON\n\nOften, we find that some CloudFormation Resource types declare properties as a string,\nbut actually expect JSON serialized as a string.\nFor 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),\nthe [`Definition` property of `AWS::StepFunctions::StateMachine`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-definition),\nto name a couple.\n\nThe `Match.serializedJson()` matcher allows deep matching within a stringified JSON.\n\n```python\n# Given a template -\n# {\n# \"Resources\": {\n# \"MyBar\": {\n# \"Type\": \"Foo::Bar\",\n# \"Properties\": {\n# \"Baz\": \"{ \\\"Fred\\\": [\\\"Waldo\\\", \\\"Willow\\\"] }\"\n# }\n# }\n# }\n# }\n\n# The following will NOT throw an assertion error\ntemplate.has_resource_properties(\"Foo::Bar\", {\n \"Baz\": Match.serialized_json({\n \"Fred\": Match.array_with([\"Waldo\"])\n })\n})\n\n# The following will throw an assertion error\ntemplate.has_resource_properties(\"Foo::Bar\", {\n \"Baz\": Match.serialized_json({\n \"Fred\": [\"Waldo\", \"Johnny\"]\n })\n})\n```\n\n## Capturing Values\n\nThe matcher APIs documented above allow capturing values in the matching entry\n(Resource, Output, Mapping, etc.). The following code captures a string from a\nmatching resource.\n\n```python\n# Given a template -\n# {\n# \"Resources\": {\n# \"MyBar\": {\n# \"Type\": \"Foo::Bar\",\n# \"Properties\": {\n# \"Fred\": [\"Flob\", \"Cat\"],\n# \"Waldo\": [\"Qix\", \"Qux\"],\n# }\n# }\n# }\n# }\n\nfred_capture = Capture()\nwaldo_capture = Capture()\ntemplate.has_resource_properties(\"Foo::Bar\", {\n \"Fred\": fred_capture,\n \"Waldo\": [\"Qix\", waldo_capture]\n})\n\nfred_capture.as_array() # returns [\"Flob\", \"Cat\"]\nwaldo_capture.as_string()\n```\n\nWith captures, a nested pattern can also be specified, so that only targets\nthat match the nested pattern will be captured. This pattern can be literals or\nfurther Matchers.\n\n```python\n# Given a template -\n# {\n# \"Resources\": {\n# \"MyBar1\": {\n# \"Type\": \"Foo::Bar\",\n# \"Properties\": {\n# \"Fred\": [\"Flob\", \"Cat\"],\n# }\n# }\n# \"MyBar2\": {\n# \"Type\": \"Foo::Bar\",\n# \"Properties\": {\n# \"Fred\": [\"Qix\", \"Qux\"],\n# }\n# }\n# }\n# }\n\ncapture = Capture(Match.array_with([\"Cat\"]))\ntemplate.has_resource_properties(\"Foo::Bar\", {\n \"Fred\": capture\n})\n\ncapture.as_array()\n```\n\nWhen multiple resources match the given condition, each `Capture` defined in\nthe condition will capture all matching values. They can be paged through using\nthe `next()` API. The following example illustrates this -\n\n```python\n# Given a template -\n# {\n# \"Resources\": {\n# \"MyBar\": {\n# \"Type\": \"Foo::Bar\",\n# \"Properties\": {\n# \"Fred\": \"Flob\",\n# }\n# },\n# \"MyBaz\": {\n# \"Type\": \"Foo::Bar\",\n# \"Properties\": {\n# \"Fred\": \"Quib\",\n# }\n# }\n# }\n# }\n\nfred_capture = Capture()\ntemplate.has_resource_properties(\"Foo::Bar\", {\n \"Fred\": fred_capture\n})\n\nfred_capture.as_string() # returns \"Flob\"\nfred_capture.next() # returns true\nfred_capture.as_string()\n```\n\n## Asserting Annotations\n\nIn addition to template matching, we provide an API for annotation matching.\n[Annotations](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.Annotations.html)\ncan be added via the [Aspects](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.Aspects.html)\nAPI. You can learn more about Aspects [here](https://docs.aws.amazon.com/cdk/v2/guide/aspects.html).\n\nSay you have a `MyAspect` and a `MyStack` that uses `MyAspect`:\n\n```python\nimport aws_cdk.core as cdk\nfrom constructs import Construct, IConstruct\n\nclass MyAspect(cdk.IAspect):\n def visit(self, node):\n if node instanceof cdk.CfnResource && node.cfn_resource_type == \"Foo::Bar\":\n self.error(node, \"we do not want a Foo::Bar resource\")\n\n def error(self, node, message):\n cdk.Annotations.of(node).add_error(message)\n\nclass MyStack(cdk.Stack):\n def __init__(self, scope, id):\n super().__init__(scope, id)\n\n stack = cdk.Stack()\n cdk.CfnResource(stack, \"Foo\",\n type=\"Foo::Bar\",\n properties={\n \"Fred\": \"Thud\"\n }\n )\n cdk.Aspects.of(stack).add(MyAspect())\n```\n\nWe can then assert that the stack contains the expected Error:\n\n```python\n# import { Annotations } from '@aws-cdk/assertions';\n\nAnnotations.from_stack(stack).has_error(\"/Default/Foo\", \"we do not want a Foo::Bar resource\")\n```\n\nHere are the available APIs for `Annotations`:\n\n* `hasError()`, `hasNoError()`, and `findError()`\n* `hasWarning()`, `hasNoWarning()`, and `findWarning()`\n* `hasInfo()`, `hasNoInfo()`, and `findInfo()`\n\nThe corresponding `findXxx()` API is complementary to the `hasXxx()` API, except instead\nof asserting its presence, it returns the set of matching messages.\n\nIn addition, this suite of APIs is compatable with `Matchers` for more fine-grained control.\nFor example, the following assertion works as well:\n\n```python\nAnnotations.from_stack(stack).has_error(\"/Default/Foo\",\n Match.string_like_regexp(\".*Foo::Bar.*\"))\n```\n\n\n",
"bugtrack_url": null,
"license": "Apache-2.0",
"summary": "An assertion library for use with CDK Apps",
"version": "1.203.0",
"project_urls": {
"Homepage": "https://github.com/aws/aws-cdk",
"Source": "https://github.com/aws/aws-cdk.git"
},
"split_keywords": [],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "ac0c5aca86e4866a980fc86faa2617b4bd3e316880bb4992f258273bc2ffb988",
"md5": "a4c763300ba9a272861f0db31a237c91",
"sha256": "d4418a0e7fe59237f23f3eecb209d148a36e696768bc57a8cfca6613d58bb283"
},
"downloads": -1,
"filename": "aws_cdk.assertions-1.203.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "a4c763300ba9a272861f0db31a237c91",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": "~=3.7",
"size": 161132,
"upload_time": "2023-05-31T22:52:12",
"upload_time_iso_8601": "2023-05-31T22:52:12.011463Z",
"url": "https://files.pythonhosted.org/packages/ac/0c/5aca86e4866a980fc86faa2617b4bd3e316880bb4992f258273bc2ffb988/aws_cdk.assertions-1.203.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "8d9815ed2e1c3c2791ad6d81320aaa70ada5bf11c6d38c10541466a7fc6bd01f",
"md5": "edcd6c5c1b5856c37fea6f8398c2242f",
"sha256": "f2bc84e0e4b80723d901fc107afbdc02242f6d47d0092e3e8c492e91fa3223cd"
},
"downloads": -1,
"filename": "aws-cdk.assertions-1.203.0.tar.gz",
"has_sig": false,
"md5_digest": "edcd6c5c1b5856c37fea6f8398c2242f",
"packagetype": "sdist",
"python_version": "source",
"requires_python": "~=3.7",
"size": 162261,
"upload_time": "2023-05-31T23:00:17",
"upload_time_iso_8601": "2023-05-31T23:00:17.672444Z",
"url": "https://files.pythonhosted.org/packages/8d/98/15ed2e1c3c2791ad6d81320aaa70ada5bf11c6d38c10541466a7fc6bd01f/aws-cdk.assertions-1.203.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2023-05-31 23:00:17",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "aws",
"github_project": "aws-cdk",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "aws-cdk.assertions"
}