diff --git a/packages/@aws-cdk-testing/cli-integ/resources/cdk-apps/diff-no-fallback-app/app.js b/packages/@aws-cdk-testing/cli-integ/resources/cdk-apps/diff-no-fallback-app/app.js new file mode 100644 index 0000000000000..599be28a88b20 --- /dev/null +++ b/packages/@aws-cdk-testing/cli-integ/resources/cdk-apps/diff-no-fallback-app/app.js @@ -0,0 +1,38 @@ +const cdk = require('aws-cdk-lib'); +const sns = require('aws-cdk-lib/aws-sns'); +/** + * This stack will be deployed in multiple phases, to achieve a very specific effect + * + * - Deploy Phase: a stack is deployed with an output set to a static string + * - Diff Phase: a reference to a non-existing macro is used for the output value + * + * To exercise this app: + * + * ``` + * npx cdk deploy + * env DIFF_PHASE=on npx cdk diff --no-fallback + * # This will surface an error to the user about the missing macro + * ``` + */ +class DiffNoFallbackTestStack extends cdk.Stack { + constructor(scope, id, props) { + super(scope, id, props); + + // Have at least one resource so that we can deploy this + new sns.Topic(this, 'topic', { + removalPolicy: cdk.RemovalPolicy.DESTROY, + }); + + const outputValue = process.env.DIFF_PHASE ? cdk.Fn.transform('NonExisting', { Param: 'Value' }) : 'static-string' + + new cdk.CfnOutput(this, 'MyOutput', { + value: outputValue + }) + } +} +const stackPrefix = process.env.STACK_NAME_PREFIX; +const app = new cdk.App(); + +new DiffNoFallbackTestStack(app, `${stackPrefix}-test-diff-no-fallback`); + +app.synth(); diff --git a/packages/@aws-cdk-testing/cli-integ/resources/cdk-apps/diff-no-fallback-app/cdk.json b/packages/@aws-cdk-testing/cli-integ/resources/cdk-apps/diff-no-fallback-app/cdk.json new file mode 100644 index 0000000000000..f0075b1c9e33b --- /dev/null +++ b/packages/@aws-cdk-testing/cli-integ/resources/cdk-apps/diff-no-fallback-app/cdk.json @@ -0,0 +1,4 @@ +{ + "app": "node app.js", + "versionReporting": false +} diff --git a/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cli.integtest.ts b/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cli.integtest.ts index f4736584a065f..8e99f59080269 100644 --- a/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cli.integtest.ts +++ b/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cli.integtest.ts @@ -2931,3 +2931,40 @@ function actions(requests: CompletedRequest[]): string[] { .map(x => x.Action as string) .filter(action => action != null))]; } + +integTest( + 'cdk diff noFallback', + withSpecificFixture('diff-no-fallback-app', async (fixture) => { + // Should succeed + await fixture.cdkDeploy('test-diff-no-fallback', { + verbose: false, + }); + try { + // Should surface the missing transform error from cloudformation in the output + const diffOutput = await fixture.cdk(['diff', '--no-fallback', fixture.fullStackName('test-diff-no-fallback')], { + modEnv: { DIFF_PHASE: 'on' }, + allowErrExit: true, + captureStderr: true, + }); + expect(diffOutput).toContain('No transform named'); + + // Should throw + await expect(fixture.cdk(['diff', '--no-fallback', fixture.fullStackName('test-diff-no-fallback')], { + modEnv: { DIFF_PHASE: 'on' }, + captureStderr: true, + })).rejects.toThrow(); + + // Should fallback to template-only diff as normal + const diffOutputWithFallback = await fixture.cdk(['diff', fixture.fullStackName('test-diff-no-fallback')], { + modEnv: { DIFF_PHASE: 'on' }, + captureStderr: true, + allowErrExit: true, + }); + + expect(diffOutputWithFallback).toContain('will base the diff on template differences'); + + } finally { + await fixture.cdkDestroy('test-diff-no-fallback', { verbose: false }); + } + }), +);