From 885d86ba4c2f9fe9e3d81a8f29ef1b0fea41836c Mon Sep 17 00:00:00 2001 From: joe-king-sh Date: Thu, 10 Mar 2022 16:01:33 +0000 Subject: [PATCH 01/10] feat(assertions): Add the `hasNoMessage` method. --- packages/@aws-cdk/assertions/lib/private/messages.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/packages/@aws-cdk/assertions/lib/private/messages.ts b/packages/@aws-cdk/assertions/lib/private/messages.ts index 95e898b687183..f8c6d6ea97b46 100644 --- a/packages/@aws-cdk/assertions/lib/private/messages.ts +++ b/packages/@aws-cdk/assertions/lib/private/messages.ts @@ -32,6 +32,17 @@ export function hasMessage(messages: Messages, constructPath: string, props: any ].join('\n'); } +export function hasNoMessage(messages: Messages, constructPath: string, props: any): string | void { + const section: { [key: string]: SynthesisMessage } = messages; + const result = matchSection(filterPath(section, constructPath), props); + + if (!result.match) { + return; + } + + return `Stack has ${Object.keys(result.matches).length} messages.`; +} + // We redact the stack trace by default because it is unnecessarily long and unintelligible. // If there is a use case for rendering the trace, we can add it later. function handleTrace(match: any, redact: boolean = true): void { From 1c60ef13e93a778b8071fed74189cb6e7955429f Mon Sep 17 00:00:00 2001 From: joe-king-sh Date: Thu, 10 Mar 2022 16:06:03 +0000 Subject: [PATCH 02/10] feat(assertions): Add the `hasNoError` method. --- packages/@aws-cdk/assertions/lib/annotations.ts | 15 ++++++++++++++- .../@aws-cdk/assertions/test/annotations.test.ts | 11 +++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/packages/@aws-cdk/assertions/lib/annotations.ts b/packages/@aws-cdk/assertions/lib/annotations.ts index 09f4309044e4a..909b06805351a 100644 --- a/packages/@aws-cdk/assertions/lib/annotations.ts +++ b/packages/@aws-cdk/assertions/lib/annotations.ts @@ -1,7 +1,7 @@ import { Stack, Stage } from '@aws-cdk/core'; import { SynthesisMessage } from '@aws-cdk/cx-api'; import { Messages } from './private/message'; -import { findMessage, hasMessage } from './private/messages'; +import { findMessage, hasMessage, hasNoMessage } from './private/messages'; /** * Suite of assertions that can be run on a CDK Stack. @@ -35,6 +35,19 @@ export class Annotations { } } + /** + * Assert that an error with the given message does not exist in the synthesized CDK `Stack`. + * + * @param constructPath the construct path to the error. Provide `'*'` to match all errors in the template. + * @param message the error message as should be expected. This should be a string or Matcher object. + */ + public hasNoError(constructPath: string, message: any): void { + const matchError = hasNoMessage(this._messages, constructPath, constructMessage('error', message)); + if (matchError) { + throw new Error(matchError); + } + } + /** * Get the set of matching errors of a given construct path and message. * diff --git a/packages/@aws-cdk/assertions/test/annotations.test.ts b/packages/@aws-cdk/assertions/test/annotations.test.ts index 2b1c0c0274ead..b11c9bf1f3b62 100644 --- a/packages/@aws-cdk/assertions/test/annotations.test.ts +++ b/packages/@aws-cdk/assertions/test/annotations.test.ts @@ -50,6 +50,17 @@ describe('Messages', () => { }); }); + describe('hasNoError', () => { + test('match', () => { + annotations.hasNoError('/Default/Fred', Match.anyValue()); + }); + + test('no match', () => { + expect(() => annotations.hasNoError('/Default/Foo', 'this is an error')) + .toThrowError(/Stack has 1 messages./); + }); + }); + describe('findError', () => { test('match', () => { const result = annotations.findError('*', Match.anyValue()); From 2820888d4f341ee0c6b808f307ea5d69fa5a4e8e Mon Sep 17 00:00:00 2001 From: joe-king-sh Date: Thu, 10 Mar 2022 16:07:26 +0000 Subject: [PATCH 03/10] feat(assertions): Add the `hasNoWarning` method. --- packages/@aws-cdk/assertions/lib/annotations.ts | 13 +++++++++++++ .../@aws-cdk/assertions/test/annotations.test.ts | 11 +++++++++++ 2 files changed, 24 insertions(+) diff --git a/packages/@aws-cdk/assertions/lib/annotations.ts b/packages/@aws-cdk/assertions/lib/annotations.ts index 909b06805351a..b310454a4bbe4 100644 --- a/packages/@aws-cdk/assertions/lib/annotations.ts +++ b/packages/@aws-cdk/assertions/lib/annotations.ts @@ -71,6 +71,19 @@ export class Annotations { } } + /** + * Assert that an warning with the given message does not exist in the synthesized CDK `Stack`. + * + * @param constructPath the construct path to the warning. Provide `'*'` to match all warnings in the template. + * @param message the warning message as should be expected. This should be a string or Matcher object. + */ + public hasNoWarning(constructPath: string, message: any): void { + const matchError = hasNoMessage(this._messages, constructPath, constructMessage('warning', message)); + if (matchError) { + throw new Error(matchError); + } + } + /** * Get the set of matching warning of a given construct path and message. * diff --git a/packages/@aws-cdk/assertions/test/annotations.test.ts b/packages/@aws-cdk/assertions/test/annotations.test.ts index b11c9bf1f3b62..521ac953ee92a 100644 --- a/packages/@aws-cdk/assertions/test/annotations.test.ts +++ b/packages/@aws-cdk/assertions/test/annotations.test.ts @@ -83,6 +83,17 @@ describe('Messages', () => { }); }); + describe('hasNoWarning', () => { + test('match', () => { + annotations.hasNoWarning('/Default/Foo', Match.anyValue()); + }); + + test('no match', () => { + expect(() => annotations.hasNoWarning('/Default/Fred', 'this is a warning')) + .toThrowError(/Stack has 1 messages./); + }); + }); + describe('findWarning', () => { test('match', () => { const result = annotations.findWarning('*', Match.anyValue()); From 4d70a707c1b629955ea1661c86e4b8a12fd26b60 Mon Sep 17 00:00:00 2001 From: joe-king-sh Date: Thu, 10 Mar 2022 16:08:58 +0000 Subject: [PATCH 04/10] feat(assertions): Add the `hasNoInfo` method. --- packages/@aws-cdk/assertions/lib/annotations.ts | 13 +++++++++++++ .../@aws-cdk/assertions/test/annotations.test.ts | 10 ++++++++++ 2 files changed, 23 insertions(+) diff --git a/packages/@aws-cdk/assertions/lib/annotations.ts b/packages/@aws-cdk/assertions/lib/annotations.ts index b310454a4bbe4..2068b58ccb480 100644 --- a/packages/@aws-cdk/assertions/lib/annotations.ts +++ b/packages/@aws-cdk/assertions/lib/annotations.ts @@ -107,6 +107,19 @@ export class Annotations { } } + /** + * Assert that an info with the given message does not exist in the synthesized CDK `Stack`. + * + * @param constructPath the construct path to the info. Provide `'*'` to match all info in the template. + * @param message the info message as should be expected. This should be a string or Matcher object. + */ + public hasNoInfo(constructPath: string, message: any): void { + const matchError = hasNoMessage(this._messages, constructPath, constructMessage('info', message)); + if (matchError) { + throw new Error(matchError); + } + } + /** * Get the set of matching infos of a given construct path and message. * diff --git a/packages/@aws-cdk/assertions/test/annotations.test.ts b/packages/@aws-cdk/assertions/test/annotations.test.ts index 521ac953ee92a..5737f28a197f2 100644 --- a/packages/@aws-cdk/assertions/test/annotations.test.ts +++ b/packages/@aws-cdk/assertions/test/annotations.test.ts @@ -116,6 +116,16 @@ describe('Messages', () => { }); }); + describe('hasNoInfo', () => { + test('match', () => { + annotations.hasNoInfo('/Default/Qux', 'this info is incorrect'); + }); + + test('no match', () => { + expect(() => annotations.hasNoInfo('/Default/Qux', 'this is an info')).toThrowError(/Stack has 1 messages./); + }); + }); + describe('findInfo', () => { test('match', () => { const result = annotations.findInfo('/Default/Qux', 'this is an info'); From 6acd7e9cb4d5a00ac58869a3d2de06217dacef34 Mon Sep 17 00:00:00 2001 From: joe-king-sh Date: Fri, 11 Mar 2022 00:11:47 +0000 Subject: [PATCH 05/10] Add descriptions about new APIs. --- packages/@aws-cdk/assertions/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/@aws-cdk/assertions/README.md b/packages/@aws-cdk/assertions/README.md index d23c37a08b099..eb9b084bc2f7f 100644 --- a/packages/@aws-cdk/assertions/README.md +++ b/packages/@aws-cdk/assertions/README.md @@ -550,9 +550,9 @@ Annotations.fromStack(stack).hasError( Here are the available APIs for `Annotations`: -- `hasError()` and `findError()` -- `hasWarning()` and `findWarning()` -- `hasInfo()` and `findInfo()` +- `hasError()`, `findError()` and `hasNoError()` +- `hasWarning()`,`findWarning()` and `hasNoWarning()` +- `hasInfo()`, `findInfo()` and `hasNoInfo()` The corresponding `findXxx()` API is complementary to the `hasXxx()` API, except instead of asserting its presence, it returns the set of matching messages. From 192b33978bf31b7f3aabc3290f147b480f17497c Mon Sep 17 00:00:00 2001 From: joe-king-sh Date: Sat, 12 Mar 2022 05:11:12 +0000 Subject: [PATCH 06/10] Reflect a review comment to README.md. --- packages/@aws-cdk/assertions/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/@aws-cdk/assertions/README.md b/packages/@aws-cdk/assertions/README.md index eb9b084bc2f7f..8692ecc7d66ce 100644 --- a/packages/@aws-cdk/assertions/README.md +++ b/packages/@aws-cdk/assertions/README.md @@ -550,9 +550,9 @@ Annotations.fromStack(stack).hasError( Here are the available APIs for `Annotations`: -- `hasError()`, `findError()` and `hasNoError()` -- `hasWarning()`,`findWarning()` and `hasNoWarning()` -- `hasInfo()`, `findInfo()` and `hasNoInfo()` +- `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. From c7597c1d03b4a9294db71c79c77cc9e0481a681c Mon Sep 17 00:00:00 2001 From: joe-king-sh Date: Sat, 12 Mar 2022 05:20:15 +0000 Subject: [PATCH 07/10] Reflect a review comment to annotations.test.ts --- packages/@aws-cdk/assertions/test/annotations.test.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/@aws-cdk/assertions/test/annotations.test.ts b/packages/@aws-cdk/assertions/test/annotations.test.ts index 5737f28a197f2..b50d5940793fc 100644 --- a/packages/@aws-cdk/assertions/test/annotations.test.ts +++ b/packages/@aws-cdk/assertions/test/annotations.test.ts @@ -122,7 +122,8 @@ describe('Messages', () => { }); test('no match', () => { - expect(() => annotations.hasNoInfo('/Default/Qux', 'this is an info')).toThrowError(/Stack has 1 messages./); + expect(() => annotations.hasNoInfo('/Default/Qux', 'this is an info')) + .toThrowError(/Stack has 1 messages./); }); }); From ef3860a1fbd596a358f608dc828a7cd3ce9c572c Mon Sep 17 00:00:00 2001 From: joe-king-sh Date: Sat, 12 Mar 2022 06:04:21 +0000 Subject: [PATCH 08/10] Reflect a review comment to display a message about errors when they occur. --- packages/@aws-cdk/assertions/lib/private/messages.ts | 5 ++++- packages/@aws-cdk/assertions/test/annotations.test.ts | 6 +++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/@aws-cdk/assertions/lib/private/messages.ts b/packages/@aws-cdk/assertions/lib/private/messages.ts index f8c6d6ea97b46..dca262326dbd3 100644 --- a/packages/@aws-cdk/assertions/lib/private/messages.ts +++ b/packages/@aws-cdk/assertions/lib/private/messages.ts @@ -40,7 +40,10 @@ export function hasNoMessage(messages: Messages, constructPath: string, props: a return; } - return `Stack has ${Object.keys(result.matches).length} messages.`; + return [ + `Expected no matches, but stack has ${Object.keys(result.matches).length} messages as follows`, + JSON.stringify(result.matches), + ].join('\n'); } // We redact the stack trace by default because it is unnecessarily long and unintelligible. diff --git a/packages/@aws-cdk/assertions/test/annotations.test.ts b/packages/@aws-cdk/assertions/test/annotations.test.ts index b50d5940793fc..976926cfbc004 100644 --- a/packages/@aws-cdk/assertions/test/annotations.test.ts +++ b/packages/@aws-cdk/assertions/test/annotations.test.ts @@ -57,7 +57,7 @@ describe('Messages', () => { test('no match', () => { expect(() => annotations.hasNoError('/Default/Foo', 'this is an error')) - .toThrowError(/Stack has 1 messages./); + .toThrowError(/Expected no matches, but stack has 1 messages as follows/); }); }); @@ -90,7 +90,7 @@ describe('Messages', () => { test('no match', () => { expect(() => annotations.hasNoWarning('/Default/Fred', 'this is a warning')) - .toThrowError(/Stack has 1 messages./); + .toThrowError(/Expected no matches, but stack has 1 messages as follows/); }); }); @@ -123,7 +123,7 @@ describe('Messages', () => { test('no match', () => { expect(() => annotations.hasNoInfo('/Default/Qux', 'this is an info')) - .toThrowError(/Stack has 1 messages./); + .toThrowError(/Expected no matches, but stack has 1 messages as follows/); }); }); From a6ac381d650bfdc1e9a008a02d7013ff21853143 Mon Sep 17 00:00:00 2001 From: kaizen3031593 Date: Mon, 14 Mar 2022 15:39:09 -0400 Subject: [PATCH 09/10] better formatting for errors --- packages/@aws-cdk/assertions/lib/private/messages.ts | 4 ++-- packages/@aws-cdk/assertions/lib/private/section.ts | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/@aws-cdk/assertions/lib/private/messages.ts b/packages/@aws-cdk/assertions/lib/private/messages.ts index dca262326dbd3..b08e189702574 100644 --- a/packages/@aws-cdk/assertions/lib/private/messages.ts +++ b/packages/@aws-cdk/assertions/lib/private/messages.ts @@ -1,6 +1,6 @@ import { SynthesisMessage } from '@aws-cdk/cx-api'; import { Messages } from './message'; -import { formatFailure, matchSection } from './section'; +import { formatAllMatches, formatFailure, matchSection } from './section'; export function findMessage(messages: Messages, constructPath: string, props: any = {}): { [key: string]: { [key: string]: any } } { const section: { [key: string]: SynthesisMessage } = messages; @@ -42,7 +42,7 @@ export function hasNoMessage(messages: Messages, constructPath: string, props: a return [ `Expected no matches, but stack has ${Object.keys(result.matches).length} messages as follows`, - JSON.stringify(result.matches), + formatAllMatches(result.matches), ].join('\n'); } diff --git a/packages/@aws-cdk/assertions/lib/private/section.ts b/packages/@aws-cdk/assertions/lib/private/section.ts index d2dd96800da08..2468e47f33c1c 100644 --- a/packages/@aws-cdk/assertions/lib/private/section.ts +++ b/packages/@aws-cdk/assertions/lib/private/section.ts @@ -43,6 +43,12 @@ function eachEntryInSection( } } +export function formatAllMatches(matches: {[key: string]: any}): string { + return [ + leftPad(JSON.stringify(matches, undefined, 2)), + ].join('\n'); +} + export function formatFailure(closestResult: MatchResult): string { return [ 'The closest result is:', From 86972e2b89bdc429551adfeef34765a167d49251 Mon Sep 17 00:00:00 2001 From: kaizen3031593 Date: Mon, 14 Mar 2022 15:40:23 -0400 Subject: [PATCH 10/10] add colon --- packages/@aws-cdk/assertions/lib/private/messages.ts | 2 +- packages/@aws-cdk/assertions/test/annotations.test.ts | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/@aws-cdk/assertions/lib/private/messages.ts b/packages/@aws-cdk/assertions/lib/private/messages.ts index b08e189702574..f152ebcefb0e5 100644 --- a/packages/@aws-cdk/assertions/lib/private/messages.ts +++ b/packages/@aws-cdk/assertions/lib/private/messages.ts @@ -41,7 +41,7 @@ export function hasNoMessage(messages: Messages, constructPath: string, props: a } return [ - `Expected no matches, but stack has ${Object.keys(result.matches).length} messages as follows`, + `Expected no matches, but stack has ${Object.keys(result.matches).length} messages as follows:`, formatAllMatches(result.matches), ].join('\n'); } diff --git a/packages/@aws-cdk/assertions/test/annotations.test.ts b/packages/@aws-cdk/assertions/test/annotations.test.ts index 976926cfbc004..ebc1ca081d868 100644 --- a/packages/@aws-cdk/assertions/test/annotations.test.ts +++ b/packages/@aws-cdk/assertions/test/annotations.test.ts @@ -57,7 +57,7 @@ describe('Messages', () => { test('no match', () => { expect(() => annotations.hasNoError('/Default/Foo', 'this is an error')) - .toThrowError(/Expected no matches, but stack has 1 messages as follows/); + .toThrowError(/Expected no matches, but stack has 1 messages as follows:/); }); }); @@ -90,7 +90,7 @@ describe('Messages', () => { test('no match', () => { expect(() => annotations.hasNoWarning('/Default/Fred', 'this is a warning')) - .toThrowError(/Expected no matches, but stack has 1 messages as follows/); + .toThrowError(/Expected no matches, but stack has 1 messages as follows:/); }); }); @@ -123,7 +123,7 @@ describe('Messages', () => { test('no match', () => { expect(() => annotations.hasNoInfo('/Default/Qux', 'this is an info')) - .toThrowError(/Expected no matches, but stack has 1 messages as follows/); + .toThrowError(/Expected no matches, but stack has 1 messages as follows:/); }); });