UNPKG

@salesforce/salesforcedx-vscode-test-tools

Version:
341 lines 17.8 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.moveCursorWithFallback = void 0; exports.getTextEditor = getTextEditor; exports.checkFileOpen = checkFileOpen; exports.waitForFileOpen = waitForFileOpen; exports.attemptToFindTextEditorText = attemptToFindTextEditorText; exports.overrideTextInFile = overrideTextInFile; exports.waitForAndGetCodeLens = waitForAndGetCodeLens; exports.replaceLineInFile = replaceLineInFile; const vscode_extension_tester_1 = require("vscode-extension-tester"); const commandPrompt_1 = require("./commandPrompt"); const miscellaneous_1 = require("../core/miscellaneous"); const workbench_1 = require("./workbench"); const retryUtils_1 = require("../retryUtils"); const fs = __importStar(require("fs/promises")); const fileSystem_1 = require("../system-operations/fileSystem"); /** * Gets a text editor for a specific file * @param workbench - The VSCode workbench instance * @param fileName - Name of the file to open and edit * @returns A TextEditor instance for the specified file */ async function getTextEditor(workbench, fileName) { (0, miscellaneous_1.log)(`calling getTextEditor(${fileName})`); (0, miscellaneous_1.log)('getTextEditor() - Attempting to open file'); const inputBox = await (0, commandPrompt_1.executeQuickPick)('Go to File...', miscellaneous_1.Duration.seconds(1)); (0, miscellaneous_1.log)('getTextEditor() - executeQuickPick() - inputBox'); await inputBox.setText(fileName); (0, miscellaneous_1.log)(`getTextEditor() - executeQuickPick() - inputBox.setText(${fileName})`); await inputBox.confirm(); (0, miscellaneous_1.log)('getTextEditor() - executeQuickPick() - inputBox.confirm()'); await (0, miscellaneous_1.pause)(miscellaneous_1.Duration.seconds(1)); (0, miscellaneous_1.log)('getTextEditor() - File opened, getting editor view'); const editorView = workbench.getEditorView(); // Add retry logic specifically around the openEditor call that fails const textEditor = await (0, retryUtils_1.retryOperation)(async () => { (0, miscellaneous_1.log)('getTextEditor() - Attempting to open editor...'); return (await editorView.openEditor(fileName)); }, 3, 'Failed to open editor after retries'); await (0, miscellaneous_1.pause)(miscellaneous_1.Duration.seconds(2)); return textEditor; } /** * Checks if a file is open in the editor * @param workbench - The VSCode workbench instance * @param name - The name of the file to check * @param options - Optional configuration including timeout and error message * @throws Timeout error if the file isn't open within the specified timeout */ async function checkFileOpen(workbench, name, options = { timeout: miscellaneous_1.Duration.milliseconds(30_000) }) { await (0, workbench_1.getBrowser)().wait(async () => { try { const editorView = workbench.getEditorView(); const activeTab = await editorView.getActiveTab(); if (activeTab != undefined && name == (await activeTab.getTitle())) { return true; } else return false; } catch (error) { return false; } }, options.timeout?.milliseconds, options.msg ?? `Expected to find file ${name} open in TextEditor before ${options.timeout}`, 500 // Check every 500 ms ); } /** * Waits for a file to be open in the editor with a 30-second timeout * @param workbench - The VSCode workbench instance * @param fileName - Name of the file to wait for * @returns Promise that resolves when file is open or rejects on timeout */ async function waitForFileOpen(workbench, fileName) { const timeout = 20_000; // 20 seconds const checkInterval = 500; // Check every 500ms const startTime = Date.now(); const endTime = startTime + timeout; let attemptCount = 0; (0, miscellaneous_1.log)(`waitForFileOpen() - Starting wait for file: ${fileName}`); (0, miscellaneous_1.log)(`waitForFileOpen() - Timeout: ${timeout}ms, Check interval: ${checkInterval}ms`); while (Date.now() < endTime) { attemptCount++; const currentTime = Date.now(); const elapsedTime = currentTime - startTime; const remainingTime = endTime - currentTime; (0, miscellaneous_1.log)(`waitForFileOpen() - Attempt ${attemptCount}, Elapsed: ${elapsedTime}ms, Remaining: ${remainingTime}ms`); try { const editorView = workbench.getEditorView(); (0, miscellaneous_1.log)(`waitForFileOpen() - Got editor view`); // Try to get the active tab with a shorter timeout let activeTab; try { // Use a promise race to implement our own timeout for getActiveTab activeTab = await Promise.race([ editorView.getActiveTab(), new Promise((_, reject) => setTimeout(() => reject(new Error('getActiveTab timeout')), 5000)) ]); } catch (tabError) { (0, miscellaneous_1.log)(`waitForFileOpen() - getActiveTab failed: ${tabError}`); // Try alternative approach: check if any tabs exist try { const tabs = await editorView.getOpenTabs(); (0, miscellaneous_1.log)(`waitForFileOpen() - Found ${tabs.length} open tabs`); if (tabs.length > 0) { // Try to find our target file in the open tabs for (const tab of tabs) { try { const tabTitle = await tab.getTitle(); (0, miscellaneous_1.log)(`waitForFileOpen() - Checking tab: "${tabTitle}"`); if (tabTitle === fileName) { (0, miscellaneous_1.log)(`waitForFileOpen() - SUCCESS: Found target file in open tabs after ${elapsedTime}ms and ${attemptCount} attempts`); return; } } catch (titleError) { (0, miscellaneous_1.log)(`waitForFileOpen() - Error getting tab title: ${titleError}`); } } } } catch (tabsError) { (0, miscellaneous_1.log)(`waitForFileOpen() - Error getting open tabs: ${tabsError}`); } // Continue to next iteration if all approaches failed (0, miscellaneous_1.log)(`waitForFileOpen() - All tab approaches failed, continuing to wait...`); await new Promise(resolve => setTimeout(resolve, checkInterval)); continue; } if (activeTab) { const tabTitle = await activeTab.getTitle(); (0, miscellaneous_1.log)(`waitForFileOpen() - Active tab title: "${tabTitle}", Expected: "${fileName}"`); if (tabTitle === fileName) { (0, miscellaneous_1.log)(`waitForFileOpen() - SUCCESS: File ${fileName} is now open in editor after ${elapsedTime}ms and ${attemptCount} attempts`); return; // File is open, success! } else { (0, miscellaneous_1.log)(`waitForFileOpen() - File not matched, continuing to wait...`); } } else { (0, miscellaneous_1.log)(`waitForFileOpen() - No active tab found, continuing to wait...`); } } catch (error) { // Continue checking if there's an error getting editor state (0, miscellaneous_1.log)(`waitForFileOpen() - Error checking file open status (attempt ${attemptCount}): ${error}`); } // Wait before next check (0, miscellaneous_1.log)(`waitForFileOpen() - Waiting ${checkInterval}ms before next check...`); await new Promise(resolve => setTimeout(resolve, checkInterval)); } // If we reach here, timeout occurred const totalElapsed = Date.now() - startTime; const errorMsg = `Timeout: File ${fileName} was not found open in editor after ${totalElapsed}ms (${attemptCount} attempts)`; (0, miscellaneous_1.log)(`waitForFileOpen() - TIMEOUT: ${errorMsg}`); throw new Error(errorMsg); } /** * Opens a file and retrieves its text content * @param filePath - The path to the file to open * @returns The text content of the file */ async function attemptToFindTextEditorText(filePath) { await (0, miscellaneous_1.openFile)(filePath); const fileName = filePath.substring(filePath.lastIndexOf(process.platform === 'win32' ? '\\' : '/') + 1); const editorView = new vscode_extension_tester_1.EditorView(); const editor = await editorView.openEditor(fileName); return await editor.getText(); } /** * Overwrites the entire content of a file using filesystem operations * @param textEditor - The text editor instance containing the file to modify * @param classText - The new content to write to the file * @throws Error if file write operation fails or content verification fails */ async function overrideTextInFile(textEditor, classText) { // Use fs.writeFileSync() to write the new content to the file try { const filePath = await textEditor.getFilePath(); // Write new content to file (0, miscellaneous_1.log)(`overrideTextInFile() - Writing content to file: ${filePath}`); (0, fileSystem_1.createOrOverwriteFile)(filePath, classText); (0, miscellaneous_1.log)(`overrideTextInFile() - Successfully wrote ${classText.length} characters to ${filePath}`); // Give the editor time to detect the file change and reload await (0, miscellaneous_1.pause)(miscellaneous_1.Duration.seconds(1)); // Verify the write was successful by reading it back const writtenContent = await fs.readFile(filePath, 'utf8'); const normalizeText = (str) => str.replace(/\s+/g, ''); const normalizedWritten = normalizeText(writtenContent); const normalizedExpected = normalizeText(classText); if (normalizedWritten !== normalizedExpected) { throw new Error(`File write verification failed. Written content does not match expected content.`); } (0, miscellaneous_1.log)('overrideTextInFile() - File content verified successfully'); } catch (error) { (0, miscellaneous_1.log)(`overrideTextInFile() - File system operation failed: ${error}`); throw new Error(`File system text replacement failed: ${error}`); } } async function waitForAndGetCodeLens(textEditor, codeLensName) { (0, miscellaneous_1.log)(`waitForAndGetCodeLens() - Waiting for code lens: ${codeLensName}`); return await (0, retryUtils_1.retryOperation)(async () => { const lens = await textEditor.getCodeLens(codeLensName); if (!lens) { (0, miscellaneous_1.log)(`waitForAndGetCodeLens() - Code lens ${codeLensName} NOT FOUND`); throw new Error(`Code lens ${codeLensName} not found`); } (0, miscellaneous_1.log)(`waitForAndGetCodeLens() - Code lens ${codeLensName} found`); return lens; }, 3); } /** * Wrapper function for moveCursor with fallback mechanism using inputarea monaco-mouse-cursor-text selector * @param textEditor - The text editor instance * @param line - The line number to move to * @param column - The column number to move to */ const moveCursorWithFallback = async (textEditor, line, column) => { try { // First try the original moveCursor approach await textEditor.moveCursor(line, column); (0, miscellaneous_1.log)(`moveCursorWithFallback() - Successfully moved cursor to line ${line}, column ${column} using original method`); } catch (error) { // Fallback when moveCursor fails due to .native-edit-context selector issues (0, miscellaneous_1.log)(`moveCursorWithFallback() - Original moveCursor failed, trying fallback approach: ${String(error)}`); try { // Find the editor element using the fallback selector const browser = (0, workbench_1.getBrowser)(); const editorElement = await browser.findElement(vscode_extension_tester_1.By.css('.inputarea.monaco-mouse-cursor-text')); if (!editorElement) { throw new Error('Could not find editor element using fallback selector .inputarea.monaco-mouse-cursor-text'); } (0, miscellaneous_1.log)('moveCursorWithFallback() - Found editor element using fallback selector'); // Get current coordinates (fallback method) const getCurrentCoordinates = async () => { try { return await textEditor.getCoordinates(); } catch (coordError) { (0, miscellaneous_1.log)(`moveCursorWithFallback() - getCoordinates() failed: ${String(coordError)}`); // Return a default position if coordinates can't be retrieved return [1, 1]; } }; // Check if we're at the target line const isAtLine = async (targetLine) => { try { const coords = await getCurrentCoordinates(); return coords[0] === targetLine; } catch { return false; } }; // Check if we're at the target column const isAtColumn = async (targetColumn) => { try { const coords = await getCurrentCoordinates(); return coords[1] === targetColumn; } catch { return false; } }; // Move to target line (mimic moveCursorToLine) const coordinates = await getCurrentCoordinates(); const lineGap = coordinates[0] - line; const lineKey = lineGap >= 0 ? vscode_extension_tester_1.Key.UP : vscode_extension_tester_1.Key.DOWN; for (let i = 0; i < Math.abs(lineGap); i++) { if (await isAtLine(line)) { break; } await editorElement.sendKeys(lineKey); await (0, miscellaneous_1.pause)(miscellaneous_1.Duration.milliseconds(50)); } (0, miscellaneous_1.log)(`moveCursorWithFallback() - Successfully moved cursor to line ${line} using fallback method`); // Move to target column (mimic moveCursorToColumn) const currentCoords = await getCurrentCoordinates(); const columnGap = currentCoords[1] - column; const columnKey = columnGap >= 0 ? vscode_extension_tester_1.Key.LEFT : vscode_extension_tester_1.Key.RIGHT; for (let i = 0; i < Math.abs(columnGap); i++) { if (await isAtColumn(column)) { break; } await editorElement.sendKeys(columnKey); await (0, miscellaneous_1.pause)(miscellaneous_1.Duration.milliseconds(50)); // Check if we moved to a different line (mimic original error handling) const newCoords = await getCurrentCoordinates(); if (newCoords[0] !== currentCoords[0]) { throw new Error(`Column number ${column} is not accessible on line ${currentCoords[0]}`); } } (0, miscellaneous_1.log)(`moveCursorWithFallback() - Successfully moved cursor to column ${column} using fallback method`); } catch (fallbackError) { (0, miscellaneous_1.log)(`moveCursorWithFallback() - Fallback approach also failed: ${String(fallbackError)}`); throw new Error(`Failed to move cursor using both original and fallback methods: ${String(fallbackError)}`); } } }; exports.moveCursorWithFallback = moveCursorWithFallback; /** Replace a specific line in a file using fs operations * @param filePath - The path to the file to modify * @param lineNumber - The line number to replace (1-based index) * @param newContent - The new content to write */ async function replaceLineInFile(filePath, lineNumber, newContent) { const fileContent = await fs.readFile(filePath, 'utf8'); const lines = fileContent.split('\n'); // Replace the specific line (1-based to 0-based index) lines[lineNumber - 1] = newContent; (0, fileSystem_1.createOrOverwriteFile)(filePath, lines.join('\n')); } //# sourceMappingURL=textEditorView.js.map