@redhat-developer/page-objects
Version:
Page Object API implementation for a VS Code editor used by ExTester framework.
379 lines • 14.3 kB
JavaScript
"use strict";
/**
* 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.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.EditorTab = exports.EditorGroup = exports.EditorView = exports.EditorTabNotFound = void 0;
const selenium_webdriver_1 = require("selenium-webdriver");
const __1 = require("../..");
const AbstractElement_1 = require("../AbstractElement");
const ElementWithContextMenu_1 = require("../ElementWithContextMenu");
const DiffEditor_1 = require("./DiffEditor");
const EditorAction_1 = require("./EditorAction");
const SettingsEditor_1 = require("./SettingsEditor");
const WebView_1 = require("./WebView");
class EditorTabNotFound extends Error {
constructor(title, group) {
super(`No editor with title '${title}' in group '${group}' available`);
}
}
exports.EditorTabNotFound = EditorTabNotFound;
/**
* View handling the open editors
*/
class EditorView extends AbstractElement_1.AbstractElement {
constructor() {
super(EditorView.locators.EditorView.constructor, EditorView.locators.Workbench.constructor);
}
/**
* Switch to an editor tab with the given title
* @param title title of the tab
* @param groupIndex zero based index for the editor group (0 for the left most group)
* @returns Promise resolving to Editor object
*/
async openEditor(title, groupIndex = 0) {
const group = await this.getEditorGroup(groupIndex);
return group.openEditor(title);
}
/**
* Close an editor tab with the given title
* @param title title of the tab
* @param groupIndex zero based index for the editor group (0 for the left most group)
* @returns Promise resolving when the tab's close button is pressed
*/
async closeEditor(title, groupIndex = 0) {
const group = await this.getEditorGroup(groupIndex);
return group.closeEditor(title);
}
/**
* Close all open editor tabs
* @param groupIndex optional index to specify an editor group
* @returns Promise resolving once all tabs have had their close button pressed
*/
async closeAllEditors(groupIndex) {
let groups = await this.getEditorGroups();
if (groupIndex !== undefined) {
return groups[groupIndex].closeAllEditors();
}
while (groups.length > 0 && (await groups[0].getOpenEditorTitles()).length > 0) {
await groups[0].closeAllEditors();
await new Promise((res) => setTimeout(res, 1000));
groups = await this.getEditorGroups();
}
}
/**
* Retrieve all open editor tab titles in an array
* @param groupIndex optional index to specify an editor group, if left empty will search all groups
* @returns Promise resolving to array of editor titles
*/
async getOpenEditorTitles(groupIndex) {
const groups = await this.getEditorGroups();
if (groupIndex !== undefined) {
return groups[groupIndex].getOpenEditorTitles();
}
const titles = [];
for (const group of groups) {
titles.push(...(await group.getOpenEditorTitles()));
}
return titles;
}
/**
* Retrieve an editor tab from a given group by title
* @param title title of the tab
* @param groupIndex zero based index of the editor group, default 0 (leftmost one)
* @returns promise resolving to EditorTab object
*/
async getTabByTitle(title, groupIndex = 0) {
const group = await this.getEditorGroup(groupIndex);
return group.getTabByTitle(title);
}
/**
* Retrieve all open editor tabs
* @param groupIndex index of group to search for tabs, if left undefined, all groups are searched
* @returns promise resolving to EditorTab list
*/
async getOpenTabs(groupIndex) {
const groups = await this.getEditorGroups();
if (groupIndex !== undefined) {
return groups[groupIndex].getOpenTabs();
}
const tabs = [];
for (const group of groups) {
tabs.push(...(await group.getOpenTabs()));
}
return tabs;
}
/**
* Retrieve the active editor tab
* @returns promise resolving to EditorTab object, undefined if no tab is active
*/
async getActiveTab() {
const tabs = await this.getOpenTabs();
for (const tab of tabs) {
if (await tab.isSelected()) {
return tab;
}
}
return undefined;
}
/**
* Retrieve all editor groups in a list, sorted left to right
* @returns promise resolving to an array of EditorGroup objects
*/
async getEditorGroups() {
const elements = await this.findElements(EditorGroup.locators.EditorView.editorGroup);
const groups = await Promise.all(elements.map(async (element, index) => new EditorGroup(element, this, index).wait()));
// sort the groups by x coordinates, so the leftmost is always at index 0
for (let i = 0; i < groups.length - 1; i++) {
for (let j = 0; j < groups.length - i - 1; j++) {
if ((await groups[j].getRect()).x > (await groups[j + 1].getRect()).x) {
const temp = groups[j];
groups[j] = groups[j + 1];
groups[j + 1] = temp;
}
}
}
return groups;
}
/**
* Retrieve an editor group with a given index (counting from left to right)
* @param index zero based index of the editor group (leftmost group has index 0)
* @returns promise resolving to an EditorGroup object
*/
async getEditorGroup(index) {
return (await this.getEditorGroups())[index];
}
/**
* Get editor actions of a select editor group
* @param groupIndex zero based index of the editor group (leftmost group has index 0), default 0
* @returns promise resolving to list of EditorAction objects
*/
async getActions(groupIndex = 0) {
const group = await this.getEditorGroup(groupIndex);
return group.getActions();
}
/**
* Get editor action of a select editor group, search by title or predicate
* @param predicateOrTitle title or predicate to be used in search process
* @param groupIndex zero based index of the editor group (leftmost group has index 0), default 0
* @returns promise resolving to EditorAction object if found, undefined otherwise
*/
async getAction(predicateOrTitle, groupIndex = 0) {
const group = await this.getEditorGroup(groupIndex);
return group.getAction(predicateOrTitle);
}
}
exports.EditorView = EditorView;
/**
* Page object representing an editor group
*/
class EditorGroup extends AbstractElement_1.AbstractElement {
index;
constructor(element, view = new EditorView(), index = 0) {
super(element, view);
this.index = index;
}
/**
* Switch to an editor tab with the given title
* @param title title of the tab
* @returns Promise resolving to Editor object
*/
async openEditor(title) {
const tab = await this.getTabByTitle(title);
await tab.select();
try {
await this.findElement(EditorView.locators.EditorView.settingsEditor);
return new SettingsEditor_1.SettingsEditor(this).wait();
}
catch (err) {
try {
await this.findElement(EditorView.locators.EditorView.webView);
return new WebView_1.WebView(this).wait();
}
catch (err) {
try {
await this.findElement(EditorView.locators.EditorView.diffEditor);
return new DiffEditor_1.DiffEditor(this).wait();
}
catch (err) {
return new __1.TextEditor(this).wait();
}
}
}
}
/**
* Close an editor tab with the given title
* @param title title of the tab
* @returns Promise resolving when the tab's close button is pressed
*/
async closeEditor(title) {
const tab = await this.getTabByTitle(title);
const closeButton = await tab.findElement(EditorView.locators.EditorView.closeTab);
await closeButton.click();
}
/**
* Close all open editor tabs
* @returns Promise resolving once all tabs have had their close button pressed
*/
async closeAllEditors() {
let titles = await this.getOpenEditorTitles();
while (titles.length > 0) {
await this.closeEditor(titles[0]);
try {
// check if the group still exists
await this.getTagName();
}
catch (err) {
break;
}
titles = await this.getOpenEditorTitles();
}
}
/**
* Retrieve all open editor tab titles in an array
* @returns Promise resolving to array of editor titles
*/
async getOpenEditorTitles() {
const tabs = await this.findElements(EditorView.locators.EditorView.tab);
const titles = [];
for (const tab of tabs) {
try {
const title = await new EditorTab(tab, this.enclosingItem).getTitle();
titles.push(title);
}
catch (e) {
if (e instanceof selenium_webdriver_1.error.StaleElementReferenceError) {
continue;
}
throw e;
}
}
return titles;
}
/**
* Retrieve an editor tab by title
* @param title title of the tab
* @returns promise resolving to EditorTab object
*/
async getTabByTitle(title) {
const tabs = await this.findElements(EditorView.locators.EditorView.tab);
for (const element of tabs) {
try {
const tab = new EditorTab(element, this.enclosingItem);
const label = await tab.getTitle();
if (label === title) {
return tab;
}
}
catch (e) {
if (e instanceof selenium_webdriver_1.error.StaleElementReferenceError) {
continue;
}
throw e;
}
}
throw new EditorTabNotFound(title, this.index);
}
/**
* Retrieve all open editor tabs
* @returns promise resolving to EditorTab list
*/
async getOpenTabs() {
const tabs = await this.findElements(EditorView.locators.EditorView.tab);
return Promise.all(tabs.map(async (tab) => new EditorTab(tab, this.enclosingItem).wait()));
}
/**
* Retrieve the active editor tab
* @returns promise resolving to EditorTab object, undefined if no tab is active
*/
async getActiveTab() {
const tabs = await this.getOpenTabs();
for (const tab of tabs) {
if (await tab.isSelected()) {
return tab;
}
}
return undefined;
}
/**
* Retrieve the editor action buttons as EditorActions
* @returns promise resolving to list of EditorAction objects
*/
async getActions() {
const actions = await this.findElement(EditorGroup.locators.EditorView.actionContainer).findElements(EditorGroup.locators.EditorView.actionItem);
return Promise.all(actions.map(async (action) => {
const dropdown = await action.getAttribute(EditorGroup.locators.EditorView.dropdown);
if (dropdown) {
return new EditorAction_1.EditorActionDropdown(action, this);
}
else {
return new EditorAction_1.EditorAction(action, this);
}
}));
}
/**
* Find an editor action button by predicate or title
* @param predicateOrTitle predicate/title to be used
* @returns promise resolving to EditorAction representing the button if found, undefined otherwise
*/
async getAction(predicateOrTitle) {
const predicate = typeof predicateOrTitle === 'string' ? async (action) => (await action.getTitle()) === predicateOrTitle : predicateOrTitle;
const actions = await this.getActions();
for (const action of actions) {
if (await predicate(action)) {
return action;
}
}
return undefined;
}
}
exports.EditorGroup = EditorGroup;
/**
* Page object for editor view tab
*/
class EditorTab extends ElementWithContextMenu_1.ElementWithContextMenu {
constructor(element, view) {
super(element, view);
}
/**
* Get the tab title as string
*/
async getTitle() {
const label = await this.findElement(EditorTab.locators.Editor.title);
return await label.getText();
}
/**
* Select (click) the tab
*/
async select() {
const tabCoords = await this.getRect();
await this.getDriver()
.actions()
.move({
x: Math.ceil(tabCoords.x + 10),
y: Math.ceil(tabCoords.y + 10),
})
.click()
.perform();
}
async isSelected() {
const klass = await this.getAttribute('class');
const segments = klass?.split(/\s+/g) ?? [];
return (await super.isSelected()) || segments.includes('active');
}
}
exports.EditorTab = EditorTab;
//# sourceMappingURL=EditorView.js.map