diff --git a/packages/@aws-cdk-testing/cli-integ/lib/process.ts b/packages/@aws-cdk-testing/cli-integ/lib/process.ts index 6dbdeab..fc5226b 100644 --- a/packages/@aws-cdk-testing/cli-integ/lib/process.ts +++ b/packages/@aws-cdk-testing/cli-integ/lib/process.ts @@ -90,9 +90,9 @@ class PtyProcess implements IProcess { this.process.onData((e) => callback(Buffer.from(e))); } - public onStderr(callback: (chunk: Buffer) => void): void { - // in a pty all streams are the same - return this.onStdout(callback); + public onStderr(_callback: (chunk: Buffer) => void): void { + // https://github.com/microsoft/node-pty/issues/71 + throw new Error(`Cannot register callback for 'stderr'. A tty does not have separate output and error channels`); } public onExit(callback: (exitCode: number) => void): void { diff --git a/packages/@aws-cdk-testing/cli-integ/lib/shell.ts b/packages/@aws-cdk-testing/cli-integ/lib/shell.ts index 5897fe5..973f110 100644 --- a/packages/@aws-cdk-testing/cli-integ/lib/shell.ts +++ b/packages/@aws-cdk-testing/cli-integ/lib/shell.ts @@ -60,12 +60,18 @@ export async function shell(command: string[], options: ShellOptions = {}): Prom if (interaction) { if (interaction.prompt.test(lastLine.get())) { + // subprocess expects a user input now. - // we have to write the input AFTER the child has started - // reading, so we do this with a small delay. + // first, shift the interactions to ensure the same interaction is not reused + remainingInteractions.shift(); + + // then, reset the last line to prevent repeated matches caused by tty echoing + lastLine.reset(); + + // now write the input with a slight delay to ensure + // the child process has already started reading. setTimeout(() => { child.writeStdin(interaction.input + (interaction.end ?? os.EOL)); - remainingInteractions.shift(); }, 500); } @@ -73,14 +79,23 @@ export async function shell(command: string[], options: ShellOptions = {}): Prom }); - child.onStderr(chunk => { - if (show === 'always') { - writeToOutputs(chunk.toString('utf-8')); - } - if (options.captureStderr ?? true) { - stderr.push(chunk); - } - }); + if (tty && options.captureStderr === false) { + // in a tty stderr goes to the same fd as stdout + throw new Error(`Cannot disable 'captureStderr' in tty`); + } + + if (!tty) { + // in a tty stderr goes to the same fd as stdout, so onStdout + // is sufficient. + child.onStderr(chunk => { + if (show === 'always') { + writeToOutputs(chunk.toString('utf-8')); + } + if (options.captureStderr ?? true) { + stderr.push(chunk); + } + }); + } child.onError(reject); @@ -309,4 +324,8 @@ class LastLine { public get(): string { return this.lastLine; } + + public reset() { + this.lastLine = ''; + } } \ No newline at end of file diff --git a/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cdk-import-interactive.integtest.ts b/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cdk-import-interactive.integtest.ts index 6533c9c..499bba5 100644 --- a/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cdk-import-interactive.integtest.ts +++ b/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cdk-import-interactive.integtest.ts @@ -27,14 +27,18 @@ integTest('cdk import prompts the user for sns topic arns', withDefaultFixture(a await fixture.cdk(['import', fullStackName], { interact: [ { - prompt: /\(empty to skip\)/, + prompt: /Topic1.*\(empty to skip\):/, input: topic1Arn, }, { - prompt: /\(empty to skip\)/, + prompt: /Topic2.*\(empty to skip\):/, input: topic2Arn, } - ] + ], + modEnv: { + // disable coloring because it messes up prompt matching. + FORCE_COLOR: '0' + } }); // assert the stack now has the two topics