che-server/e2e/pageobjects/ide/Ide.ts

282 lines
12 KiB
TypeScript

/*********************************************************************
* Copyright (c) 2019 Red Hat, Inc.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
**********************************************************************/
import axios from 'axios';
import { DriverHelper } from '../../utils/DriverHelper';
import { injectable, inject } from 'inversify';
import { CLASSES, TYPES } from '../../inversify.types';
import { TestConstants } from '../../TestConstants';
import { By, WebElement, error } from 'selenium-webdriver';
import { ITestWorkspaceUtil } from '../../utils/workspace/ITestWorkspaceUtil';
import { WorkspaceStatus } from '../../utils/workspace/WorkspaceStatus';
export enum RightToolbarButton {
Explorer = 'Explorer',
Git = 'Git',
Debug = 'Debug'
}
@injectable()
export class Ide {
public static readonly EXPLORER_BUTTON_XPATH: string = '(//ul[@class=\'p-TabBar-content\']//li[@title=\'Explorer\'])[1]';
public static readonly SELECTED_EXPLORER_BUTTON_XPATH: string = '(//ul[@class=\'p-TabBar-content\']//li[@title=\'Explorer\' and contains(@class, \'p-mod-current\')])[1]';
public static readonly ACTIVATED_IDE_IFRAME_CSS: string = '#ide-iframe-window[aria-hidden=\'false\']';
public static readonly SELECTED_GIT_BUTTON_XPATH: string = '(//ul[@class=\'p-TabBar-content\']//li[@title=\'Git\' and contains(@class, \'p-mod-current\')])[1]';
private static readonly TOP_MENU_PANEL_CSS: string = '#theia-app-shell #theia-top-panel .p-MenuBar-content';
private static readonly LEFT_CONTENT_PANEL_CSS: string = '#theia-left-content-panel';
private static readonly PRELOADER_CSS: string = '.theia-preload';
private static readonly IDE_IFRAME_CSS: string = 'iframe#ide-application-iframe';
constructor(
@inject(CLASSES.DriverHelper) private readonly driverHelper: DriverHelper,
@inject(TYPES.WorkspaceUtil) private readonly testWorkspaceUtil: ITestWorkspaceUtil) { }
async waitAndSwitchToIdeFrame(timeout: number = TestConstants.TS_SELENIUM_LOAD_PAGE_TIMEOUT) {
await this.driverHelper.waitAndSwitchToFrame(By.css(Ide.IDE_IFRAME_CSS), timeout);
}
async waitNotification(notificationText: string, timeout: number = TestConstants.TS_SELENIUM_DEFAULT_TIMEOUT) {
const notificationLocator: By = By.xpath(this.getNotificationXpathLocator(notificationText));
await this.driverHelper.waitVisibility(notificationLocator, timeout);
}
async waitNotificationAndClickOnButton(notificationText: string,
buttonText: string,
timeout: number = TestConstants.TS_SELENIUM_DEFAULT_TIMEOUT) {
await this.driverHelper.getDriver().wait(async () => {
await this.waitNotification(notificationText, timeout);
await this.clickOnNotificationButton(notificationText, buttonText);
try {
await this.waitNotificationDisappearance(notificationText);
return true;
} catch (err) {
if (!(err instanceof error.TimeoutError)) {
throw err;
}
console.log(`After clicking on "${buttonText}" button of the notification with text "${notificationText}" \n` +
'it is still visible (issue #14121), try again.');
await this.driverHelper.wait(TestConstants.TS_SELENIUM_DEFAULT_POLLING);
}
}, timeout);
}
async waitNotificationAndConfirm(notificationText: string, timeout: number = TestConstants.TS_SELENIUM_DEFAULT_TIMEOUT) {
await this.waitNotificationAndClickOnButton(notificationText, 'yes', timeout);
}
async waitNotificationAndOpenLink(notificationText: string, timeout: number = TestConstants.TS_SELENIUM_DEFAULT_TIMEOUT) {
await this.waitApllicationIsReady(await this.getApplicationUrlFromNotification(notificationText));
await this.waitNotificationAndClickOnButton(notificationText, 'Open Link', timeout);
}
async isNotificationPresent(notificationText: string): Promise<boolean> {
const notificationLocator: By = By.xpath(this.getNotificationXpathLocator(notificationText));
return await this.driverHelper.waitVisibilityBoolean(notificationLocator);
}
async waitNotificationDisappearance(notificationText: string,
attempts: number = TestConstants.TS_SELENIUM_DEFAULT_ATTEMPTS,
polling: number = TestConstants.TS_SELENIUM_DEFAULT_POLLING) {
const notificationLocator: By = By.xpath(this.getNotificationXpathLocator(notificationText));
await this.driverHelper.waitDisappearance(notificationLocator, attempts, polling);
}
async clickOnNotificationButton(notificationText: string, buttonText: string) {
const notificationLocator: string = this.getNotificationXpathLocator(notificationText);
const yesButtonLocator: string = notificationLocator + `//button[text()=\'${buttonText}\']`;
await this.driverHelper.waitAndClick(By.xpath(yesButtonLocator));
}
async waitWorkspaceAndIde(workspaceNamespace: string,
workspaceName: string,
timeout: number = TestConstants.TS_SELENIUM_LOAD_PAGE_TIMEOUT) {
await this.waitAndSwitchToIdeFrame(timeout);
await this.testWorkspaceUtil.waitWorkspaceStatus(workspaceNamespace, workspaceName, WorkspaceStatus.RUNNING);
await this.waitIde(timeout);
}
async waitIde(timeout: number = TestConstants.TS_SELENIUM_LOAD_PAGE_TIMEOUT) {
const mainIdeParts: Array<By> = [By.css(Ide.TOP_MENU_PANEL_CSS), By.css(Ide.LEFT_CONTENT_PANEL_CSS), By.xpath(Ide.EXPLORER_BUTTON_XPATH)];
for (const idePartLocator of mainIdeParts) {
await this.driverHelper.waitVisibility(idePartLocator, timeout);
}
}
async waitRightToolbarButton(buttonTitle: RightToolbarButton, timeout: number = TestConstants.TS_SELENIUM_DEFAULT_TIMEOUT) {
const buttonLocator: By = this.getRightToolbarButtonLocator(buttonTitle);
await this.driverHelper.waitVisibility(buttonLocator, timeout);
}
async waitAndClickRightToolbarButton(buttonTitle: RightToolbarButton, timeout: number = TestConstants.TS_SELENIUM_DEFAULT_TIMEOUT) {
const buttonLocator: By = this.getRightToolbarButtonLocator(buttonTitle);
await this.driverHelper.waitAndClick(buttonLocator, timeout);
}
async waitTopMenuPanel(timeout: number = TestConstants.TS_SELENIUM_DEFAULT_TIMEOUT) {
await this.driverHelper.waitVisibility(By.css(Ide.TOP_MENU_PANEL_CSS), timeout);
}
async waitLeftContentPanel(timeout: number = TestConstants.TS_SELENIUM_DEFAULT_TIMEOUT) {
await this.driverHelper.waitVisibility(By.css(Ide.LEFT_CONTENT_PANEL_CSS));
}
async waitPreloaderAbsent(attempts: number = TestConstants.TS_SELENIUM_DEFAULT_ATTEMPTS,
polling: number = TestConstants.TS_SELENIUM_DEFAULT_POLLING) {
await this.driverHelper.waitDisappearance(By.css(Ide.PRELOADER_CSS), attempts, polling);
}
async waitStatusBarContains(expectedText: string, timeout: number = TestConstants.TS_SELENIUM_LANGUAGE_SERVER_START_TIMEOUT) {
const statusBarLocator: By = By.css('div[id=\'theia-statusBar\']');
await this.driverHelper.getDriver().wait(async () => {
const elementText: string = await this.driverHelper.waitAndGetText(statusBarLocator, timeout);
const isTextPresent: boolean = elementText.search(expectedText) > 0;
if (isTextPresent) {
return true;
}
}, timeout);
}
async waitStatusBarTextAbsence(expectedText: string, timeout: number = TestConstants.TS_SELENIUM_DEFAULT_TIMEOUT) {
const statusBarLocator: By = By.css('div[id=\'theia-statusBar\']');
// for ensuring that check is not invoked in the gap of status displaying
for (let i: number = 0; i < 3; i++) {
await this.driverHelper.getDriver().wait(async () => {
const elementText: string = await this.driverHelper.waitAndGetText(statusBarLocator, timeout);
const isTextAbsent: boolean = elementText.search(expectedText) === -1;
if (isTextAbsent) {
return true;
}
}, timeout);
}
}
async waitIdeFrameAndSwitchOnIt(timeout: number = TestConstants.TS_SELENIUM_LOAD_PAGE_TIMEOUT) {
await this.driverHelper.waitAndSwitchToFrame(By.css(Ide.IDE_IFRAME_CSS), timeout);
}
async checkLsInitializationStart(expectedTextInStatusBar: string) {
try {
await this.waitStatusBarContains(expectedTextInStatusBar, 20000);
} catch (err) {
if (!(err instanceof error.TimeoutError)) {
throw err;
}
await this.driverHelper.getDriver().navigate().refresh();
await this.waitAndSwitchToIdeFrame();
await this.waitStatusBarContains(expectedTextInStatusBar);
}
}
async closeAllNotifications() {
const notificationLocator: By = By.css('.theia-Notification');
if (! await this.driverHelper.isVisible(notificationLocator)) {
return;
}
const notifications: WebElement[] = await this.driverHelper.waitAllPresence(notificationLocator);
const notificationsCapacity: number = notifications.length;
for (let i = 1; i <= notificationsCapacity; i++) {
const notificationLocator: By = By.xpath('//div[@class=\'theia-Notification\']//button[text()=\'Close\']');
try {
await this.driverHelper.waitAndClick(notificationLocator);
} catch (err) {
if (err instanceof error.TimeoutError) {
console.log(`The '${notificationLocator}' element is not visible and can't be clicked`);
continue;
}
throw err;
}
}
}
async performKeyCombination(keyCombination: string) {
const bodyLocator: By = By.tagName('body');
await this.driverHelper.type(bodyLocator, keyCombination);
}
async waitRightToolbarButtonSelection(buttonTitle: string, timeout: number = TestConstants.TS_SELENIUM_DEFAULT_TIMEOUT) {
const selectedRightToolbarButtonLocator: By = this.getSelectedRightToolbarButtonLocator(buttonTitle);
await this.driverHelper.waitVisibility(selectedRightToolbarButtonLocator, timeout);
}
async getApplicationUrlFromNotification(notificationText: string) {
const notificationTextLocator: By = By.xpath(`//div[@class='theia-Notification']//p[contains(@id,'${notificationText}')]`);
let notification = await this.driverHelper.waitAndGetText(notificationTextLocator);
let regexp: RegExp = new RegExp('^.*(https?://.*)$');
if (!regexp.test(notification)) {
throw new Error('Cannot obtaine url from notification message');
}
return notification.split(regexp)[1];
}
async waitApllicationIsReady(url: string,
timeout: number = TestConstants.TS_SELENIUM_DEFAULT_TIMEOUT) {
await this.driverHelper.getDriver().wait(async () => {
try {
let res = await axios.get(url);
if (res.status === 200) {
console.log('Application is ready for use.');
return true;
}
} catch (error) {
console.log('Application is not yet ready for use');
}
await this.driverHelper.wait(TestConstants.TS_SELENIUM_DEFAULT_POLLING);
}, timeout);
}
private getSelectedRightToolbarButtonLocator(buttonTitle: string): By {
return By.xpath(`//div[@id='theia-left-content-panel']//ul[@class='p-TabBar-content']` +
`//li[@title='${buttonTitle}' and contains(@id, 'shell-tab')] and contains(@class, 'p-mod-current')`);
}
private getRightToolbarButtonLocator(buttonTitle: String): By {
return By.xpath(`//div[@id='theia-left-content-panel']//ul[@class='p-TabBar-content']` +
`//li[@title='${buttonTitle}' and contains(@id, 'shell-tab')]`);
}
private getNotificationXpathLocator(notificationText: string): string {
return `//div[@class='theia-Notification' and contains(@id,'${notificationText}')]`;
}
}