Skip to content

Commit

Permalink
feat: Add support for array string settings
Browse files Browse the repository at this point in the history
Signed-off-by: Dominik Jelinek <[email protected]>
  • Loading branch information
djelinek committed Apr 12, 2024
1 parent 75b9be2 commit 788339f
Show file tree
Hide file tree
Showing 5 changed files with 346 additions and 10 deletions.
12 changes: 11 additions & 1 deletion packages/locators/lib/1.37.0.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,17 @@ const editor = {
checkboxSetting: By.className('setting-value-checkbox'),
checkboxChecked: 'aria-checked',
linkButton: By.className('edit-in-settings-button'),
itemCount: By.className('settings-count-widget')
itemCount: By.className('settings-count-widget'),
arraySetting: By.className('setting-item-control'),
arrayRoot: By.xpath(`.//div[@role='list' and contains(@class, 'setting-list-widget')]`),
arrayRow: By.className('setting-list-row'),
arrayRowValue: By.className('setting-list-value'),
arrayNewRow: By.className('setting-list-new-row'),
arrayEditRow: By.className('setting-list-edit-row'),
arrayBtnConstructor: (label: string) => By.xpath(`.//a[contains(@role, 'button') and @aria-label='${label}']`),
arraySettingItem: {
btnConstructor: (label: string) => By.xpath(`.//a[contains(@role, 'button') and text()='${label}']`)
}
},
DiffEditor: {
originalEditor: By.className('original-in-monaco-diff-editor'),
Expand Down
201 changes: 196 additions & 5 deletions packages/page-objects/src/components/editor/SettingsEditor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ export class SettingsEditor extends Editor {
* Context menu is disabled in this editor, throw an error
*/
async openContextMenu(): Promise<ContextMenu> {
throw new Error('Operation not supported');
throw new Error('Operation not supported!');
}

private async createSetting(element: WebElement, title: string, category: string): Promise<Setting> {
Expand All @@ -132,7 +132,13 @@ export class SettingsEditor extends Editor {
await element.findElement(SettingsEditor.locators.SettingsEditor.linkButton);
return new LinkSetting(SettingsEditor.locators.SettingsEditor.settingConstructor(title, category), this);
} catch (err) {
throw new Error('Setting type not supported');
// try array setting
try {
await element.findElement(SettingsEditor.locators.SettingsEditor.arraySetting);
return new ArraySetting(SettingsEditor.locators.SettingsEditor.settingConstructor(title, category), this);
} catch (err) {
throw new Error('Setting type not supported!');
}
}
}
}
Expand All @@ -142,7 +148,7 @@ export class SettingsEditor extends Editor {

/**
* Abstract item representing a Setting with title, description and
* an input element (combo/textbox/checkbox/link)
* an input element (combo/textbox/checkbox/link/array)
*/
export abstract class Setting extends AbstractElement {

Expand Down Expand Up @@ -274,11 +280,11 @@ export class CheckboxSetting extends Setting {
export class LinkSetting extends Setting {

async getValue(): Promise<string> {
throw new Error('Method getValue is not available for LinkSetting');
throw new Error('Method getValue is not available for LinkSetting!');
}

async setValue(value: string | boolean): Promise<void> {
throw new Error('Method setValue is not available for LinkSetting');
throw new Error('Method setValue is not available for LinkSetting!');
}

/**
Expand All @@ -290,3 +296,188 @@ export class LinkSetting extends Setting {
await link.click();
}
}

/**
* TODO
*/
export class ArraySetting extends Setting {

/**
* @deprecated Method 'getValue' is not available for ArraySetting!
*/
async getValue(): Promise<string | boolean> {
throw new Error('Method \'getValue\' is not available for ArraySetting!');
}

/**
* @deprecated Method 'setValue' is not available for ArraySetting!
*/
async setValue(value: string | boolean): Promise<void> {
throw new Error('Method \'setValue\' is not available for ArraySetting!');
}

/**
* TODO
*/
async select(item: string): Promise<void> {
const toSelect = await this.getItem(item);
await toSelect?.select()
}

/**
* TODO
*/
async getItem(item: string | number): Promise<ArraySettingItem | undefined> {
const row = await this.findRow(item);
if(row) {
return new ArraySettingItem(row, this);
}
return undefined;
}

/**
* TODO
*/
async getItems(): Promise<ArraySettingItem[]> {
const listRows = await this.getRows();
let items: ArraySettingItem[] = [];
for(const row of listRows) {
items.push(new ArraySettingItem(row, this));
}
return items;
}

/**
* TODO
*/
async getValues(): Promise<string[]> {
const items = await this.getItems();
let values: string[] = [];
for(const item of items) {
values.push(await item.getValue());
}
return values;
}

/**
* TODO
*/
async add(): Promise<ArraySettingItem> {
// click 'Add Item' button
const button = await this.findElement(SettingsEditor.locators.SettingsEditor.arrayNewRow).findElement(By.className('monaco-button'));
await button.click();

// get item row switched to 'edit' mode
const list = await this.getListRootElement();
const editRow = await list.findElement(SettingsEditor.locators.SettingsEditor.arrayEditRow);
return new ArraySettingItem(editRow, this);
}

/**
* TODO
*/
async edit(item: string | number): Promise<ArraySettingItem | undefined> {
const row = await this.findRow(item);
if(row) {
// select item row
const toEdit = new ArraySettingItem(row, this);
await toEdit.select();

// click 'Edit Item' button
const edit = await toEdit.findElement(SettingsEditor.locators.SettingsEditor.arrayBtnConstructor('Edit Item'));
await edit.click();

// get item row switched to 'edit' mode
const list = await this.getListRootElement();
const editRow = await list.findElement(SettingsEditor.locators.SettingsEditor.arrayEditRow);
return new ArraySettingItem(editRow, this);
}
return undefined;
}

private async getListRootElement(): Promise<WebElement> {
return await this.findElement(SettingsEditor.locators.SettingsEditor.arrayRoot);
}

private async getRows(): Promise<WebElement[]> {
const list = await this.getListRootElement();
return await list.findElements(SettingsEditor.locators.SettingsEditor.arrayRow);
}

private async findRow(item: string | number): Promise<WebElement | undefined> {
const listRows = await this.getRows();
if(Number.isInteger(item)) {
const index = +item;
if (index < 0 || index > listRows.length - 1) {
throw Error(`Index '${index}' is of bounds! Found items have length = ${listRows.length}.`);
}
return listRows[index];
} else {
for(const row of listRows) {
const li = await row.findElement(SettingsEditor.locators.SettingsEditor.arrayRowValue);
if(await li.getText() === item) {
return row;
}
}
}
return undefined;
}
}

/**
* TODO
*/
export class ArraySettingItem extends AbstractElement {

constructor(element: WebElement, setting: ArraySetting) {
super(element, setting);
}

/**
* TODO
*/
async select(): Promise<void> {
await this.click();
}

/**
* TODO
*/
async getValue(): Promise<string> {
return await this.getText();
}

/**
* TODO
*/
async setValue(value: string): Promise<void> {
const input = await this.findElement(SettingsEditor.locators.SettingsEditor.textSetting);
await input.clear();
await input.sendKeys(value);
}

/**
* TODO
*/
async remove(): Promise<void> {
await this.select();
const remove = await this.findElement(SettingsEditor.locators.SettingsEditor.arrayBtnConstructor('Remove Item'));
await remove.click();
}

/**
* TODO
*/
async ok(): Promise<void> {
const ok = await this.findElement(SettingsEditor.locators.SettingsEditor.arraySettingItem.btnConstructor('OK'));
await ok.click();
}

/**
* TODO
*/
async cancel(): Promise<void> {
const cancel = await this.findElement(SettingsEditor.locators.SettingsEditor.arraySettingItem.btnConstructor('Cancel'));
await cancel.click();
}
}
10 changes: 10 additions & 0 deletions packages/page-objects/src/locators/locators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,16 @@ export interface Locators {
checkboxChecked: string
linkButton: By
itemCount: By
arraySetting: By
arrayRoot: By
arrayRow: By
arrayRowValue: By
arrayNewRow: By
arrayEditRow: By
arrayBtnConstructor: (label: string) => By
arraySettingItem: {
btnConstructor: (label: string) => By
}
}
DiffEditor: {
originalEditor: By
Expand Down
15 changes: 14 additions & 1 deletion tests/test-project/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@
}
],
"configuration": {
"title": "Test Project",
"title": "ExTester Tests",
"properties": {
"testProject.general.helloWorld": {
"type": "boolean",
Expand All @@ -151,6 +151,19 @@
"testProject.enableCodeLens": {
"type": "boolean",
"default": false
},
"testProject.general.helloWorldArray": {
"type": "array",
"uniqueItems": true,
"items": {
"type": "string"
},
"additionalProperties": false,
"markdownDescription": "This is an example array of strings",
"default": [
"Hello World",
"Hello ExTester"
]
}
}
},
Expand Down
Loading

0 comments on commit 788339f

Please sign in to comment.