UNPKG

@salesforce/salesforcedx-vscode-test-tools

Version:
342 lines 18.1 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; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.TestSetup = void 0; /* * Copyright (c) 2024, salesforce.com, inc. * All rights reserved. * Licensed under the BSD 3-Clause license. * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause */ const path = __importStar(require("path")); const fs_1 = __importDefault(require("fs")); const environmentSettings_1 = require("./environmentSettings"); const core = __importStar(require("./core/index")); const types_1 = require("./core/types"); const system_operations_1 = require("./system-operations"); const testing_1 = require("./testing"); const ui_interaction_1 = require("./ui-interaction"); const salesforce_components_1 = require("./salesforce-components"); const retryUtils_1 = require("./retryUtils"); class TestSetup { testSuiteSuffixName = ''; // this needs to be defined in EnvironmentSettings with the default being os.tmpDir() tempFolderPath = path.join(process.cwd(), 'e2e-temp'); projectFolderPath; testDataFolderPath; aliasAndUserNameWereVerified = false; scratchOrgAliasName; scratchOrgId; configuredExtensions = []; constructor() { // Private constructor to prevent direct instantiation - use TestSetup.setUp() instead } get tempProjectName() { return 'TempProject-' + this.testSuiteSuffixName; } static async setUp(testReqConfig) { const testSetup = new TestSetup(); testSetup.testSuiteSuffixName = testReqConfig.testSuiteSuffixName; core.log(''); core.log(`${testSetup.testSuiteSuffixName} - Starting TestSetup.setUp()...`); // Configure extensions based on test requirements testSetup.configureExtensions(testReqConfig); /* The expected workspace will be open up after setUpTestingWorkspace */ await testSetup.setUpTestingWorkspace(testReqConfig.projectConfig); await (0, ui_interaction_1.executeQuickPick)('View: Close All Editors'); if (testReqConfig.projectConfig.projectShape !== types_1.ProjectShapeOption.NONE) { await (0, testing_1.verifyExtensionsAreRunning)(testSetup.getExtensionsToVerify()); if (process.platform === 'darwin') testSetup.setJavaHomeConfigEntry(); // Extra config needed for Apex LSP on GHA if (testReqConfig.isOrgRequired) { await (0, salesforce_components_1.setUpScratchOrg)(testSetup); } await (0, testing_1.reloadAndEnableExtensions)(); // This is necessary in order to update JAVA home path } testSetup.setWindowDialogStyle(); testSetup.setWorkbenchHoverDelay(); testSetup.setMaximumWindowSize(); await (0, ui_interaction_1.reloadWindow)(); // reload window to apply settings core.log(`${testSetup.testSuiteSuffixName} - ...finished TestSetup.setUp()`); return testSetup; } /** * Configure extensions based on test requirements * @param testReqConfig Test requirement configuration */ configureExtensions(testReqConfig) { // Start with all default extensions from salesforceExtensions this.configuredExtensions = testReqConfig.extensionConfigs || []; testReqConfig.extensionConfigs = testReqConfig.extensionConfigs || testing_1.extensions; // If extensionConfigs is provided, configure the specific extensions if (testReqConfig.extensionConfigs) { if (testReqConfig.extensionConfigs.length === 0) { // Empty array means no extensions this.configuredExtensions = []; } else { // For each configured extension, update the corresponding default extension or add a new one for (const extConfig of testReqConfig.extensionConfigs) { const existingExtIndex = this.configuredExtensions.findIndex(ext => ext.extensionId === extConfig.extensionId); if (existingExtIndex >= 0) { // Update existing extension configuration this.configuredExtensions[existingExtIndex] = { ...this.configuredExtensions[existingExtIndex], shouldInstall: extConfig.shouldInstall, shouldVerifyActivation: extConfig.shouldVerifyActivation, vsixPath: extConfig.vsixPath || this.configuredExtensions[existingExtIndex].vsixPath }; } else { // Add new extension configuration this.configuredExtensions.push({ extensionId: extConfig.extensionId, name: extConfig.name || extConfig.extensionId, // Use provided name or extensionId as name vsixPath: extConfig.vsixPath || '', shouldInstall: extConfig.shouldInstall, shouldVerifyActivation: extConfig.shouldVerifyActivation }); } } } } // For backward compatibility: handle excludedExtensions by setting shouldInstall to 'never' if (testReqConfig.excludedExtensions && testReqConfig.excludedExtensions.length > 0) { for (const excludedExtId of testReqConfig.excludedExtensions) { const extIndex = this.configuredExtensions.findIndex(ext => ext.extensionId === excludedExtId); if (extIndex >= 0) { this.configuredExtensions[extIndex].shouldInstall = 'never'; this.configuredExtensions[extIndex].shouldVerifyActivation = false; } } } // Update the global extensions variable to use our configured extensions // This ensures compatibility with any code that still uses the global extensions Object.assign(testing_1.extensions, this.configuredExtensions); core.log(`${this.testSuiteSuffixName} - Configured ${this.configuredExtensions.length} extensions for testing`); } /** * Get extensions that should be verified during test setup */ getExtensionsToVerify() { return this.configuredExtensions.filter(ext => ext.shouldVerifyActivation); } /** * Get extensions that should be installed with a specific installation option * @param option Installation option to filter by */ getExtensionsToInstall(option) { return this.configuredExtensions.filter(ext => ext.shouldInstall === option); } async tearDown(shouldCheckForUncaughtErrors = true) { if (shouldCheckForUncaughtErrors) await (0, testing_1.checkForUncaughtErrors)(); try { await (0, system_operations_1.deleteScratchOrg)(this.scratchOrgAliasName); } catch (error) { core.log(`Deleting scratch org (or info) failed with Error: ${error.message}`); } } async initializeNewSfProject() { if (!fs_1.default.existsSync(this.tempFolderPath)) { (0, system_operations_1.createFolder)(this.tempFolderPath); } await (0, system_operations_1.generateSfProject)(this.tempProjectName, this.tempFolderPath); // generate a sf project for 'new' this.projectFolderPath = path.join(this.tempFolderPath, this.tempProjectName); } async setUpTestingWorkspace(projectConfig) { core.log(`${this.testSuiteSuffixName} - Starting setUpTestingWorkspace()...`); let projectName; switch (projectConfig.projectShape) { case types_1.ProjectShapeOption.NEW: await this.initializeNewSfProject(); break; case types_1.ProjectShapeOption.NAMED: if (projectConfig.githubRepoUrl) { // verify if folder matches the github repo url const repoExists = await (0, system_operations_1.gitRepoExists)(projectConfig.githubRepoUrl); if (!repoExists) { this.throwError(`Repository does not exist or is inaccessible: ${projectConfig.githubRepoUrl}`); } const repoName = (0, system_operations_1.getRepoNameFromUrl)(projectConfig.githubRepoUrl); if (!repoName) { this.throwError(`Unable to determine repository name from URL: ${projectConfig.githubRepoUrl}`); } else { projectName = repoName; if (projectConfig.folderPath) { const localProjName = (0, system_operations_1.getFolderName)(projectConfig.folderPath); if (localProjName !== repoName) { this.throwError(`The local project ${localProjName} does not match the required Github repo ${repoName}`); } else { // If it is a match, use the local folder directly. Local dev use only. this.projectFolderPath = projectConfig.folderPath; } } else { // Clone the project from Github URL directly this.projectFolderPath = path.join(this.tempFolderPath, repoName); await (0, system_operations_1.gitClone)(projectConfig.githubRepoUrl, this.projectFolderPath); } } } else { // missing info, throw an error this.throwError(`githubRepoUrl is required for named project shape`); } break; case types_1.ProjectShapeOption.ANY: // ANY: workspace is designated to open when redhat vscode-extension-tester is initialized if (projectConfig.folderPath) { this.projectFolderPath = projectConfig.folderPath; projectName = (0, system_operations_1.getFolderName)(projectConfig.folderPath); } else { // Fallback: if no folder specified, create a new sf project instead await this.initializeNewSfProject(); } break; case types_1.ProjectShapeOption.NONE: // NONE: no project open in the workspace by default /* create the e2e-temp folder to benefit further testing */ this.projectFolderPath = path.join(this.tempFolderPath, this.tempProjectName); if (!fs_1.default.existsSync(this.tempFolderPath)) { (0, system_operations_1.createFolder)(this.tempFolderPath); } break; default: this.throwError(`Invalid project shape: ${projectConfig.projectShape}`); } if ([types_1.ProjectShapeOption.NAMED, types_1.ProjectShapeOption.NEW].includes(projectConfig.projectShape)) { core.log(`Project folder to open: ${this.projectFolderPath}`); // Verify the project was loaded. await (0, retryUtils_1.retryOperation)(async () => { if (this.projectFolderPath) { await core.openFolder(this.projectFolderPath); await (0, ui_interaction_1.verifyProjectLoaded)(projectName ?? this.tempProjectName); } else { this.throwError('Project folder path is not set'); } }); } } throwError(message) { core.log(message); throw new Error(message); } updateScratchOrgDefWithEdition(scratchOrgEdition) { if (scratchOrgEdition === 'enterprise') { if (!this.projectFolderPath) { this.throwError('Project folder path is not set'); return; // This line will never be reached, but helps TypeScript understand } const projectScratchDefPath = path.join(this.projectFolderPath, 'config', 'project-scratch-def.json'); let projectScratchDef = fs_1.default.readFileSync(projectScratchDefPath, 'utf8'); projectScratchDef = projectScratchDef.replace(`"edition": "Developer"`, `"edition": "Enterprise"`); fs_1.default.writeFileSync(projectScratchDefPath, projectScratchDef, 'utf8'); } } setJavaHomeConfigEntry() { if (!this.projectFolderPath) { this.throwError('Project folder path is not set'); return; // This line will never be reached, but helps TypeScript understand } const vscodeSettingsPath = path.join(this.projectFolderPath, '.vscode', 'settings.json'); if (!environmentSettings_1.EnvironmentSettings.getInstance().javaHome) { return; } if (!fs_1.default.existsSync(path.dirname(vscodeSettingsPath))) { fs_1.default.mkdirSync(path.dirname(vscodeSettingsPath), { recursive: true }); } let settings = fs_1.default.existsSync(vscodeSettingsPath) ? JSON.parse(fs_1.default.readFileSync(vscodeSettingsPath, 'utf8')) : {}; settings = { ...settings, ...(process.env.JAVA_HOME ? { 'salesforcedx-vscode-apex.java.home': process.env.JAVA_HOME } : {}) }; fs_1.default.writeFileSync(vscodeSettingsPath, JSON.stringify(settings, null, 2), 'utf8'); core.log(`${this.testSuiteSuffixName} - Set 'salesforcedx-vscode-apex.java.home' to '${process.env.JAVA_HOME}' in ${vscodeSettingsPath}`); } setWorkbenchHoverDelay() { if (!this.projectFolderPath) { this.throwError('Project folder path is not set'); return; // This line will never be reached, but helps TypeScript understand } const vscodeSettingsPath = path.join(this.projectFolderPath, '.vscode', 'settings.json'); if (!fs_1.default.existsSync(path.dirname(vscodeSettingsPath))) { fs_1.default.mkdirSync(path.dirname(vscodeSettingsPath), { recursive: true }); } let settings = fs_1.default.existsSync(vscodeSettingsPath) ? JSON.parse(fs_1.default.readFileSync(vscodeSettingsPath, 'utf8')) : {}; // Update settings to set workbench.hover.delay settings = { ...settings, 'workbench.hover.delay': 300000 }; fs_1.default.writeFileSync(vscodeSettingsPath, JSON.stringify(settings, null, 2), 'utf8'); core.log(`${this.testSuiteSuffixName} - Set 'workbench.hover.delay' to '300000' in ${vscodeSettingsPath}`); } setMaximumWindowSize() { if (!this.projectFolderPath) { return; } const vscodeSettingsPath = path.join(this.projectFolderPath, '.vscode', 'settings.json'); if (!fs_1.default.existsSync(path.dirname(vscodeSettingsPath))) { fs_1.default.mkdirSync(path.dirname(vscodeSettingsPath), { recursive: true }); } let settings = fs_1.default.existsSync(vscodeSettingsPath) ? JSON.parse(fs_1.default.readFileSync(vscodeSettingsPath, 'utf8')) : {}; // Update settings to set window.newWindowDimensions settings = { ...settings, 'window.newWindowDimensions': 'maximized' }; fs_1.default.writeFileSync(vscodeSettingsPath, JSON.stringify(settings, null, 2), 'utf8'); core.log(`${this.testSuiteSuffixName} - Set 'window.newWindowDimensions' to 'maximized' in ${vscodeSettingsPath}`); } setWindowDialogStyle() { if (!this.projectFolderPath) { this.throwError('Project folder path is not set'); return; // This line will never be reached, but helps TypeScript understand } const vscodeSettingsPath = path.join(this.projectFolderPath, '.vscode', 'settings.json'); if (!fs_1.default.existsSync(path.dirname(vscodeSettingsPath))) { fs_1.default.mkdirSync(path.dirname(vscodeSettingsPath), { recursive: true }); } let settings = fs_1.default.existsSync(vscodeSettingsPath) ? JSON.parse(fs_1.default.readFileSync(vscodeSettingsPath, 'utf8')) : {}; // Update settings to set window.dialogStyle settings = { ...settings, 'window.dialogStyle': 'custom' }; fs_1.default.writeFileSync(vscodeSettingsPath, JSON.stringify(settings, null, 2), 'utf8'); core.log(`${this.testSuiteSuffixName} - Set 'window.dialogStyle' to 'custom' in ${vscodeSettingsPath}`); } } exports.TestSetup = TestSetup; //# sourceMappingURL=testSetup.js.map