@aws-cdk-testing/cli-integ
Version:
Integration tests for the AWS CDK CLI
111 lines (94 loc) • 3.67 kB
text/typescript
import * as fs from 'fs';
import * as path from 'path';
import { MemoryStream } from './corking';
const SKIP_TESTS = fs.readFileSync(path.join(__dirname, '..', 'skip-tests.txt'), { encoding: 'utf-8' })
.split('\n')
.map(x => x.trim())
.filter(x => x && !x.startsWith('#'));
if (SKIP_TESTS.length > 0) {
process.stderr.write(`ℹ️ Skipping tests: ${JSON.stringify(SKIP_TESTS)}\n`);
}
// Whether we want to stop after the first failure, for quicker debugging (hopefully).
const FAIL_FAST = process.env.FAIL_FAST === 'true';
// Keep track of whether the suite has failed. If so, we stop running.
let failed = false;
export interface TestContext {
readonly randomString: string;
readonly name: string;
readonly output: NodeJS.WritableStream;
log(s: string): void;
}
/**
* A wrapper for jest's 'test' which takes regression-disabled tests into account and prints a banner
*/
export function integTest(
name: string,
callback: (context: TestContext) => Promise<void>,
timeoutMillis?: number,
): void {
const runner = shouldSkip(name) ? test.skip : test;
runner(name, async () => {
const output = new MemoryStream();
output.write('================================================================\n');
output.write(`${name}\n`);
output.write('================================================================\n');
const now = Date.now();
process.stderr.write(`[INTEG TEST::${name}] Starting (pid ${process.pid})...\n`);
try {
if (FAIL_FAST && failed) {
throw new Error('FAIL_FAST requested and currently failing. Stopping test early.');
}
return await callback({
output,
randomString: randomString(),
name,
log(s: string) {
output.write(`${s}\n`);
},
});
} catch (e: any) {
failed = true;
// Print the buffered output, only if the test fails.
output.write(e.message);
output.write(e.stack);
process.stderr.write(`[INTEG TEST::${name}] Failed: ${e}\n`);
const isGitHub = !!process.env.GITHUB_RUN_ID;
if (isGitHub) {
// GitHub Actions compatible output formatting
// https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/workflow-commands-for-github-actions#setting-an-error-message
let written = process.stderr.write(`::error title=Failed ${name}::${e.message}\n`);
if (!written) {
// Wait for drain
await new Promise((ok) => process.stderr.once('drain', ok));
}
// Print output only if the test fails. Use 'console.log' so the output is buffered by
// jest and prints without a stack trace (if verbose: false).
written = process.stdout.write([
`::group::Failure details: ${name} (click to expand)\n`,
`${output.buffer().toString()}\n`,
'::endgroup::\n',
].join(''));
if (!written) {
// Wait for drain
await new Promise((ok) => process.stdout.once('drain', ok));
}
} else {
// Use 'console.log' so the output is buffered by
// jest and prints without a stack trace (if verbose: false).
// eslint-disable-next-line no-console
console.log(output.buffer().toString());
}
throw e;
} finally {
const duration = Date.now() - now;
process.stderr.write(`[INTEG TEST::${name}] Done (${duration} ms).\n`);
}
}, timeoutMillis);
}
function shouldSkip(testName: string) {
return SKIP_TESTS.includes(testName);
}
export function randomString() {
// Crazy
return Math.random().toString(36).replace(/[^a-z0-9]+/g, '');
}