Skip to content

Commit

Permalink
feat: Add support for Extension Editor View (#1527)
Browse files Browse the repository at this point in the history
Co-authored-by: Dominik Jelinek <[email protected]>
  • Loading branch information
pospisilf and djelinek authored Oct 2, 2024
1 parent c49de57 commit af602bf
Show file tree
Hide file tree
Showing 8 changed files with 441 additions and 0 deletions.
23 changes: 23 additions & 0 deletions docs/ExtensionEditorDetailsSections.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<img width="1512" alt="ExtensionEditorDetailsSections" src="https://github.com/user-attachments/assets/b795e36c-41b2-4251-9d2a-58585377dfe0">

#### Lookup

```typescript
import { ExtensionEditorDetailsSection } from 'vscode-extension-tester';
...
const extensionEditorDetails = new ExtensionEditorDetailsSection();
```

You can get values using following functions:

```typescript
await extensionEditorDetails.getCategories();

await extensionEditorDetails.getResources();

await extensionEditorDetails.getMoreInfo();

await extensionEditorDetails.getMoreInfoItem("Identifier");

await extensionEditorDetails.getReadme(); // currently not supported (Blocked by https://github.com/redhat-developer/vscode-extension-tester/issues/1492)
```
37 changes: 37 additions & 0 deletions docs/ExtensionEditorView.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<img width="1512" alt="ExtensionEditorView" src="https://github.com/user-attachments/assets/df5a4809-7fa6-4417-9024-a9a35b8257e4">

#### Lookup

```typescript
import { ExtensionEditorView } from 'vscode-extension-tester';
...
const extensionEditor = new ExtensionEditorView();
```

#### Get values from opened extension

You can get individual values using following functions:

```typescript
await extensionEditor.getName();

await extensionEditor.getVersion();

await extensionEditor.getPublisher();

await extensionEditor.getDescription();

await extensionEditor.getCount();
```

#### Manage tabs

Tabs section can be managed by this editor as well. For work with 'Details' you can use ExtensionEditorDetailsSection.

```typescript
await extensionEditor.getTabs();

await extensionEditor.switchToTab("tabname");

await extensionEditor.getActiveTab();
```
21 changes: 21 additions & 0 deletions packages/locators/lib/1.37.0.ts
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,27 @@ const editor = {
container: (id: string) => By.id(id),
attribute: 'aria-flowto',
},
ExtensionEditorView: {
constructor: By.className('extension-editor'),
name: By.className('name'),
version: By.className('version'),
publisher: By.className('publisher-name'),
description: By.className('description'),
count: By.className('count'),
navbar: By.className('navbar'),
tab: By.className('action-label'),
activeTab: By.xpath(`.//a[starts-with(@class, 'action-label checked')]`),
specificTab: (tabname: string) => By.xpath(`.//a[starts-with(@class, 'action-label') and text()='${tabname}']`),
},
ExtensionEditorDetailsSection: {
categoriesContainer: By.className('categories'),
category: By.className('category'),
resourcesContainer: By.className('resources'),
resource: By.className('resource'),
moreInfoContainer: By.className('more-info'),
moreInfo: By.className('more-info-entry'),
moreInfoElements: By.xpath('./*'),
},
};

