UNPKG

6.7 kBMarkdownView Raw
1# Testing utilities and assertions for CDK libraries
2<!--BEGIN STABILITY BANNER-->
3
4---
5
6![Deprecated](https://img.shields.io/badge/deprecated-critical.svg?style=for-the-badge)
7
8 > This API may emit warnings. Backward compatibility is not guaranteed.
9
10## Replacement recommended
11
12This library has been deprecated. We recommend you use the
13[@aws-cdk/assertions](https://docs.aws.amazon.com/cdk/api/v1/docs/assertions-readme.html) module instead.
14
15---
16
17<!--END STABILITY BANNER-->
18
19This library contains helpers for writing unit tests and integration tests for CDK libraries
20
21## Unit tests
22
23Write your unit tests like this:
24
25```ts
26const stack = new Stack();
27
28new MyConstruct(stack, 'MyConstruct', {
29 ...
30});
31
32expect(stack).to(someExpectation(...));
33```
34
35Here are the expectations you can use:
36
37## Verify (parts of) a template
38
39Check that the synthesized stack template looks like the given template, or is a superset of it. These functions match logical IDs and all properties of a resource.
40
41```ts
42matchTemplate(template, matchStyle)
43exactlyMatchTemplate(template)
44beASupersetOfTemplate(template)
45```
46
47Example:
48
49```ts
50expect(stack).to(beASupersetOfTemplate({
51 Resources: {
52 HostedZone674DD2B7: {
53 Type: "AWS::Route53::HostedZone",
54 Properties: {
55 Name: "test.private.",
56 VPCs: [{
57 VPCId: { Ref: 'VPC06C5F037' },
58 VPCRegion: { Ref: 'AWS::Region' }
59 }]
60 }
61 }
62 }
63}));
64```
65
66
67## Check existence of a resource
68
69If you only care that a resource of a particular type exists (regardless of its logical identifier), and that *some* of its properties are set to specific values:
70
71```ts
72haveResource(type, subsetOfProperties)
73haveResourceLike(type, subsetOfProperties)
74```
75
76Example:
77
78```ts
79expect(stack).to(haveResource('AWS::CertificateManager::Certificate', {
80 DomainName: 'test.example.com',
81 // Note: some properties omitted here
82
83 ShouldNotExist: ABSENT
84}));
85```
86
87The object you give to `haveResource`/`haveResourceLike` like can contain the
88following values:
89
90- **Literal values**: the given property in the resource must match the given value *exactly*.
91- `ABSENT`: a magic value to assert that a particular key in an object is *not* set (or set to `undefined`).
92- special matchers for inexact matching. You can use these to match values based on more lenient conditions
93 than the default (such as an array containing at least one element, ignoring the rest, or an inexact string
94 match).
95
96The following matchers exist:
97
98- `objectLike(O)` - the value has to be an object matching at least the keys in `O` (but may contain
99 more). The nested values must match exactly.
100- `deepObjectLike(O)` - as `objectLike`, but nested objects are also treated as partial specifications.
101- `exactValue(X)` - must match exactly the given value. Use this to escape from `deepObjectLike`'s leniency
102 back to exact value matching.
103- `arrayWith(E, [F, ...])` - value must be an array containing the given elements (or matchers) in any order.
104- `stringLike(S)` - value must be a string matching `S`. `S` may contain `*` as wildcard to match any number
105 of characters. Multiline strings are supported.
106- `anything()` - matches any value.
107- `notMatching(M)` - any value that does NOT match the given matcher (or exact value) given.
108- `encodedJson(M)` - value must be a string which, when decoded as JSON, matches the given matcher or
109 exact value.
110
111Slightly more complex example with array matchers:
112
113```ts
114expect(stack).to(haveResourceLike('AWS::IAM::Policy', {
115 PolicyDocument: {
116 Statement: arrayWith(objectLike({
117 Action: ['s3:GetObject'],
118 Resource: ['arn:my:arn'],
119 }})
120 }
121}));
122```
123
124## Capturing values from a match
125
126Special `Capture` matchers exist to capture values encountered during a match. These can be
127used for two typical purposes:
128
129- Apply additional assertions to the values found during a matching operation.
130- Use the value found during a matching operation in a new matching operation.
131
132`Capture` matchers take an inner matcher as an argument, and will only capture the value
133if the inner matcher succeeds in matching the given value.
134
135Here's an example which asserts that a policy for `RoleA` contains two statements
136with *different* ARNs (without caring what those ARNs might be), and that
137a policy for `RoleB` *also* has a statement for one of those ARNs (again, without
138caring what the ARN might be):
139
140```ts
141const arn1 = Capture.aString();
142const arn2 = Capture.aString();
143
144expect(stack).to(haveResourceLike('AWS::IAM::Policy', {
145 Roles: ['RoleA'],
146 PolicyDocument: {
147 Statement: [
148 objectLike({
149 Resource: [arn1.capture()],
150 }),
151 objectLike({
152 Resource: [arn2.capture()],
153 }),
154 ],
155 },
156}));
157
158// Don't care about the values as long as they are not the same
159expect(arn1.capturedValue).not.toEqual(arn2.capturedValue);
160
161expect(stack).to(haveResourceLike('AWS::IAM::Policy', {
162 Roles: ['RoleB'],
163 PolicyDocument: {
164 Statement: [
165 objectLike({
166 // This ARN must be the same as ARN1 above.
167 Resource: [arn1.capturedValue]
168 }),
169 ],
170 },
171}));
172```
173
174NOTE: `Capture` look somewhat like *bindings* in other pattern matching
175libraries you might be used to, but they are far simpler and very
176deterministic. In particular, they don't do unification: if the same Capture
177is either used multiple times in the same structure expression or matches
178multiple times, no restarting of the match is done to make them all match the
179same value: the last value encountered by the `Capture` (as determined by the
180behavior of the matchers around it) is stored into it and will be the one
181available after the match has completed.
182
183## Check number of resources
184
185If you want to assert that `n` number of resources of a particular type exist, with or without specific properties:
186
187```ts
188countResources(type, count)
189countResourcesLike(type, count, props)
190```
191
192Example:
193
194```ts
195expect(stack).to(countResources('AWS::ApiGateway::Method', 3));
196expect(stack).to(countResourcesLike('AWS::ApiGateway::Method', 1, {
197 HttpMethod: 'GET',
198 ResourceId: {
199 "Ref": "MyResource01234"
200 }
201}));
202```
203
204## Check existence of an output
205
206`haveOutput` assertion can be used to check that a stack contains specific output.
207Parameters to check against can be:
208
209- `outputName`
210- `outputValue`
211- `exportName`
212
213If `outputValue` is provided, at least one of `outputName`, `exportName` should be provided as well
214
215Example
216
217```ts
218expect(synthStack).to(haveOutput({
219 outputName: 'TestOutputName',
220 exportName: 'TestOutputExportName',
221 outputValue: {
222 'Fn::GetAtt': [
223 'TestResource',
224 'Arn'
225 ]
226 }
227}));
228```