diff --git a/rascal-vscode-extension/src/test/vscode-suite/utils.ts b/rascal-vscode-extension/src/test/vscode-suite/utils.ts index 6bdffe9c6..b5a42cdb7 100644 --- a/rascal-vscode-extension/src/test/vscode-suite/utils.ts +++ b/rascal-vscode-extension/src/test/vscode-suite/utils.ts @@ -27,7 +27,8 @@ import { assert, expect } from "chai"; import { createHash } from "crypto"; -import { readFile, stat, unlink, writeFile } from "fs/promises"; +import { existsSync } from "fs"; +import { readdir, readFile, stat, unlink, writeFile } from "fs/promises"; import * as os from 'os'; import path from "path/posix"; import { env } from "process"; @@ -524,40 +525,72 @@ async function assureDebugLevelLoggingIsEnabled() { export function printRascalOutputOnFailure(channel: 'Language Parametric Rascal' | 'Rascal MPL') { const ZOOM_OUT_FACTOR = 5; + const N_LOG_LINES = 250; + // We guess some locations where the logs can be, since we cannot easily retrieve those from VS Code. + const TEST_STORAGE_DIRS = [ + path.join(path.resolve(), "uitests"), // typical CI path + path.join(os.tmpdir(), "vscode-uitests") // typical local path + ]; + afterEach("print output in case of failure", async function () { if (!this.currentTest || this.currentTest.state !== "failed") { return; } - const bbp = new BottomBarPanel(); - try { - for (let z = 0; z < ZOOM_OUT_FACTOR; z++) { - await new Workbench().executeCommand('workbench.action.zoomOut'); - } - await bbp.maximize(); - console.log('**********************************************'); - console.log('***** Rascal MPL output for the failed tests: '); - let textLines: WebElement[] = []; - let tries = 0; - while (textLines.length === 0 && tries < 3) { - await showRascalOutput(bbp, channel); - textLines = await ignoreFails(bbp.findElements(By.className('view-line'))) ?? []; - tries++; - } - if (textLines.length === 0) { - console.log("We could not capture the output lines"); - } - for (const l of textLines) { - console.log(await l.getText()); + console.log('**********************************************'); + console.log(`***** ${channel} output for the failed tests: `); + + let foundLogs = false; + for (const vsCodeDir of TEST_STORAGE_DIRS) { + try { + const logDir = path.join(vsCodeDir, "settings", "logs"); + if (existsSync(logDir)) { + for (const entry of await readdir(logDir, {recursive: true})) { + if (entry.includes("usethesource.rascalmpl") && entry.includes(channel)) { + console.log(`***** ${entry}`); + const contents = await readFile(path.join(logDir, entry), {encoding: "utf-8"}); + console.log(contents.split('\n').splice(-N_LOG_LINES).join('\n')); + foundLogs = true; + } + } + } + } catch (e) { + console.log(`Error capturing logs in ${vsCodeDir}: `, e); } - } catch (e) { - console.log('Error capturing output: ', e); } - finally { - console.log('*******End output*****************************'); - for (let z = 0; z < ZOOM_OUT_FACTOR; z++) { - await new Workbench().executeCommand('workbench.action.zoomIn'); + + if (!foundLogs) { + // Fall back to legacy copy-from-VS Code approach if there were no log files. + const bbp = new BottomBarPanel(); + try { + for (let z = 0; z < ZOOM_OUT_FACTOR; z++) { + await new Workbench().executeCommand('workbench.action.zoomOut'); + } + await bbp.maximize(); + let textLines: WebElement[] = []; + let tries = 0; + while (textLines.length === 0 && tries < 3) { + await showRascalOutput(bbp, channel); + textLines = await ignoreFails(bbp.findElements(By.className('view-line'))) ?? []; + tries++; + } + if (textLines.length === 0) { + console.log("We could not capture the output lines"); + } + + for (const l of textLines) { + console.log(await l.getText()); + } + } catch (e) { + console.log('Error capturing output: ', e); + } + finally { + for (let z = 0; z < ZOOM_OUT_FACTOR; z++) { + await new Workbench().executeCommand('workbench.action.zoomIn'); + } + await bbp.closePanel(); } - await bbp.closePanel(); } + + console.log('*******End output*****************************'); }); }