Skip to content

Commit

Permalink
feat(awscdk): allow users to integration test multi-stack stages (pro…
Browse files Browse the repository at this point in the history
…jen#1496)

Allows users to add AWS CDK integration tests consisting of stages with multiple stacks.

```ts
new awscdk.IntegrationTest(project, {
  name: "my-stage",
  entrypoint: "test/my-stage.myinteg.ts",
  stacks: ["my-stage/*"],
  tsconfigPath: project.tsconfigDev.fileName,
  cdkDeps: project.cdkDeps,
});
```

Fixes projen#1495

---
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
  • Loading branch information
misterjoshua authored Jan 12, 2022
1 parent 43ee650 commit f6529dc
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 9 deletions.
4 changes: 4 additions & 0 deletions API.md
Original file line number Diff line number Diff line change
Expand Up @@ -3916,6 +3916,8 @@ new awscdk.IntegrationTest(project: Project, options: IntegrationTestOptions)
* **cdkDeps** (<code>[awscdk.AwsCdkDeps](#projen-awscdk-awscdkdeps)</code>) AWS CDK dependency manager.
* **entrypoint** (<code>string</code>) A path from the project root directory to a TypeScript file which contains the integration test app.
* **tsconfigPath** (<code>string</code>) The path of the tsconfig.json file to use when running integration test cdk apps.
* **name** (<code>string</code>) Name of the integration test. __*Default*__: Derived from the entrypoint filename.
* **stacks** (<code>Array<string></code>) A list of stacks within the integration test to deploy/destroy. __*Default*__: ["*"]



Expand Down Expand Up @@ -11703,6 +11705,8 @@ Name | Type | Description
**entrypoint**🔹 | <code>string</code> | A path from the project root directory to a TypeScript file which contains the integration test app.
**tsconfigPath**🔹 | <code>string</code> | The path of the tsconfig.json file to use when running integration test cdk apps.
**destroyAfterDeploy**?🔹 | <code>boolean</code> | Destroy the test app after a successful deployment.<br/>__*Default*__: true
**name**?🔹 | <code>string</code> | Name of the integration test.<br/>__*Default*__: Derived from the entrypoint filename.
**stacks**?🔹 | <code>Array<string></code> | A list of stacks within the integration test to deploy/destroy.<br/>__*Default*__: ["*"]



Expand Down
24 changes: 20 additions & 4 deletions src/awscdk/integration-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,18 @@ export interface IntegrationTestCommonOptions {
* Options for `IntegrationTest`.
*/
export interface IntegrationTestOptions extends IntegrationTestCommonOptions {
/**
* Name of the integration test
* @default - Derived from the entrypoint filename.
*/
readonly name?: string;

/**
* A list of stacks within the integration test to deploy/destroy.
* @default ["*"]
*/
readonly stacks?: string[];

/**
* A path from the project root directory to a TypeScript file which contains
* the integration test app.
Expand Down Expand Up @@ -72,7 +84,7 @@ export class IntegrationTest extends Component {
constructor(project: Project, options: IntegrationTestOptions) {
super(project);
const entry = options.entrypoint;
const name = basename(entry, TYPESCRIPT_INTEG_EXT);
const name = options.name ?? basename(entry, TYPESCRIPT_INTEG_EXT);
const dir = dirname(entry);

const deploydir = join(dir, ".tmp", `${name}.integ`, "deploy.cdk.out");
Expand Down Expand Up @@ -107,13 +119,17 @@ export class IntegrationTest extends Component {

const cdkopts = opts.join(" ");

// Determine which stacks to deploy
const stacks = options.stacks ?? ["*"];
const stackOpts = stacks.map((stack) => `'${stack}'`).join(" ");

const deployTask = project.addTask(`integ:${name}:deploy`, {
description: `deploy integration test '${name}' and capture snapshot`,
});

deployTask.exec(`rm -fr ${deploydir}`);
deployTask.exec(
`cdk deploy ${cdkopts} --require-approval=never -o ${deploydir}`
`cdk deploy ${cdkopts} ${stackOpts} --require-approval=never -o ${deploydir}`
);

// if deployment was successful, copy the deploy dir to the expected dir
Expand All @@ -122,12 +138,12 @@ export class IntegrationTest extends Component {

const watchTask = project.addTask(`integ:${name}:watch`, {
description: `watch integration test '${name}' (without updating snapshots)`,
exec: `cdk watch ${cdkopts} -o ${deploydir}`,
exec: `cdk watch ${cdkopts} ${stackOpts} -o ${deploydir}`,
});

const destroyTask = project.addTask(`integ:${name}:destroy`, {
description: `destroy integration test '${name}'`,
exec: `cdk destroy --app ${snapshotdir} --no-version-reporting`,
exec: `cdk destroy --app ${snapshotdir} ${stackOpts} --no-version-reporting`,
});

const destroyAfterDeploy = options.destroyAfterDeploy ?? true;
Expand Down
58 changes: 53 additions & 5 deletions test/awscdk/__snapshots__/integration-test.test.ts.snap

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

31 changes: 31 additions & 0 deletions test/awscdk/integration-test.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,3 +118,34 @@ test("synthesizing cdk v2 integration tests", () => {
output[".projen/tasks.json"].tasks["integ:foo:watch"]
).toMatchSnapshot();
});

test("synthesizing an integration test containing a multi-stack stage", () => {
// GIVEN
const project = new awscdk.AwsCdkTypeScriptApp({
name: "test",
defaultReleaseBranch: "main",
cdkVersion: "2.3.1",
});

// WHEN
new awscdk.IntegrationTest(project, {
name: "my-stage",
entrypoint: "test/my-stage.myinteg.ts",
stacks: ["my-stage/*"],
tsconfigPath: project.tsconfigDev.fileName,
cdkDeps: project.cdkDeps,
});

// THEN
const output = Testing.synth(project);

expect(
output[".projen/tasks.json"].tasks["integ:my-stage:deploy"]
).toMatchSnapshot();
expect(
output[".projen/tasks.json"].tasks["integ:my-stage:snapshot"]
).toMatchSnapshot();
expect(
output[".projen/tasks.json"].tasks["integ:my-stage:watch"]
).toMatchSnapshot();
});

0 comments on commit f6529dc

Please sign in to comment.