diff --git a/packages/@aws-cdk/integ-runner/README.md b/packages/@aws-cdk/integ-runner/README.md index d682e02ebb205..3e2553ac3a5f9 100644 --- a/packages/@aws-cdk/integ-runner/README.md +++ b/packages/@aws-cdk/integ-runner/README.md @@ -68,7 +68,8 @@ to be a self contained CDK app. The runner will execute the following for each f Read the list of tests from this file - `--disable-update-workflow` (default=`false`) If this is set to `true` then the [update workflow](#update-workflow) will be disabled - +- `--app` + The custom CLI command that will be used to run the test files. You can include {filePath} to specify where in the command the test file path should be inserted. Example: --app="python3.8 {filePath}". Example: ```bash diff --git a/packages/@aws-cdk/integ-runner/lib/cli.ts b/packages/@aws-cdk/integ-runner/lib/cli.ts index 0904ffb96d438..740ce476671d6 100644 --- a/packages/@aws-cdk/integ-runner/lib/cli.ts +++ b/packages/@aws-cdk/integ-runner/lib/cli.ts @@ -30,6 +30,7 @@ async function main() { .options('from-file', { type: 'string', desc: 'Read TEST names from a file (one TEST per line)' }) .option('inspect-failures', { type: 'boolean', desc: 'Keep the integ test cloud assembly if a failure occurs for inspection', default: false }) .option('disable-update-workflow', { type: 'boolean', default: false, desc: 'If this is "true" then the stack update workflow will be disabled' }) + .option('app', { type: 'string', default: undefined, desc: 'The custom CLI command that will be used to run the test files. You can include {filePath} to specify where in the command the test file path should be inserted. Example: --app="python3.8 {filePath}".' }) .strict() .argv; @@ -76,6 +77,7 @@ async function main() { failedSnapshots = await runSnapshotTests(pool, testsFromArgs, { retain: argv['inspect-failures'], verbose: Boolean(argv.verbose), + appCommand: argv.app, }); for (const failure of failedSnapshots) { destructiveChanges.push(...failure.destructiveChanges ?? []); @@ -99,6 +101,7 @@ async function main() { dryRun: argv['dry-run'], verbosity: argv.verbose, updateWorkflow: !argv['disable-update-workflow'], + appCommand: argv.app, }); testsSucceeded = success; diff --git a/packages/@aws-cdk/integ-runner/lib/runner/runner-base.ts b/packages/@aws-cdk/integ-runner/lib/runner/runner-base.ts index 7f8e1963dd5e4..0e4ba15683eea 100644 --- a/packages/@aws-cdk/integ-runner/lib/runner/runner-base.ts +++ b/packages/@aws-cdk/integ-runner/lib/runner/runner-base.ts @@ -49,6 +49,14 @@ export interface IntegRunnerOptions { */ readonly cdk?: ICdk; + /** + * You can specify a custom run command, and it will be applied to all test files. + * If it contains {filePath}, the test file names will be substituted at that place in the command for each run. + * + * @default - test run command will be `node {filePath}` + */ + readonly appCommand?: string; + /** * Show output from running integration tests * @@ -150,7 +158,10 @@ export abstract class IntegRunner { }, }); this.cdkOutDir = options.integOutDir ?? this.test.temporaryOutputDir; - this.cdkApp = `node ${path.relative(this.directory, this.test.fileName)}`; + + const testRunCommand = options.appCommand ?? 'node {filePath}'; + this.cdkApp = testRunCommand.replace('{filePath}', path.relative(this.directory, this.test.fileName)); + this.profile = options.profile; if (this.hasSnapshot()) { this.expectedTestSuite = this.loadManifest(); diff --git a/packages/@aws-cdk/integ-runner/lib/workers/common.ts b/packages/@aws-cdk/integ-runner/lib/workers/common.ts index 7f49cb73b864c..a8c3a7b92079d 100644 --- a/packages/@aws-cdk/integ-runner/lib/workers/common.ts +++ b/packages/@aws-cdk/integ-runner/lib/workers/common.ts @@ -103,6 +103,13 @@ export interface SnapshotVerificationOptions { * @default false */ readonly verbose?: boolean; + + /** + * The CLI command used to run the test files. + * + * @default - test run command will be `node {filePath}` + */ + readonly appCommand?: string; } /** @@ -162,6 +169,13 @@ export interface IntegTestOptions { * @default true */ readonly updateWorkflow?: boolean; + + /** + * The CLI command used to run the test files. + * + * @default - test run command will be `node {filePath}` + */ + readonly appCommand?: string; } /** diff --git a/packages/@aws-cdk/integ-runner/lib/workers/extract/extract_worker.ts b/packages/@aws-cdk/integ-runner/lib/workers/extract/extract_worker.ts index a8166680fb7ba..047e03463efdf 100644 --- a/packages/@aws-cdk/integ-runner/lib/workers/extract/extract_worker.ts +++ b/packages/@aws-cdk/integ-runner/lib/workers/extract/extract_worker.ts @@ -27,6 +27,7 @@ export function integTestWorker(request: IntegTestBatchRequest): IntegTestWorker env: { AWS_REGION: request.region, }, + appCommand: request.appCommand, showOutput: verbosity >= 2, }, testInfo.destructiveChanges); @@ -105,7 +106,7 @@ export function snapshotTestWorker(testInfo: IntegTestInfo, options: SnapshotVer }, 60_000); try { - const runner = new IntegSnapshotRunner({ test }); + const runner = new IntegSnapshotRunner({ test, appCommand: options.appCommand }); if (!runner.hasSnapshot()) { workerpool.workerEmit({ reason: DiagnosticReason.NO_SNAPSHOT, diff --git a/packages/@aws-cdk/integ-runner/lib/workers/integ-test-worker.ts b/packages/@aws-cdk/integ-runner/lib/workers/integ-test-worker.ts index 77752c029abbb..06d73967a2d25 100644 --- a/packages/@aws-cdk/integ-runner/lib/workers/integ-test-worker.ts +++ b/packages/@aws-cdk/integ-runner/lib/workers/integ-test-worker.ts @@ -135,6 +135,7 @@ export async function runIntegrationTestsInParallel( dryRun: options.dryRun, verbosity: options.verbosity, updateWorkflow: options.updateWorkflow, + appCommand: options.appCommand, }], { on: printResults, }); diff --git a/packages/@aws-cdk/integ-runner/test/runner/integ-test-runner.test.ts b/packages/@aws-cdk/integ-runner/test/runner/integ-test-runner.test.ts index b34c19e862a57..53bdd9f4519e0 100644 --- a/packages/@aws-cdk/integ-runner/test/runner/integ-test-runner.test.ts +++ b/packages/@aws-cdk/integ-runner/test/runner/integ-test-runner.test.ts @@ -559,4 +559,33 @@ describe('IntegTest runIntegTests', () => { debug, })); }); + + test('with custom app run command for JavaScript', () => { + // WHEN + const integTest = new IntegTestRunner({ + cdk: cdkMock.cdk, + test: new IntegTest({ + fileName: 'test/test-data/xxxxx.test-with-snapshot.js', + discoveryRoot: 'test/test-data', + }), + appCommand: 'node --no-warnings {filePath}', + }); + integTest.runIntegTestCase({ + testCaseName: 'xxxxx.test-with-snapshot', + }); + + // THEN + expect(deployMock).toHaveBeenCalledTimes(2); + expect(destroyMock).toHaveBeenCalledTimes(1); + expect(synthFastMock).toHaveBeenCalledTimes(1); + expect(deployMock).toHaveBeenCalledWith(expect.objectContaining({ + app: 'node --no-warnings xxxxx.test-with-snapshot.js', + })); + expect(synthFastMock).toHaveBeenCalledWith(expect.objectContaining({ + execCmd: ['node', '--no-warnings', 'xxxxx.test-with-snapshot.js'], + })); + expect(destroyMock).toHaveBeenCalledWith(expect.objectContaining({ + app: 'node --no-warnings xxxxx.test-with-snapshot.js', + })); + }); });