const menu = {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License", destination); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { ExtensionEditorView, WebView } from '../..';

export class ExtensionEditorDetailsSection extends ExtensionEditorView {
/**
* Get all categories of extension.
* @returns Promise resolving categories of extension.
*/
async getCategories(): Promise<string[]> {
const categories: string[] = [];

const container = await this.findElement(ExtensionEditorDetailsSection.locators.ExtensionEditorDetailsSection.categoriesContainer);
const categoriesInContainer = await container.findElements(ExtensionEditorDetailsSection.locators.ExtensionEditorDetailsSection.category);

for (const cat of categoriesInContainer) {
categories.push(await cat.getText());
}
return categories;
}

/**
* Get all resources of extension.
* @returns Promise resolving resources of extension.
*/
async getResources(): Promise<string[]> {
const resources: string[] = [];

const container = await this.findElement(ExtensionEditorDetailsSection.locators.ExtensionEditorDetailsSection.resourcesContainer);
const resourcesInContainer = await container.findElements(ExtensionEditorDetailsSection.locators.ExtensionEditorDetailsSection.resource);

for (const res of resourcesInContainer) {
resources.push(await res.getText());
}

return resources;
}

/**
* Get content of More Info section.
* @returns Promise resolving content of 'More Info' section.
*/
async getMoreInfo(): Promise<{ [key: string]: string }> {
const moreInfo: { [key: string]: string } = {};

const container = await this.findElement(ExtensionEditorDetailsSection.locators.ExtensionEditorDetailsSection.moreInfoContainer);
const moreInfoInContainer = await container.findElements(ExtensionEditorDetailsSection.locators.ExtensionEditorDetailsSection.moreInfo);

for (const entry of moreInfoInContainer) {
const elmnts = await entry.findElements(ExtensionEditorDetailsSection.locators.ExtensionEditorDetailsSection.moreInfoElements);
const name = await (await elmnts.at(0))?.getText();
const value = await (await elmnts.at(1))?.getText();
if (name !== undefined && value !== undefined) {
moreInfo[name] = value;
}
}

return moreInfo;
}

/**
* Get value of specific attribute from 'More Info' section.
* @param key Name of attribute.
* @returns Promise resolving value for specified attribute.
*/
async getMoreInfoItem(key: string): Promise<string> {
const moreInfo = await this.getMoreInfo();
return moreInfo[key];
}

/**
* Blocked by https://github.com/redhat-developer/vscode-extension-tester/issues/1492
*/
async getReadme(): Promise<WebView> {
throw Error('Not implemented yet.');
}
}
105 changes: 105 additions & 0 deletions packages/page-objects/src/components/editor/ExtensionEditorView.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License", destination); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { Editor, EditorGroup, EditorView } from '../..';

export class ExtensionEditorView extends Editor {
constructor(view: EditorView | EditorGroup = new EditorView()) {
super(view, ExtensionEditorView.locators.ExtensionEditorView.constructor);
}

/**
* Get name of extension.
* @returns Promise resolving name of extension.
*/
async getName(): Promise<string> {
const name = await this.findElement(ExtensionEditorView.locators.ExtensionEditorView.name);
return await name?.getText();
}

/**
* Get version of extension.
* @returns Promise resolving version of extension.
*/
async getVersion(): Promise<string> {
const name = await this.findElement(ExtensionEditorView.locators.ExtensionEditorView.version);
return await name?.getText();
}

/**
* Get publisher of extension.
* @returns Promise resolving publisher of extension.
*/
async getPublisher(): Promise<string> {
const name = await this.findElement(ExtensionEditorView.locators.ExtensionEditorView.publisher);
return await name?.getText();
}

/**
* Get description of extension.
* @returns Promise description name of opened extension.
*/
async getDescription(): Promise<string> {
const name = await this.findElement(ExtensionEditorView.locators.ExtensionEditorView.description);
return await name?.getText();
}

/**
* Get count of extension.
* @returns Promise resolving count of opened extension.
*/
async getCount(): Promise<string> {
const count = await this.findElement(ExtensionEditorView.locators.ExtensionEditorView.count);
return await count?.getText();
}

/**
* Get available tabs.
* @returns Promise resolving tabs of opened extension.
*/
async getTabs(): Promise<string[]> {
const tabs: string[] = [];
const navbar = await this.findElement(ExtensionEditorView.locators.ExtensionEditorView.navbar);
const els = await navbar.findElements(ExtensionEditorView.locators.ExtensionEditorView.tab);
for (const element of els) {
tabs.push(await element.getText());
}
return tabs;
}

/**
* Switch to different tab.
* @param tabName Name of required tab to be switched on.
* @returns Promise resolving to true if tabs were switched successfully, false otherwise.
*/
async switchToTab(tabName: string): Promise<boolean> {
const navbar = await this.findElement(ExtensionEditorView.locators.ExtensionEditorView.navbar);
const requiredTab = await navbar.findElement(ExtensionEditorView.locators.ExtensionEditorView.specificTab(tabName));
await requiredTab.click();
return (await this.getActiveTab()).toLowerCase() === tabName.toLowerCase();
}

/**
* Get name of opened tab.
* @returns Promise resolving name of opened tab.
*/
async getActiveTab(): Promise<string> {
const navbar = await this.findElement(ExtensionEditorView.locators.ExtensionEditorView.navbar);
const features = await navbar.findElement(ExtensionEditorView.locators.ExtensionEditorView.activeTab);
return await features.getText();
}
}
2 changes: 2 additions & 0 deletions packages/page-objects/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ export * from './components/editor/DiffEditor';
export * from './components/editor/WebView';
export * from './components/editor/ContentAssist';
export * from './components/editor/CustomEditor';
export * from './components/editor/ExtensionEditorView';
export * from './components/editor/ExtensionEditorDetailsSection';

export { Notification, NotificationType } from './components/workbench/Notification';
export * from './components/workbench/NotificationsCenter';
Expand Down
21 changes: 21 additions & 0 deletions packages/page-objects/src/locators/locators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,27 @@ export interface Locators {
container: (id: string) => By;
attribute: string;
};
ExtensionEditorView: {
constructor: By;
name: By;
version: By;
publisher: By;
description: By;
count: By;
navbar: By;
tab: By;
activeTab: By;
specificTab: (tabname: string) => By;
};
ExtensionEditorDetailsSection: {
categoriesContainer: By;
category: By;
resourcesContainer: By;
resource: By;
moreInfoContainer: By;
moreInfo: By;
moreInfoElements: By;
};

// Menus
ContextMenu: {
Expand Down
Loading

0 comments on commit af602bf

Please sign in to comment.