@salesforce/salesforcedx-vscode-test-tools
Version:
Test automation framework for Salesforce Extensions for VS Code
334 lines • 16.3 kB
JavaScript
;
/*
* 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
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.setSettingValue = void 0;
exports.inWorkspaceSettings = inWorkspaceSettings;
exports.inUserSettings = inUserSettings;
exports.enableBooleanSetting = enableBooleanSetting;
exports.disableBooleanSetting = disableBooleanSetting;
exports.isBooleanSettingEnabled = isBooleanSettingEnabled;
const vscode_extension_tester_1 = require("vscode-extension-tester");
const commandPrompt_1 = require("../ui-interaction/commandPrompt");
const miscellaneous_1 = require("../core/miscellaneous");
const workbench_1 = require("../ui-interaction/workbench");
/**
* Finds a setting in VSCode settings UI and checks its value
* @param id - The ID of the setting to find
* @returns Object containing the setting and its current value
* @throws Error if the setting cannot be found
* @private
*/
async function findAndCheckSetting(id) {
(0, miscellaneous_1.log)(`enter findAndCheckSetting for id: ${id}`);
await (0, commandPrompt_1.executeQuickPick)('Preferences: Clear Settings Search Results', miscellaneous_1.Duration.seconds(2));
try {
const input = await (0, workbench_1.getBrowser)().findElement(vscode_extension_tester_1.By.css('div.suggest-input-container'));
await input.click();
const textArea = await (0, workbench_1.getBrowser)().findElement(vscode_extension_tester_1.By.css('textarea.inputarea.monaco-mouse-cursor-text'));
await textArea.sendKeys(id);
await (0, miscellaneous_1.pause)(miscellaneous_1.Duration.seconds(2));
let checkButton = null;
let checkButtonValue = null;
await (0, workbench_1.getBrowser)().wait(async () => {
checkButton = (await (0, miscellaneous_1.findElementByText)('div', 'aria-label', id));
if (checkButton) {
checkButtonValue = await checkButton.getAttribute('aria-checked');
(0, miscellaneous_1.log)(`found setting checkbox with value "${checkButtonValue}"`);
return true;
}
return false;
}, 5000, `Could not find setting with name: ${id}`);
if (!checkButton) {
throw new Error(`Could not find setting with name: ${id}`);
}
(0, miscellaneous_1.log)(`findAndCheckSetting result for ${id} found ${!!checkButton} value: ${checkButtonValue}`);
return { checkButton, checkButtonValue };
}
catch (error) {
(0, miscellaneous_1.log)(`error in findAndCheckSetting for ${id}: ${error}`);
(0, miscellaneous_1.log)(`trying to find setting by id: ${id}`);
const settingsEditor = new vscode_extension_tester_1.SettingsEditor();
const setting = await settingsEditor.findSettingByID(id);
(0, miscellaneous_1.log)(`found setting by id: ${id} ${setting}`);
return { checkButton: setting, checkButtonValue: String(await setting.getValue()) };
}
}
/**
* Opens the workspace settings editor
*/
async function inWorkspaceSettings() {
await (0, commandPrompt_1.executeQuickPick)('Preferences: Open Workspace Settings', miscellaneous_1.Duration.seconds(5));
}
/**
* Opens the user settings editor
*/
async function inUserSettings() {
await (0, commandPrompt_1.executeQuickPick)('Preferences: Open User Settings', miscellaneous_1.Duration.seconds(5));
}
/**
* Toggles a boolean setting to the specified state
* @param id - The ID of the setting to toggle
* @param finalState - The desired final state (true for enabled, false for disabled)
* @param settingsType - Whether to modify user or workspace settings
* @returns The final state of the setting after toggling
* @private
*/
async function toggleBooleanSetting(id, finalState, settingsType) {
const settingsFunction = settingsType === 'workspace' ? inWorkspaceSettings : inUserSettings;
await settingsFunction();
let result = await findAndCheckSetting(id);
if (finalState !== undefined) {
if ((finalState && result.checkButtonValue === 'true') || (!finalState && result.checkButtonValue === 'false')) {
return true;
}
}
await result.checkButton.click();
result = await findAndCheckSetting(id);
return result.checkButtonValue === 'true';
}
/**
* Enables a boolean setting
* @param id - The ID of the setting to enable
* @param settingsType - Whether to modify user or workspace settings, defaults to workspace
* @returns True if the setting was successfully enabled
*/
async function enableBooleanSetting(id, settingsType = 'workspace') {
(0, miscellaneous_1.log)(`enableBooleanSetting ${id}`);
return toggleBooleanSetting(id, true, settingsType);
}
/**
* Disables a boolean setting
* @param id - The ID of the setting to disable
* @param settingsType - Whether to modify user or workspace settings, defaults to workspace
* @returns True if the setting was successfully disabled
*/
async function disableBooleanSetting(id, settingsType = 'workspace') {
(0, miscellaneous_1.log)(`disableBooleanSetting ${id}`);
return toggleBooleanSetting(id, false, settingsType);
}
/**
* Checks if a boolean setting is enabled
* @param id - The ID of the setting to check
* @param settingsType - Whether to check user or workspace settings, defaults to workspace
* @returns True if the setting is enabled, false otherwise
*/
async function isBooleanSettingEnabled(id, settingsType = 'workspace') {
const settingsFunction = settingsType === 'workspace' ? inWorkspaceSettings : inUserSettings;
await settingsFunction();
const { checkButtonValue } = await findAndCheckSetting(id);
return checkButtonValue === 'true';
}
/**
* Sets the value of a specified setting in VSCode.
* @param id - The unique identifier of the setting to be updated.
* @param value - The new value to set for the specified setting.
* @param isWorkspace - True if the setting is a workspace setting; false if it's a user setting.
* @returns A promise that resolves when the setting value has been updated.
*/
const setSettingValue = async (id, value, isWorkspace) => {
await (isWorkspace ? inWorkspaceSettings() : inUserSettings());
try {
// Try the original implementation using RedHat page objects
const settingsEditor = new vscode_extension_tester_1.SettingsEditor();
const logLevelSetting = await settingsEditor.findSettingByID(id);
await logLevelSetting?.setValue(value);
}
catch (error) {
// Fallback for VS Code 1.90.0+ where .native-edit-context selector doesn't exist
(0, miscellaneous_1.log)(`Primary findSettingByID failed, using fallback implementation for VS Code 1.90.0+: ${error}`);
try {
const browser = (0, workbench_1.getBrowser)();
// Alternative selectors for the search input in newer VS Code versions
const searchSelectors = [
'.inputarea.monaco-mouse-cursor-text',
'input[placeholder*="Search settings"]',
];
let searchInput;
for (const selector of searchSelectors) {
try {
searchInput = await browser.findElement(vscode_extension_tester_1.By.css(selector));
break;
}
catch {
// Try next selector
}
}
if (!searchInput) {
throw new Error('Could not find settings search input with any known selector');
}
// Clear and search for the setting
await searchInput.clear();
await searchInput.sendKeys(id);
await (0, miscellaneous_1.pause)(miscellaneous_1.Duration.seconds(1));
// Find the setting by its title (last part of the ID) using robust approach
const title = id.split('.').pop();
let settingElement;
// Wait for settings to load and stabilize
await (0, miscellaneous_1.pause)(miscellaneous_1.Duration.seconds(1));
// Try to find setting items using multiple selector approaches
const itemSelectors = [
'.setting-item',
'.settings-row-inner-container',
'.setting-list-item',
'[data-key]'
];
let items = [];
for (const selector of itemSelectors) {
try {
items = await browser.findElements(vscode_extension_tester_1.By.css(selector));
if (items.length > 0)
break;
}
catch {
// Try next selector
}
}
if (items.length === 0) {
throw new Error('Could not find any setting items with known selectors');
}
// Search through items to find the matching setting
for (const item of items) {
try {
// Try to find the setting label/title within the item
const labelSelectors = [
'.setting-item-label',
'.setting-item-title',
'.label-name',
'.setting-key-label',
'.monaco-label'
];
let itemTitle = '';
for (const labelSelector of labelSelectors) {
try {
const labelElement = await item.findElement(vscode_extension_tester_1.By.css(labelSelector));
itemTitle = await labelElement.getText();
if (itemTitle)
break;
}
catch {
// Try next selector
}
}
// If no label found, try getting text content directly
if (!itemTitle) {
itemTitle = await item.getText();
}
// Normalize text comparison like SettingsEditor.js does
const normalizedTitle = title?.toLowerCase().replace(/\s/g, '').trim() || '';
const normalizedItemTitle = itemTitle.toLowerCase().replace(/\s/g, '').trim();
if (normalizedItemTitle.includes(normalizedTitle) || normalizedTitle.includes(normalizedItemTitle)) {
settingElement = item;
break;
}
}
catch (err) {
// Continue to next item
}
}
if (!settingElement) {
throw new Error(`Could not find setting element for: ${title}`);
}
// Find the input/control within the setting element and set the value
const parent = await settingElement.findElement(vscode_extension_tester_1.By.xpath('..'));
const settingContainer = await parent.findElement(vscode_extension_tester_1.By.xpath('..'));
if (typeof value === 'boolean') {
const checkbox = await settingContainer.findElement(vscode_extension_tester_1.By.css('input[type="checkbox"]'));
const isChecked = await checkbox.isSelected();
if (isChecked !== value) {
await checkbox.click();
}
}
else {
// Try to find and handle different input types
let inputHandled = false;
// First, try to find a select element (dropdown)
try {
const selectElement = await settingContainer.findElement(vscode_extension_tester_1.By.css('select'));
// For select elements, we need to find the option with the desired value
const options = await selectElement.findElements(vscode_extension_tester_1.By.css('option'));
for (const option of options) {
const optionValue = await option.getAttribute('value');
const optionText = await option.getText();
// Match by value or text content
if (optionValue === value.toString() || optionText === value.toString()) {
await option.click();
inputHandled = true;
break;
}
}
if (!inputHandled) {
// If no exact match found, try partial matching
for (const option of options) {
const optionValue = await option.getAttribute('value');
const optionText = await option.getText();
if (optionValue.toLowerCase().includes(value.toString().toLowerCase()) ||
optionText.toLowerCase().includes(value.toString().toLowerCase())) {
await option.click();
inputHandled = true;
break;
}
}
}
}
catch {
// Select element not found, continue to text input
}
// If no select element found or handled, try text input
if (!inputHandled) {
try {
const textInput = await settingContainer.findElement(vscode_extension_tester_1.By.css('input[type="text"], textarea'));
await textInput.clear();
await textInput.sendKeys(value.toString());
inputHandled = true;
}
catch {
// Text input not found
}
}
// If still not handled, try more input types
if (!inputHandled) {
try {
const input = await settingContainer.findElement(vscode_extension_tester_1.By.css('input, textarea, select'));
const inputType = await input.getTagName();
if (inputType === 'select') {
// Handle select that wasn't caught above
const options = await input.findElements(vscode_extension_tester_1.By.css('option'));
for (const option of options) {
const optionText = await option.getText();
if (optionText === value.toString()) {
await option.click();
inputHandled = true;
break;
}
}
}
else {
// Handle other input types
await input.clear();
await input.sendKeys(value.toString());
inputHandled = true;
}
}
catch {
// No input found
}
}
if (!inputHandled) {
throw new Error(`Could not find or handle input control for setting: ${title}`);
}
}
(0, miscellaneous_1.log)(`Successfully set setting ${id} to ${value} using fallback implementation`);
}
catch (fallbackError) {
(0, miscellaneous_1.log)(`Both primary and fallback implementations failed: ${fallbackError}`);
throw new Error(`Failed to set setting ${id}: ${fallbackError}`);
}
}
};
exports.setSettingValue = setSettingValue;
//# sourceMappingURL=settings.js.map