Skip to content

Commit

Permalink
feat(assert): more powerful matchers (aws#8444)
Browse files Browse the repository at this point in the history
In order to write better assertions on complex resource structs that
only test what we're interested in (and not properties that may
accidentally change as part of unrelated refactors), add more powerful
matchers that can express things like:

- `objectLike()`
- `arrayWith()`
- `stringContaining()` (not implemented by default but easy to add now)

We can now write:

```ts
  expect(stack).toHaveResourceLike('AWS::S3::BucketPolicy',  {
    PolicyDocument: {
      Statement: arrayWith(objectLike({
        Action: arrayWith('s3:GetObject*', 's3:GetBucket*', 's3:List*'),
        Principal: {
          AWS: {
            'Fn::Sub': stringContaining('-deploy-role-')
          }
        }
      }))
    }
  });
```

And be invariant to things like the order of elements in the arrays,
and default role name qualifiers.

Refactor the old assertions to be epxressed in terms of the new
matchers.

NOTE: Matchers are now functions, which won't translate into
jsii in the future. It will be easy enough to make them single-method
objects in the future when we move this library (or a similar
one to jsii). For now, I did not want to let that impact the design.


----

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
  • Loading branch information
rix0rrr authored Jun 9, 2020
1 parent b50bb83 commit ed6f763
Show file tree
Hide file tree
Showing 3 changed files with 383 additions and 72 deletions.
31 changes: 30 additions & 1 deletion packages/@aws-cdk/assert/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ If you only care that a resource of a particular type exists (regardless of its

```ts
haveResource(type, subsetOfProperties)
haveResourceLike(type, subsetOfProperties)
```

Example:
Expand All @@ -76,7 +77,35 @@ expect(stack).to(haveResource('AWS::CertificateManager::Certificate', {
}));
```

`ABSENT` is a magic value to assert that a particular key in an object is *not* set (or set to `undefined`).
The object you give to `haveResource`/`haveResourceLike` like can contain the
following values:

- **Literal values**: the given property in the resource must match the given value *exactly*.
- `ABSENT`: a magic value to assert that a particular key in an object is *not* set (or set to `undefined`).
- `arrayWith(...)`/`objectLike(...)`/`deepObjectLike(...)`/`exactValue()`: special matchers
for inexact matching. You can use these to match arrays where not all elements have to match,
just a single one, or objects where not all keys have to match.

The difference between `haveResource` and `haveResourceLike` is the same as
between `objectLike` and `deepObjectLike`: the first allows
additional (unspecified) object keys only at the *first* level, while the
second one allows them in nested objects as well.

If you want to escape from the "deep lenient matching" behavior, you can use
`exactValue()`.

Slightly more complex example with array matchers:

```ts
expect(stack).to(haveResourceLike('AWS::IAM::Policy', {
PolicyDocument: {
Statement: arrayWith(objectLike({
Action: ['s3:GetObject'],
Resource: ['arn:my:arn'],
}})
}
}));
```
### Check number of resources
Expand Down
Loading

0 comments on commit ed6f763

Please sign in to comment.