550 lines
21 KiB
TypeScript
550 lines
21 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 { IDriver } from '../driver/IDriver';
|
|
import { inject, injectable } from 'inversify';
|
|
import { TYPES } from '../inversify.types';
|
|
import { error, ActionSequence } from 'selenium-webdriver';
|
|
import 'reflect-metadata';
|
|
import { ThenableWebDriver, By, until, WebElement } from 'selenium-webdriver';
|
|
import { TestConstants } from '../TestConstants';
|
|
import { Logger } from './Logger';
|
|
|
|
|
|
@injectable()
|
|
export class DriverHelper {
|
|
private readonly driver: ThenableWebDriver;
|
|
|
|
constructor(@inject(TYPES.Driver) driver: IDriver) {
|
|
this.driver = driver.get();
|
|
}
|
|
|
|
public getAction(): ActionSequence {
|
|
Logger.trace('DriverHelper.getAction');
|
|
|
|
return this.driver.actions();
|
|
}
|
|
|
|
public async isVisible(locator: By): Promise<boolean> {
|
|
Logger.trace(`DriverHelper.isVisible ${locator}`);
|
|
|
|
try {
|
|
const element: WebElement = await this.driver.findElement(locator);
|
|
const isVisible: boolean = await element.isDisplayed();
|
|
return isVisible;
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public async wait(milliseconds: number) {
|
|
Logger.trace(`DriverHelper.wait (${milliseconds} milliseconds)`);
|
|
|
|
await this.driver.sleep(milliseconds);
|
|
}
|
|
|
|
public async waitVisibilityBoolean(locator: By,
|
|
attempts: number = TestConstants.TS_SELENIUM_DEFAULT_ATTEMPTS,
|
|
polling: number = TestConstants.TS_SELENIUM_DEFAULT_POLLING): Promise<boolean> {
|
|
|
|
Logger.trace(`DriverHelper.waitVisibilityBoolean ${locator}`);
|
|
|
|
for (let i = 0; i < attempts; i++) {
|
|
const isVisible: boolean = await this.isVisible(locator);
|
|
|
|
if (isVisible) {
|
|
return true;
|
|
}
|
|
|
|
await this.wait(polling);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public async waitDisappearanceBoolean(locator: By,
|
|
attempts: number = TestConstants.TS_SELENIUM_DEFAULT_ATTEMPTS,
|
|
polling: number = TestConstants.TS_SELENIUM_DEFAULT_POLLING): Promise<boolean> {
|
|
|
|
Logger.trace(`DriverHelper.waitDisappearanceBoolean ${locator}`);
|
|
|
|
for (let i = 0; i < attempts; i++) {
|
|
const isVisible: boolean = await this.isVisible(locator);
|
|
|
|
if (!isVisible) {
|
|
return true;
|
|
}
|
|
|
|
await this.wait(polling);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public async waitVisibility(elementLocator: By, timeout: number = TestConstants.TS_SELENIUM_DEFAULT_TIMEOUT): Promise<WebElement> {
|
|
const attempts: number = TestConstants.TS_SELENIUM_DEFAULT_ATTEMPTS;
|
|
const polling: number = TestConstants.TS_SELENIUM_DEFAULT_POLLING;
|
|
|
|
Logger.trace(`DriverHelper.waitVisibility ${elementLocator}`);
|
|
|
|
for (let i = 0; i < attempts; i++) {
|
|
Logger.trace('DriverHelper.waitVisibility - Waiting until element is located');
|
|
const webElement: WebElement = await this.driver.wait(until.elementLocated(elementLocator), timeout);
|
|
Logger.trace('DriverHelper.waitVisibility - Element was located. Waitng for visibility now.');
|
|
try {
|
|
const visibleWebElement = await this.driver.wait(until.elementIsVisible(webElement), timeout);
|
|
Logger.trace('DriverHelper.waitVisibility - Element is located and is visible.');
|
|
return visibleWebElement;
|
|
} catch (err) {
|
|
if (err instanceof error.StaleElementReferenceError) {
|
|
Logger.debug(`DriverHelper.waitVisibility - Stale element error - ${err}`);
|
|
await this.wait(polling);
|
|
continue;
|
|
}
|
|
throw err;
|
|
}
|
|
}
|
|
|
|
throw new error.TimeoutError(`Exceeded maximum visibility checkings attempts, problems with 'StaleElementReferenceError' of '${elementLocator}' element`);
|
|
}
|
|
|
|
public async waitPresence(elementLocator: By, timeout: number = TestConstants.TS_SELENIUM_DEFAULT_TIMEOUT): Promise<WebElement> {
|
|
const attempts: number = TestConstants.TS_SELENIUM_DEFAULT_ATTEMPTS;
|
|
const polling: number = TestConstants.TS_SELENIUM_DEFAULT_POLLING;
|
|
|
|
Logger.trace(`DriverHelper.waitPresence ${elementLocator}`);
|
|
|
|
for (let i = 0; i < attempts; i++) {
|
|
try {
|
|
const webElement: WebElement = await this.driver.wait(until.elementLocated(elementLocator), timeout);
|
|
return webElement;
|
|
} catch (err) {
|
|
if (err instanceof error.StaleElementReferenceError) {
|
|
await this.wait(polling);
|
|
continue;
|
|
}
|
|
|
|
throw err;
|
|
}
|
|
}
|
|
|
|
throw new error.TimeoutError(`Exceeded maximum presence checkings attempts, problems with 'StaleElementReferenceError' of '${elementLocator}' element`);
|
|
}
|
|
|
|
public async waitAllPresence(elementLocator: By, timeout: number = TestConstants.TS_SELENIUM_DEFAULT_TIMEOUT): Promise<Array<WebElement>> {
|
|
const attempts: number = TestConstants.TS_SELENIUM_DEFAULT_ATTEMPTS;
|
|
const polling: number = TestConstants.TS_SELENIUM_DEFAULT_POLLING;
|
|
|
|
Logger.trace(`DriverHelper.waitAllPresence ${elementLocator}`);
|
|
|
|
for (let i = 0; i < attempts; i++) {
|
|
try {
|
|
const webElements: Array<WebElement> = await this.driver.wait(until.elementsLocated(elementLocator), timeout);
|
|
return webElements;
|
|
} catch (err) {
|
|
if (err instanceof error.StaleElementReferenceError) {
|
|
await this.wait(polling);
|
|
continue;
|
|
}
|
|
|
|
throw err;
|
|
}
|
|
}
|
|
|
|
throw new error.TimeoutError(`Exceeded maximum presence checkings attempts, problems with 'StaleElementReferenceError' of '${elementLocator}' element`);
|
|
}
|
|
|
|
public async waitAllVisibility(locators: Array<By>, timeout: number = TestConstants.TS_SELENIUM_DEFAULT_TIMEOUT) {
|
|
Logger.trace(`DriverHelper.waitAllVisibility ${locators}`);
|
|
|
|
for (const elementLocator of locators) {
|
|
await this.waitVisibility(elementLocator, timeout);
|
|
}
|
|
}
|
|
|
|
public async waitDisappearance(elementLocator: By,
|
|
attempts: number = TestConstants.TS_SELENIUM_DEFAULT_ATTEMPTS,
|
|
polling: number = TestConstants.TS_SELENIUM_DEFAULT_POLLING) {
|
|
|
|
Logger.trace(`DriverHelper.waitDisappearance ${elementLocator}`);
|
|
|
|
const isDisappeared = await this.waitDisappearanceBoolean(elementLocator, attempts, polling);
|
|
|
|
if (!isDisappeared) {
|
|
throw new error.TimeoutError(`Waiting attempts exceeded, element '${elementLocator}' is still visible`);
|
|
}
|
|
}
|
|
|
|
public async waitDisappearanceWithTimeout(elementLocator: By, timeout: number = TestConstants.TS_SELENIUM_DEFAULT_TIMEOUT) {
|
|
Logger.trace(`DriverHelper.waitDisappearanceWithTimeout ${elementLocator}`);
|
|
|
|
await this.getDriver().wait(async () => {
|
|
const isVisible: boolean = await this.isVisible(elementLocator);
|
|
|
|
if (!isVisible) {
|
|
return true;
|
|
}
|
|
}, timeout);
|
|
}
|
|
|
|
public async waitAllDisappearance(locators: Array<By>,
|
|
attempts: number = TestConstants.TS_SELENIUM_DEFAULT_ATTEMPTS,
|
|
polling: number = TestConstants.TS_SELENIUM_DEFAULT_POLLING) {
|
|
|
|
Logger.trace(`DriverHelper.waitAllDisappearance ${locators}`);
|
|
|
|
for (const elementLocator of locators) {
|
|
await this.waitDisappearance(elementLocator, attempts, polling);
|
|
}
|
|
}
|
|
|
|
public async waitAndClick(elementLocator: By, timeout: number = TestConstants.TS_SELENIUM_DEFAULT_TIMEOUT) {
|
|
const attempts: number = TestConstants.TS_SELENIUM_DEFAULT_ATTEMPTS;
|
|
const polling: number = TestConstants.TS_SELENIUM_DEFAULT_POLLING;
|
|
|
|
Logger.trace(`DriverHelper.waitAndClick ${elementLocator}`);
|
|
|
|
for (let i = 0; i < attempts; i++) {
|
|
const element: WebElement = await this.waitVisibility(elementLocator, timeout);
|
|
|
|
try {
|
|
await element.click();
|
|
return;
|
|
} catch (err) {
|
|
if (err instanceof error.StaleElementReferenceError) {
|
|
Logger.debug(`DriverHelper.waitAndClik - ${elementLocator} - StaleElementReferenceError - ${err}`);
|
|
await this.wait(polling);
|
|
continue;
|
|
}
|
|
|
|
if (err instanceof error.WebDriverError) {
|
|
Logger.debug(`DriverHelper.waitAndClik - ${elementLocator} - WebDriverError - ${err}`);
|
|
await this.wait(polling);
|
|
continue;
|
|
}
|
|
|
|
throw err;
|
|
}
|
|
}
|
|
|
|
throw new error.TimeoutError(`Exceeded maximum clicking attempts, the '${elementLocator}' element is not clickable`);
|
|
|
|
}
|
|
|
|
public async waitAndGetElementAttribute(elementLocator: By,
|
|
attribute: string,
|
|
visibilityTimeout: number = TestConstants.TS_SELENIUM_DEFAULT_TIMEOUT): Promise<string> {
|
|
|
|
const attempts: number = TestConstants.TS_SELENIUM_DEFAULT_ATTEMPTS;
|
|
const polling: number = TestConstants.TS_SELENIUM_DEFAULT_POLLING;
|
|
|
|
Logger.trace(`DriverHelper.waitAndGetElementAttribute ${elementLocator} attribute: '${attribute}'`);
|
|
|
|
for (let i = 0; i < attempts; i++) {
|
|
const element: WebElement = await this.waitVisibility(elementLocator, visibilityTimeout);
|
|
|
|
try {
|
|
const attributeValue = await element.getAttribute(attribute);
|
|
return attributeValue;
|
|
} catch (err) {
|
|
if (err instanceof error.StaleElementReferenceError) {
|
|
await this.wait(polling);
|
|
continue;
|
|
}
|
|
|
|
throw err;
|
|
}
|
|
}
|
|
|
|
throw new error.TimeoutError(`Exceeded maximum gettin of the '${attribute}' attribute attempts, from the '${elementLocator}' element`);
|
|
}
|
|
|
|
public async waitAndGetCssValue(elementLocator: By,
|
|
cssAttribute: string,
|
|
visibilityTimeout: number = TestConstants.TS_SELENIUM_DEFAULT_TIMEOUT): Promise<string> {
|
|
|
|
const attempts: number = TestConstants.TS_SELENIUM_DEFAULT_ATTEMPTS;
|
|
const polling: number = TestConstants.TS_SELENIUM_DEFAULT_POLLING;
|
|
|
|
Logger.trace(`DriverHelper.waitAndGetCssValue ${elementLocator} cssAttribute: ${cssAttribute}`);
|
|
|
|
for (let i = 0; i < attempts; i++) {
|
|
const element: WebElement = await this.waitVisibility(elementLocator, visibilityTimeout);
|
|
|
|
try {
|
|
const cssAttributeValue = await element.getCssValue(cssAttribute);
|
|
return cssAttributeValue;
|
|
} catch (err) {
|
|
if (err instanceof error.StaleElementReferenceError) {
|
|
await this.wait(polling);
|
|
continue;
|
|
}
|
|
|
|
throw err;
|
|
}
|
|
}
|
|
|
|
throw new error.TimeoutError(`Exceeded maximum gettin of the '${cssAttribute}' css attribute attempts, from the '${elementLocator}' element`);
|
|
}
|
|
|
|
public async waitAttributeValue(elementLocator: By,
|
|
attribute: string,
|
|
expectedValue: string,
|
|
timeout: number = TestConstants.TS_SELENIUM_DEFAULT_TIMEOUT) {
|
|
|
|
Logger.trace(`DriverHelper.waitAttributeValue ${elementLocator}`);
|
|
|
|
await this.driver.wait(async () => {
|
|
const attributeValue: string = await this.waitAndGetElementAttribute(elementLocator, attribute, timeout);
|
|
|
|
return expectedValue === attributeValue;
|
|
},
|
|
timeout,
|
|
`The '${attribute}' attribute value doesn't match with expected value '${expectedValue}'`);
|
|
}
|
|
|
|
public async type(elementLocator: By, text: string, timeout: number = TestConstants.TS_SELENIUM_DEFAULT_TIMEOUT) {
|
|
const attempts: number = TestConstants.TS_SELENIUM_DEFAULT_ATTEMPTS;
|
|
const polling: number = TestConstants.TS_SELENIUM_DEFAULT_POLLING;
|
|
|
|
Logger.trace(`DriverHelper.type ${elementLocator} text: ${text}`);
|
|
|
|
for (let i = 0; i < attempts; i++) {
|
|
const element: WebElement = await this.waitVisibility(elementLocator, timeout);
|
|
|
|
try {
|
|
await element.sendKeys(text);
|
|
return;
|
|
} catch (err) {
|
|
if (err instanceof error.StaleElementReferenceError) {
|
|
await this.wait(polling);
|
|
continue;
|
|
}
|
|
|
|
throw err;
|
|
}
|
|
}
|
|
|
|
throw new error.TimeoutError(`Exceeded maximum typing attempts, to the '${elementLocator}' element`);
|
|
}
|
|
|
|
public async typeToInvisible(elementLocator: By, text: string, timeout: number = TestConstants.TS_SELENIUM_DEFAULT_TIMEOUT) {
|
|
const attempts: number = TestConstants.TS_SELENIUM_DEFAULT_ATTEMPTS;
|
|
const polling: number = TestConstants.TS_SELENIUM_DEFAULT_POLLING;
|
|
|
|
Logger.trace(`DriverHelper.typeToInvisible ${elementLocator} text: ${text}`);
|
|
|
|
for (let i = 0; i < attempts; i++) {
|
|
const element: WebElement = await this.waitPresence(elementLocator, timeout);
|
|
|
|
try {
|
|
await element.sendKeys(text);
|
|
return;
|
|
} catch (err) {
|
|
if (err instanceof error.StaleElementReferenceError) {
|
|
await this.wait(polling);
|
|
continue;
|
|
}
|
|
|
|
throw err;
|
|
}
|
|
}
|
|
|
|
throw new error.TimeoutError(`Exceeded maximum typing attempts, to the '${elementLocator}' element`);
|
|
}
|
|
|
|
public async clear(elementLocator: By, timeout: number = TestConstants.TS_SELENIUM_DEFAULT_TIMEOUT) {
|
|
const attempts: number = TestConstants.TS_SELENIUM_DEFAULT_ATTEMPTS;
|
|
const polling: number = TestConstants.TS_SELENIUM_DEFAULT_POLLING;
|
|
|
|
Logger.trace(`DriverHelper.clear ${elementLocator}`);
|
|
|
|
for (let i = 0; i < attempts; i++) {
|
|
const element: WebElement = await this.waitVisibility(elementLocator, timeout);
|
|
|
|
try {
|
|
await element.clear();
|
|
return;
|
|
} catch (err) {
|
|
if (err instanceof error.StaleElementReferenceError) {
|
|
await this.wait(polling);
|
|
continue;
|
|
}
|
|
|
|
throw err;
|
|
}
|
|
}
|
|
|
|
throw new error.TimeoutError(`Exceeded maximum clearing attempts, to the '${elementLocator}' element`);
|
|
}
|
|
|
|
public async clearInvisible(elementLocator: By, timeout: number = TestConstants.TS_SELENIUM_DEFAULT_TIMEOUT) {
|
|
const attempts: number = TestConstants.TS_SELENIUM_DEFAULT_ATTEMPTS;
|
|
const polling: number = TestConstants.TS_SELENIUM_DEFAULT_POLLING;
|
|
|
|
Logger.trace(`DriverHelper.clearInvisible ${elementLocator}`);
|
|
|
|
for (let i = 0; i < attempts; i++) {
|
|
const element: WebElement = await this.waitPresence(elementLocator, timeout);
|
|
|
|
try {
|
|
await element.clear();
|
|
return;
|
|
} catch (err) {
|
|
if (err instanceof error.StaleElementReferenceError) {
|
|
await this.wait(polling);
|
|
continue;
|
|
}
|
|
|
|
throw err;
|
|
}
|
|
}
|
|
|
|
throw new error.TimeoutError(`Exceeded maximum clearing attempts, to the '${elementLocator}' element`);
|
|
}
|
|
|
|
public async enterValue(elementLocator: By, text: string, timeout: number = TestConstants.TS_SELENIUM_DEFAULT_TIMEOUT) {
|
|
Logger.trace(`DriverHelper.enterValue ${elementLocator} text: ${text}`);
|
|
|
|
await this.waitVisibility(elementLocator, timeout);
|
|
await this.clear(elementLocator, timeout);
|
|
await this.waitAttributeValue(elementLocator, 'value', '', timeout);
|
|
await this.type(elementLocator, text, timeout);
|
|
await this.waitAttributeValue(elementLocator, 'value', text, timeout);
|
|
}
|
|
|
|
public async waitAndSwitchToFrame(iframeLocator: By, timeout: number = TestConstants.TS_SELENIUM_DEFAULT_TIMEOUT) {
|
|
Logger.trace(`DriverHelper.waitAndSwitchToFrame ${iframeLocator}`);
|
|
|
|
await this.driver.wait(until.ableToSwitchToFrame(iframeLocator), timeout);
|
|
}
|
|
|
|
public async waitAndGetText(elementLocator: By, timeout: number = TestConstants.TS_SELENIUM_DEFAULT_TIMEOUT): Promise<string> {
|
|
const attempts: number = TestConstants.TS_SELENIUM_DEFAULT_ATTEMPTS;
|
|
const polling: number = TestConstants.TS_SELENIUM_DEFAULT_POLLING;
|
|
|
|
Logger.trace(`DriverHelper.waitAndGetText ${elementLocator}`);
|
|
|
|
for (let i = 0; i < attempts; i++) {
|
|
const element: WebElement = await this.waitVisibility(elementLocator, timeout);
|
|
|
|
try {
|
|
const innerText: string = await element.getText();
|
|
return innerText;
|
|
} catch (err) {
|
|
if (err instanceof error.StaleElementReferenceError) {
|
|
await this.wait(polling);
|
|
continue;
|
|
}
|
|
|
|
throw err;
|
|
}
|
|
}
|
|
|
|
throw new error.TimeoutError(`Exceeded maximum text obtaining attempts, from the '${elementLocator}' element`);
|
|
}
|
|
|
|
public async waitAndGetValue(elementLocator: By, timeout: number = TestConstants.TS_SELENIUM_DEFAULT_TIMEOUT): Promise<string> {
|
|
Logger.trace(`DriverHelper.waitAndGetValue ${elementLocator}`);
|
|
|
|
const elementValue: string = await this.waitAndGetElementAttribute(elementLocator, 'value', timeout);
|
|
return elementValue;
|
|
}
|
|
|
|
public async waitUntilTrue(callback: any, timeout: number = TestConstants.TS_SELENIUM_DEFAULT_TIMEOUT) {
|
|
Logger.trace('DriverHelper.waitUntilTrue');
|
|
|
|
await this.driver.wait(callback, timeout);
|
|
}
|
|
|
|
public async reloadPage() {
|
|
Logger.debug('DriverHelper.reloadPage');
|
|
|
|
await this.driver.navigate().refresh();
|
|
}
|
|
|
|
public async navigateAndWaitToUrl(url: string) {
|
|
Logger.trace(`DriverHelper.navigateAndWaitToUrl ${url}`);
|
|
|
|
await this.navigateToUrl(url);
|
|
await this.waitURL(url);
|
|
}
|
|
|
|
public async navigateToUrl(url: string) {
|
|
Logger.debug(`DriverHelper.navigateToUrl ${url}`);
|
|
|
|
await this.driver.navigate().to(url);
|
|
}
|
|
|
|
public async waitURL(expectedUrl: string, timeout: number = TestConstants.TS_SELENIUM_DEFAULT_TIMEOUT) {
|
|
Logger.trace(`DriverHelper.waitURL ${expectedUrl}`);
|
|
|
|
await this.getDriver().wait(async () => {
|
|
const currentUrl: string = await this.getDriver().getCurrentUrl();
|
|
const urlEquals: boolean = currentUrl === expectedUrl;
|
|
|
|
if (urlEquals) {
|
|
return true;
|
|
}
|
|
});
|
|
}
|
|
|
|
public async scrollTo(elementLocator: By, timeout: number = TestConstants.TS_SELENIUM_DEFAULT_TIMEOUT) {
|
|
const attempts: number = TestConstants.TS_SELENIUM_DEFAULT_ATTEMPTS;
|
|
const polling: number = TestConstants.TS_SELENIUM_DEFAULT_POLLING;
|
|
|
|
Logger.trace(`DriverHelper.scrollTo ${elementLocator}`);
|
|
|
|
for (let i = 0; i < attempts; i++) {
|
|
const element: WebElement = await this.waitPresence(elementLocator, timeout);
|
|
|
|
try {
|
|
await this.getAction().mouseMove(element).perform();
|
|
return;
|
|
} catch (err) {
|
|
if (err instanceof error.StaleElementReferenceError) {
|
|
await this.wait(polling);
|
|
continue;
|
|
}
|
|
|
|
throw err;
|
|
}
|
|
}
|
|
|
|
throw new error.TimeoutError(`Exceeded maximum mouse move attempts, for the '${elementLocator}' element`);
|
|
}
|
|
|
|
getDriver(): ThenableWebDriver {
|
|
Logger.trace('DriverHelper.getDriver');
|
|
|
|
return this.driver;
|
|
}
|
|
|
|
async waitOpenningSecondWindow(timeout: number = TestConstants.TS_SELENIUM_DEFAULT_TIMEOUT) {
|
|
Logger.trace('DriverHelper.waitOpenningSecondWindow');
|
|
|
|
await this.driver.wait(async () => {
|
|
const handles: string[] = await this.driver.getAllWindowHandles();
|
|
if (handles.length > 1) {
|
|
return true;
|
|
}
|
|
}, timeout);
|
|
}
|
|
|
|
async switchToSecondWindow(mainWindowHandle: string) {
|
|
Logger.debug('DriverHelper.switchToSecondWindow');
|
|
|
|
await this.waitOpenningSecondWindow();
|
|
const handles: string[] = await this.driver.getAllWindowHandles();
|
|
handles.splice(handles.indexOf(mainWindowHandle), 1);
|
|
await this.driver.switchTo().window(handles[0]);
|
|
}
|
|
|
|
}
|