Skip to content

Commit b620490

Browse files
committed
fix(e2e): show command output on error
This change updates the CLI e2e test spec so that it prints the full output of whatever command fails during execution. This change also includes some tidying of the e2e test output in general so it's hopefully easier to follow, for example avoiding jest's console.log wrapper. Assisted-by: Cursor Desktop rh-pre-commit.version: 2.3.2 rh-pre-commit.check-secrets: ENABLED
1 parent 8488f62 commit b620490

3 files changed

Lines changed: 64 additions & 47 deletions

File tree

e2e-tests/community-plugin-build-package.test.ts

Lines changed: 56 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,18 @@ const exec = promisify(require('child_process').exec);
99

1010
const CONTAINER_TOOL = process.env.CONTAINER_TOOL || 'podman';
1111

12+
const LOG_PREFIX = '[e2e]';
13+
14+
function log(msg: string): void {
15+
console.log(`${LOG_PREFIX} ${msg}`);
16+
}
17+
18+
function logSection(title: string): void {
19+
console.log(`${LOG_PREFIX} --- ${title} ---`);
20+
}
21+
1222
async function downloadFile(url: string, file: string): Promise<void> {
13-
console.log(`Downloading file from ${url} to ${file}`);
23+
log(`Downloading ${url} -> ${file}`);
1424
const response = await axios({
1525
method: 'GET',
1626
url: url,
@@ -31,32 +41,40 @@ async function runCommand(
3141
command: string,
3242
options: { cwd?: string } = {},
3343
): Promise<{ stdout: string; stderr: string }> {
34-
console.log(
35-
`Executing command: ${command}, in directory: ${options.cwd || process.cwd()}`,
36-
);
44+
const cwd = options.cwd || process.cwd();
3745

3846
try {
3947
const { stdout, stderr } = await exec(command, {
4048
shell: true,
4149
maxBuffer: 10 * 1024 * 1024, // 10MB buffer for large outputs
4250
...options,
4351
});
44-
console.log(`Command output: ${stdout}`);
45-
if (stderr) {
46-
console.log(`Command stderr: ${stderr}`);
47-
}
4852
return { stdout, stderr };
49-
} catch (error: any) {
50-
console.error(`\n========== COMMAND FAILED ==========`);
51-
console.error(`Command: ${command}`);
52-
console.error(`Working directory: ${options.cwd || process.cwd()}`);
53-
console.error(`Exit code: ${error.code}`);
54-
console.error(`Signal: ${error.signal}`);
55-
console.error(`\n--- STDOUT ---\n${error.stdout || '(empty)'}`);
56-
console.error(`\n--- STDERR ---\n${error.stderr || '(empty)'}`);
57-
console.error(`\n--- ERROR MESSAGE ---\n${error.message}`);
58-
console.error(`====================================\n`);
59-
throw error;
53+
} catch (err: unknown) {
54+
const e = err as {
55+
code?: string | number;
56+
signal?: string;
57+
stdout?: string;
58+
stderr?: string;
59+
};
60+
const out = (e.stdout ?? '').trim() || '(empty)';
61+
const errOut = (e.stderr ?? '').trim() || '(empty)';
62+
const enrichedMessage = [
63+
`Command failed: ${command}`,
64+
`Cwd: ${cwd}`,
65+
`Exit code: ${e.code ?? 'N/A'} | Signal: ${e.signal ?? 'N/A'}`,
66+
'--- stdout ---',
67+
out,
68+
'--- stderr ---',
69+
errOut,
70+
].join('\n');
71+
72+
console.error(`${LOG_PREFIX} COMMAND FAILED: ${command}`);
73+
console.error(`${LOG_PREFIX} cwd: ${cwd}`);
74+
console.error(`${LOG_PREFIX} --- stdout ---\n${out}`);
75+
console.error(`${LOG_PREFIX} --- stderr ---\n${errOut}`);
76+
77+
throw new Error(enrichedMessage);
6078
}
6179
}
6280

@@ -98,9 +116,10 @@ describe('export and package backstage-community plugin', () => {
98116
jest.setTimeout(TEST_TIMEOUT);
99117

100118
beforeAll(async () => {
101-
console.log(`Using rhdh-cli at: ${RHDH_CLI}`);
102-
console.log(`Test workspace: ${tmpDir}`);
103-
console.log(`Container tool: ${CONTAINER_TOOL}`);
119+
logSection('Setup');
120+
log(`rhdh-cli: ${RHDH_CLI}`);
121+
log(`workspace: ${tmpDir}`);
122+
log(`container tool: ${CONTAINER_TOOL}`);
104123

105124
let communityPluginsArchivePath = path.join(
106125
tmpDir,
@@ -109,26 +128,20 @@ describe('export and package backstage-community plugin', () => {
109128

110129
if (process.env.COMMUNITY_PLUGINS_REPO_ARCHIVE) {
111130
communityPluginsArchivePath = process.env.COMMUNITY_PLUGINS_REPO_ARCHIVE;
112-
console.log(
113-
`Using community plugins repo archive: ${communityPluginsArchivePath}`,
114-
);
131+
log(`Community plugins: path from env: ${communityPluginsArchivePath}`);
115132
}
116133

117-
if (!fs.existsSync(communityPluginsArchivePath)) {
118-
console.log(`Downloading community plugins archive from: ${REPO_URL}`);
119-
await downloadFile(REPO_URL, communityPluginsArchivePath);
120-
console.log(
121-
`Downloaded community plugins archive to: ${communityPluginsArchivePath}`,
134+
if (fs.existsSync(communityPluginsArchivePath)) {
135+
log(
136+
`Community plugins: using existing archive (skipping download): ${communityPluginsArchivePath}`,
122137
);
123138
} else {
124-
console.log(
125-
`Using existing community plugins archive: ${communityPluginsArchivePath}`,
126-
);
139+
log(`Community plugins: archive not found, downloading from ${REPO_URL}`);
140+
await downloadFile(REPO_URL, communityPluginsArchivePath);
141+
log(`Community plugins: downloaded to ${communityPluginsArchivePath}`);
127142
}
128143

129-
console.log(
130-
`Extracting community plugins archive to: ${getClonedRepoPath()}`,
131-
);
144+
log(`Community plugins: extracting to ${getClonedRepoPath()}`);
132145
fs.mkdirSync(getClonedRepoPath(), { recursive: true });
133146
await tar.x({
134147
file: communityPluginsArchivePath,
@@ -162,26 +175,24 @@ describe('export and package backstage-community plugin', () => {
162175
path.join(getClonedRepoPath(), workspacePath, pluginRelPath);
163176

164177
beforeAll(async () => {
165-
console.log(`Installing dependencies in workspace ${getWorkspacePath()}`);
178+
logSection(`Plugin: ${workspacePath}/${pluginRelPath}`);
179+
log(`Installing dependencies in workspace ${getWorkspacePath()}`);
166180
// Use YARN_ENABLE_SCRIPTS=false to skip native module builds that may fail
167-
// Then run tsc and build separately
168181
await runCommand(`YARN_ENABLE_SCRIPTS=false yarn install`, {
169182
cwd: getWorkspacePath(),
170183
});
171-
console.log(
172-
`Generating TypeScript declarations in ${getWorkspacePath()}`,
173-
);
184+
log(`Generating TypeScript declarations in ${getWorkspacePath()}`);
174185
await runCommand(`yarn tsc`, {
175186
cwd: getWorkspacePath(),
176187
});
177-
console.log(`Building plugin in ${getFullPluginPath()}`);
188+
log(`Building plugin in ${getFullPluginPath()}`);
178189
await runCommand(`yarn build`, {
179190
cwd: getFullPluginPath(),
180191
});
181192
});
182193

183194
afterAll(async () => {
184-
console.log(`Cleaning up image: ${imageTag}`);
195+
log(`Cleaning up image: ${imageTag}`);
185196
await runCommand(`${CONTAINER_TOOL} rmi -f ${imageTag}`);
186197
});
187198

@@ -221,10 +232,8 @@ describe('export and package backstage-community plugin', () => {
221232
);
222233

223234
const imageMetadata = await getImageMetadata(imageTag);
224-
console.log(
225-
`Image annotations: ${JSON.stringify(imageMetadata.annotations)}`,
226-
);
227-
console.log(`Image labels: ${JSON.stringify(imageMetadata.labels)}`);
235+
log(`Image annotations: ${JSON.stringify(imageMetadata.annotations)}`);
236+
log(`Image labels: ${JSON.stringify(imageMetadata.labels)}`);
228237

229238
// There needs to be at least one annotation (the default dynamic plugin annotation)
230239
expect(imageMetadata.annotations).not.toBeNull();

e2e-tests/jest.config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ const tsJestTransformCfg = createDefaultPreset().transform;
55
/** @type {import("jest").Config} **/
66
module.exports = {
77
testEnvironment: 'node',
8+
setupFilesAfterEnv: ['e2e-tests/setup.js'],
89
transform: {
910
...tsJestTransformCfg,
1011
},

e2e-tests/setup.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// Plain console output for e2e tests (no Jest "console.log" label or stack trace)
2+
console.log = (...args) => {
3+
process.stdout.write(args.map(String).join(' ') + '\n');
4+
};
5+
console.error = (...args) => {
6+
process.stderr.write(args.map(String).join(' ') + '\n');
7+
};

0 commit comments

Comments
 (0)