Skip to content

Instantly share code, notes, and snippets.

@gbvanrenswoude
Created April 6, 2023 13:34
Show Gist options
  • Save gbvanrenswoude/14b4d6b6c46a9c4f4d5f1c58f0ca1dd2 to your computer and use it in GitHub Desktop.
Save gbvanrenswoude/14b4d6b6c46a9c4f4d5f1c58f0ca1dd2 to your computer and use it in GitHub Desktop.
cdk snapshot testing with the ability to exclude or include assets
import { SynthUtils } from '@aws-cdk/assert';
import * as cdk from 'aws-cdk-lib';
import { Stack, StageSynthesisOptions } from 'aws-cdk-lib';
import { Template } from 'aws-cdk-lib/assertions';
import { InfrastructureStack } from '../../src/lib/infrastructure-stack';
type Options = StageSynthesisOptions & {
/**
* Ignore Assets
*/
ignoreAssets?: boolean;
/**
* Remove only resources of given types, e.g. subsetResourceTypes: ['AWS::SNS::Topic']
*/
removeResourceTypes?: string[];
/**
* Remove only resources of given keys, e.g. subsetResourceKeys: ['TopicX']
*/
removeResourceKeys?: string[];
/**
* Match only resources of given types, e.g. subsetResourceTypes: ['AWS::SNS::Topic']
*/
subsetResourceTypes?: string[];
/**
* Match only resources of given keys, e.g. subsetResourceKeys: ['TopicX']
*/
subsetResourceKeys?: string[];
propertyMatchers?: { [property: string]: unknown };
};
const postProcessedStack = (stack: Stack, options: Options = {}) => {
const { ignoreAssets = false, removeResourceTypes, removeResourceKeys, subsetResourceTypes, subsetResourceKeys, ...synthOptions } = options;
const template = SynthUtils.toCloudFormation(stack, synthOptions);
if (ignoreAssets && template.Resources) {
if (template.Parameters) {
template.Parameters = expect.any(Object);
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
Object.values(template.Resources).forEach((resource: any) => {
if (resource?.Properties?.Code) {
resource.Properties.Code = expect.any(Object);
}
});
}
if (subsetResourceTypes && template.Resources) {
for (const [key, resource] of Object.entries(template.Resources)) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
if (!subsetResourceTypes.includes((resource as any).Type)) {
delete template.Resources[key];
}
}
}
if (subsetResourceKeys && template.Resources) {
for (const [key] of Object.entries(template.Resources)) {
if (!subsetResourceKeys.includes(key)) {
delete template.Resources[key];
}
}
}
if (removeResourceTypes && template.Resources) {
for (const [key, resource] of Object.entries(template.Resources)) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
if (removeResourceTypes.includes((resource as any).Type)) {
delete template.Resources[key];
}
}
}
if (removeResourceKeys && template.Resources) {
for (const [key] of Object.entries(template.Resources)) {
if (removeResourceKeys.includes(key)) {
delete template.Resources[key];
}
}
}
return Template.fromJSON(template);
};
describe('CDK Infra tests - master', () => {
const app = new cdk.App();
const templateMaster = postProcessedStack(
new InfrastructureStack(app, 'some, 'stack', valueObject, {
env: {
account: something,
region: something,
},
}),
{ ignoreAssets: true, removeResourceTypes: ['AWS::CloudFormation::Stack', 'Custom::AWSCDKOpenIdConnectProvider'] }, // removes assets for nested stacks e.d. as well
);
test('CDK_SNAPSHOT - Matches the snapshot', () => {
expect(templateMaster).toMatchSnapshot();
});
...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment