[ACS-6572] break dependency on adf-testing (#3594)

* remove Logger dependency

* remove BrowserVisibility dependency

* remove BrowserActions dependency

* remove ViewerPage dependency

* remove ApiUtil dependency

* remove StringUtil dependency

* remove adf-testing dependency

* bug fixes
This commit is contained in:
Denys Vuika
2024-01-11 09:02:58 -05:00
committed by GitHub
parent 09aba59b06
commit dbe724552f
61 changed files with 871 additions and 538 deletions

View File

@@ -0,0 +1,46 @@
/*!
* Copyright © 2005-2023 Hyland Software, Inc. and its affiliates. All rights reserved.
*
* Alfresco Example Content Application
*
* This file is part of the Alfresco Example Content Application.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
export type ApiResultPredicate<T> = (result: T) => boolean;
export type ApiCall<T> = () => Promise<T>;
export async function waitForApi<T>(apiCall: ApiCall<T>, predicate: ApiResultPredicate<T>, retry: number = 30, delay: number = 1000) {
const apiCallWithPredicateChecking = async () => {
const apiCallResult = await apiCall();
if (predicate(apiCallResult)) {
return Promise.resolve(apiCallResult);
} else {
return Promise.reject(apiCallResult);
}
};
return retryCall(apiCallWithPredicateChecking, retry, delay);
}
function retryCall(fn: () => Promise<any>, retry: number = 30, delay: number = 1000): Promise<any> {
const pause = (duration) => new Promise((res) => setTimeout(res, duration));
const run = (retries) => fn().catch((err) => (retries > 1 ? pause(delay).then(() => run(retries - 1)) : Promise.reject(err)));
return run(retry);
}

View File

@@ -0,0 +1,84 @@
/*!
* Copyright © 2005-2023 Hyland Software, Inc. and its affiliates. All rights reserved.
*
* Alfresco Example Content Application
*
* This file is part of the Alfresco Example Content Application.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
import { browser, ElementFinder, protractor } from 'protractor';
import { waitUntilElementHasValue, waitUntilElementIsClickable, waitUntilElementIsVisible } from './browser-visibility';
export async function click(elementToClick: ElementFinder): Promise<void> {
try {
await waitUntilElementIsVisible(elementToClick);
await waitUntilElementIsClickable(elementToClick);
await elementToClick.click();
} catch (clickErr) {
await clickScript(elementToClick);
}
}
export async function rightClick(elementFinder: ElementFinder): Promise<void> {
await browser.actions().mouseMove(elementFinder).mouseDown().mouseMove(elementFinder).perform();
await browser.actions().click(elementFinder, protractor.Button.RIGHT).perform();
}
async function clickScript(elementToClick: ElementFinder): Promise<void> {
await browser.executeScript(`arguments[0].scrollIntoView();`, elementToClick);
await browser.executeScript(`arguments[0].click();`, elementToClick);
}
export async function getInputValue(elementFinder: ElementFinder): Promise<string> {
const present = await waitUntilElementIsVisible(elementFinder);
if (present) {
return browser.executeScript(`return arguments[0].value`, elementFinder);
} else {
console.error(`Get Input value ${elementFinder.locator().toString()} not present`);
return '';
}
}
export async function getUrl(url: string, timeout: number = 10000): Promise<any> {
return browser.get(url, timeout);
}
export async function clearSendKeys(elementFinder: ElementFinder, text: string = '', sleepTime: number = 0): Promise<void> {
await click(elementFinder);
await elementFinder.sendKeys('');
await elementFinder.clear();
if (sleepTime === 0) {
await elementFinder.sendKeys(text);
} else {
// eslint-disable-next-line @typescript-eslint/prefer-for-of
for (let i = 0; i < text.length; i++) {
await elementFinder.sendKeys(text[i]);
await browser.sleep(sleepTime);
}
}
try {
if (text !== protractor.Key.SPACE && text !== protractor.Key.ENTER) {
await waitUntilElementHasValue(elementFinder, text, 1000);
}
} catch (e) {
console.info(`Set value different from the input`);
}
}

View File

@@ -0,0 +1,80 @@
/*!
* Copyright © 2005-2023 Hyland Software, Inc. and its affiliates. All rights reserved.
*
* Alfresco Example Content Application
*
* This file is part of the Alfresco Example Content Application.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
import { browser, ElementFinder, protractor } from 'protractor';
import { falseIfMissing } from 'protractor/built/util';
export async function waitUntilElementIsVisible(
elementToCheck: ElementFinder,
waitTimeout: number = 10000,
message: string = 'Element is not visible'
): Promise<any> {
return browser.wait(protractor.ExpectedConditions.visibilityOf(elementToCheck), waitTimeout, message + elementToCheck.locator());
}
export async function waitUntilElementIsNotVisible(elementToCheck: ElementFinder, waitTimeout: number = 10000): Promise<any> {
return browser.wait(
protractor.ExpectedConditions.invisibilityOf(elementToCheck),
waitTimeout,
'Element is Visible and it should not' + elementToCheck.locator()
);
}
export async function waitUntilElementIsClickable(elementToCheck: ElementFinder, waitTimeout: number = 10000): Promise<any> {
return browser.wait(
protractor.ExpectedConditions.elementToBeClickable(elementToCheck),
waitTimeout,
'Element is not Clickable ' + elementToCheck.locator()
);
}
export async function waitUntilElementIsPresent(elementToCheck: ElementFinder, waitTimeout: number = 10000): Promise<any> {
return browser.wait(protractor.ExpectedConditions.presenceOf(elementToCheck), waitTimeout, 'Element is not present ' + elementToCheck.locator());
}
export async function waitUntilElementIsNotPresent(elementToCheck: ElementFinder, waitTimeout: number = 10000): Promise<any> {
return browser.wait(protractor.ExpectedConditions.stalenessOf(elementToCheck), waitTimeout, 'Element is present ' + elementToCheck.locator());
}
function textToBePresentInElementValue(elementFinder: ElementFinder, text: string) {
const hasText = async () =>
browser.executeScript(`return arguments[0].value`, elementFinder).then((actualText: string) => actualText.indexOf(text) > -1, falseIfMissing);
return protractor.ExpectedConditions.and(protractor.ExpectedConditions.presenceOf(elementFinder), hasText);
}
export async function waitUntilElementHasValue(elementToCheck: ElementFinder, elementValue, waitTimeout: number = 10000): Promise<any> {
return browser.wait(
textToBePresentInElementValue(elementToCheck, elementValue),
waitTimeout,
`Element doesn't have a value ${elementValue} ${elementToCheck.locator()}`
);
}
export async function waitUntilElementHasText(elementToCheck: ElementFinder, text, waitTimeout: number = 10000): Promise<any> {
return browser.wait(
protractor.ExpectedConditions.textToBePresentInElement(elementToCheck, text),
waitTimeout,
`Element doesn't have the text ${text} ${elementToCheck.locator()}`
);
}

View File

@@ -27,3 +27,8 @@ export * from './repo-client/repo-client';
export * from './admin-actions';
export * from './user-actions';
export * from './utils';
export * from './browser-visibility';
export * from './browser-actions';
export * from './api';
export * from './logger';
export * from './test-element';

View File

@@ -0,0 +1,88 @@
/*!
* Copyright © 2005-2023 Hyland Software, Inc. and its affiliates. All rights reserved.
*
* Alfresco Example Content Application
*
* This file is part of the Alfresco Example Content Application.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* from Hyland Software. If not, see <http://www.gnu.org/licenses/>.
*/
/* eslint-disable @typescript-eslint/naming-convention */
export const infoColor = '\x1b[36m%s\x1b[0m';
export const logColor = '\x1b[35m%s\x1b[0m';
export const warnColor = '\x1b[33m%s\x1b[0m';
export const errorColor = '\x1b[31m%s\x1b[0m';
export type LOG_LEVEL = 'TRACE' | 'DEBUG' | 'INFO' | 'WARN' | 'ERROR' | 'SILENT';
export class LogLevelsEnum extends Number {
static TRACE: number = 5;
static DEBUG: number = 4;
static INFO: number = 3;
static WARN: number = 2;
static ERROR: number = 1;
static SILENT: number = 0;
}
export const logLevels: { level: LogLevelsEnum; name: LOG_LEVEL }[] = [
{ level: LogLevelsEnum.TRACE, name: 'TRACE' },
{ level: LogLevelsEnum.DEBUG, name: 'DEBUG' },
{ level: LogLevelsEnum.INFO, name: 'INFO' },
{ level: LogLevelsEnum.WARN, name: 'WARN' },
{ level: LogLevelsEnum.ERROR, name: 'ERROR' },
{ level: LogLevelsEnum.SILENT, name: 'SILENT' }
];
export interface LoggerLike {
info(...messages: string[]): void;
log(...messages: string[]): void;
warn(...messages: string[]): void;
error(...messages: string[]): void;
}
/* eslint-disable no-console */
export class GenericLogger implements LoggerLike {
private readonly level: LogLevelsEnum;
constructor(logLevel: string) {
this.level = logLevels.find(({ name }) => name === logLevel)?.level || LogLevelsEnum.ERROR;
}
info(...messages: string[]): void {
if (this.level >= LogLevelsEnum.INFO) {
console.log(infoColor, messages.join(''));
}
}
log(...messages: string[]): void {
if (this.level >= LogLevelsEnum.TRACE) {
console.log(logColor, messages.join(''));
}
}
warn(...messages: string[]): void {
if (this.level >= LogLevelsEnum.WARN) {
console.log(warnColor, messages.join(''));
}
}
error(...messages: string[]): void {
console.log(errorColor, messages.join(''));
}
}

View File

@@ -23,8 +23,7 @@
*/
import { RepoApi } from '../repo-api';
import { Logger } from '@alfresco/adf-testing';
import { Utils } from '../../../../utilities/utils';
import { Utils } from '../../../utils';
import { FavoritesApi as AdfFavoritesApi, SitesApi as AdfSiteApi, FavoriteEntry } from '@alfresco/js-api';
export class FavoritesApi extends RepoApi {
@@ -103,10 +102,9 @@ export class FavoritesApi extends RepoApi {
}
async isFavoriteWithRetry(nodeId: string, data: { expect: boolean }) {
let isFavorite = false;
try {
const favorite = async () => {
isFavorite = await this.isFavorite(nodeId);
let isFavorite = await this.isFavorite(nodeId);
if (isFavorite !== data.expect) {
return Promise.reject(isFavorite);
} else {
@@ -114,8 +112,9 @@ export class FavoritesApi extends RepoApi {
}
};
return await Utils.retryCall(favorite);
} catch (error) {}
return isFavorite;
} catch {
return false;
}
}
private async removeFavoriteById(nodeId: string) {
@@ -150,8 +149,8 @@ export class FavoritesApi extends RepoApi {
};
return await Utils.retryCall(favoriteFiles);
} catch (error) {
Logger.error(`FavoritesApi waitForApi : catch : `);
Logger.error(`\tExpected: ${data.expect} items, but found ${error}`);
console.error(`FavoritesApi waitForApi : catch : `);
console.error(`\tExpected: ${data.expect} items, but found ${error}`);
}
}
}

View File

@@ -23,8 +23,7 @@
*/
import { RepoApi } from '../repo-api';
import { Logger } from '@alfresco/adf-testing';
import { Utils } from '../../../../utilities/utils';
import { Utils } from '../../../utils';
import { QueriesApi as AdfQueriesApi } from '@alfresco/js-api';
export class QueriesApi extends RepoApi {
@@ -64,8 +63,8 @@ export class QueriesApi extends RepoApi {
return await Utils.retryCall(sites);
} catch (error) {
Logger.error(`QueriesApi waitForSites : catch : `);
Logger.error(`\tExpected: ${data.expect} items, but found ${error}`);
console.error(`QueriesApi waitForSites : catch : `);
console.error(`\tExpected: ${data.expect} items, but found ${error}`);
}
}
}

View File

@@ -24,7 +24,6 @@
import { browser } from 'protractor';
import { AlfrescoApi } from '@alfresco/js-api';
import { Logger } from '@alfresco/adf-testing';
export abstract class RepoApi {
alfrescoJsApi = new AlfrescoApi();
@@ -38,18 +37,18 @@ export abstract class RepoApi {
}
protected handleError(message: string, response: any) {
Logger.error(`\n--- ${message} error :`);
Logger.error('\t>>> username: ', this.username);
Logger.error('\t>>> JSON: ', JSON.stringify(browser.params.config));
console.error(`\n--- ${message} error :`);
console.error('\t>>> username: ', this.username);
console.error('\t>>> JSON: ', JSON.stringify(browser.params.config));
if (response.status && response.response) {
try {
Logger.error('\t>>> Status: ', response.status);
Logger.error('\t>>> Text: ', response.response.text);
Logger.error('\t>>> Method: ', response.response.error.method);
Logger.error('\t>>> Path: ', response.response.error.path);
console.error('\t>>> Status: ', response.status);
console.error('\t>>> Text: ', response.response.text);
console.error('\t>>> Method: ', response.response.error.method);
console.error('\t>>> Path: ', response.response.error.path);
} catch {
Logger.error('\t>>> ', response);
console.error('\t>>> ', response);
}
} else Logger.error('\t>>> ', response);
} else console.error('\t>>> ', response);
}
}

View File

@@ -23,8 +23,8 @@
*/
import { RepoApi } from '../repo-api';
import { ApiUtil, Logger } from '@alfresco/adf-testing';
import { Utils } from '../../../../utilities/utils';
import { Utils } from '../../../utils';
import { waitForApi } from '../../../api';
import { SearchApi as AdfSearchApi } from '@alfresco/js-api';
export class SearchApi extends RepoApi {
@@ -96,8 +96,8 @@ export class SearchApi extends RepoApi {
return await Utils.retryCall(recentFiles);
} catch (error) {
Logger.error(`SearchApi waitForApi : catch : `);
Logger.error(`\tExpected: ${data.expect} items, but found ${error}`);
console.error(`SearchApi waitForApi : catch : `);
console.error(`\tExpected: ${data.expect} items, but found ${error}`);
}
}
@@ -113,10 +113,10 @@ export class SearchApi extends RepoApi {
};
try {
await ApiUtil.waitForApi(apiCall, predicate, 30, 2500);
await waitForApi(apiCall, predicate, 30, 2500);
} catch (error) {
Logger.error(`SearchApi waitForNodes : catch : `);
Logger.error(`\tExpected: ${data.expect} items, but found ${error}`);
console.error(`SearchApi waitForNodes : catch : `);
console.error(`\tExpected: ${data.expect} items, but found ${error}`);
}
}
}

View File

@@ -23,8 +23,7 @@
*/
import { RepoApi } from '../repo-api';
import { Logger } from '@alfresco/adf-testing';
import { Utils } from '../../../../utilities/utils';
import { Utils } from '../../../utils';
import { SharedlinksApi as AdfSharedlinksApi, SharedLinkEntry, SharedLinkPaging } from '@alfresco/js-api';
export class SharedLinksApi extends RepoApi {
@@ -63,26 +62,6 @@ export class SharedLinksApi extends RepoApi {
return sharedLinks;
}
private async getSharedIdOfNode(fileId: string): Promise<string> {
try {
const sharedLinksEntries = (await this.getSharedLinks())?.list.entries;
const found = sharedLinksEntries.find((sharedLink) => sharedLink.entry.nodeId === fileId);
return (found || { entry: { id: null } }).entry.id;
} catch (error) {
this.handleError(`SharedLinksApi getSharedIdOfNode : catch : `, error);
return null;
}
}
async unshareFileById(fileId: string): Promise<any> {
try {
const sharedId = await this.getSharedIdOfNode(fileId);
return await this.sharedlinksApi.deleteSharedLink(sharedId);
} catch (error) {
this.handleError(`SharedLinksApi unshareFileById : catch : `, error);
}
}
private async getSharedLinks(maxItems: number = 250): Promise<SharedLinkPaging | null> {
try {
await this.apiAuth();
@@ -108,31 +87,8 @@ export class SharedLinksApi extends RepoApi {
};
return Utils.retryCall(sharedFile).catch((error) => {
Logger.error(`SharedLinksApi waitForFilesToBeShared : catch : ${error}`);
Logger.error(`\tWait timeout reached waiting for files to be shared`);
console.error(`SharedLinksApi waitForFilesToBeShared : catch : ${error}`);
console.error(`\tWait timeout reached waiting for files to be shared`);
});
}
async waitForFilesToNotBeShared(filesIds: string[]): Promise<any> {
try {
const sharedFile = async () => {
const sharedFiles = (await this.getSharedLinks()).list.entries.map((link) => link.entry.nodeId);
const foundItems = filesIds.some((id) => {
return sharedFiles.includes(id);
});
if (foundItems) {
return Promise.reject(foundItems);
} else {
return Promise.resolve(foundItems);
}
};
return await Utils.retryCall(sharedFile);
} catch (error) {
Logger.error(`SharedLinksApi waitForFilesToNotBeShared : catch : ${error}`);
Logger.error(`\tWait timeout reached waiting for files to no longer be shared`);
}
}
}

View File

@@ -23,18 +23,9 @@
*/
import { RepoApi } from '../repo-api';
import { Logger } from '@alfresco/adf-testing';
import {
SiteBodyCreate,
SiteMembershipBodyUpdate,
SiteMembershipBodyCreate,
SiteEntry,
SiteMembershipRequestEntry,
SitesApi as AdfSiteApi,
SiteMemberEntry
} from '@alfresco/js-api';
import { SITE_VISIBILITY, SITE_ROLES } from '../../../../configs';
import { Utils } from '../../../../utilities/utils';
import { SiteBodyCreate, SiteMembershipBodyUpdate, SiteMembershipBodyCreate, SiteEntry, SitesApi as AdfSiteApi } from '@alfresco/js-api';
import { SITE_VISIBILITY } from '../../../../configs';
import { Utils } from '../../../utils';
export class SitesApi extends RepoApi {
sitesApi = new AdfSiteApi(this.alfrescoJsApi);
@@ -80,21 +71,6 @@ export class SitesApi extends RepoApi {
}
}
async createSites(siteNames: string[], visibility?: string): Promise<SiteEntry[]> {
const sites: SiteEntry[] = [];
try {
if (siteNames && siteNames.length > 0) {
for (const siteName of siteNames) {
const site = await this.createSite(siteName, visibility);
sites.push(site);
}
}
} catch (error) {
this.handleError(`SitesApi createSites : catch : `, error);
}
return sites;
}
async deleteSite(siteId: string, permanent: boolean = true) {
try {
await this.apiAuth();
@@ -151,52 +127,6 @@ export class SitesApi extends RepoApi {
}
}
async addSiteConsumer(siteId: string, userId: string): Promise<SiteMemberEntry> {
return this.addSiteMember(siteId, userId, SITE_ROLES.SITE_CONSUMER.ROLE);
}
async addSiteContributor(siteId: string, userId: string): Promise<SiteMemberEntry> {
return this.addSiteMember(siteId, userId, SITE_ROLES.SITE_CONTRIBUTOR.ROLE);
}
async addSiteCollaborator(siteId: string, userId: string): Promise<SiteMemberEntry> {
return this.addSiteMember(siteId, userId, SITE_ROLES.SITE_COLLABORATOR.ROLE);
}
async deleteSiteMember(siteId: string, userId: string) {
try {
await this.apiAuth();
return await this.sitesApi.deleteSiteMembership(siteId, userId);
} catch (error) {
this.handleError(`SitesApi deleteSiteMember : catch : `, error);
}
}
async requestToJoin(siteId: string): Promise<SiteMembershipRequestEntry | null> {
const body = {
id: siteId
};
try {
await this.apiAuth();
return await this.sitesApi.createSiteMembershipRequestForPerson('-me-', body);
} catch (error) {
this.handleError(`SitesApi requestToJoin : catch : `, error);
return null;
}
}
async hasMembershipRequest(siteId: string) {
try {
await this.apiAuth();
const requests = (await this.sitesApi.listSiteMembershipRequestsForPerson('-me-')).list.entries.map((e) => e.entry.id);
return requests.includes(siteId);
} catch (error) {
this.handleError(`SitesApi hasMembershipRequest : catch : `, error);
return null;
}
}
async waitForSitesToBeCreated(sitesIds: string[]) {
try {
const site = async () => {
@@ -213,8 +143,8 @@ export class SitesApi extends RepoApi {
return await Utils.retryCall(site);
} catch (error) {
Logger.error(`SitesApi waitForSitesToBeCreated : catch : ${error}`);
Logger.error(`\tWait timeout reached waiting for sites to be created`);
console.error(`SitesApi waitForSitesToBeCreated : catch : ${error}`);
console.error(`\tWait timeout reached waiting for sites to be created`);
}
}
}

View File

@@ -0,0 +1,255 @@
/*!
* Copyright © 2005-2023 Hyland Software, Inc. and its affiliates. All rights reserved.
*
* Alfresco Example Content Application
*
* This file is part of the Alfresco Example Content Application.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
import { by, element, ElementFinder, protractor, $, browser } from 'protractor';
import { clearSendKeys, click, getInputValue } from './browser-actions';
import {
waitUntilElementHasValue,
waitUntilElementIsNotPresent,
waitUntilElementIsNotVisible,
waitUntilElementIsPresent,
waitUntilElementIsVisible
} from './browser-visibility';
async function getAttribute(elementFinder: ElementFinder, attribute: string): Promise<string> {
await waitUntilElementIsPresent(elementFinder);
const attributeValue: string = await browser.executeScript(`return arguments[0].getAttribute(arguments[1])`, elementFinder, attribute);
return attributeValue || '';
}
async function getText(elementFinder: ElementFinder): Promise<string> {
const present = await waitUntilElementIsVisible(elementFinder);
if (present) {
let text = await elementFinder.getText();
if (text === '') {
// DO NOT REMOVE BUG sometime wrongly return empty text for cdk elements
console.info(`Use backup get text script`);
text = await this.getTextScript(elementFinder);
return text?.trim();
}
return text;
} else {
console.error(`Get Text ${elementFinder.locator().toString()} not present`);
return '';
}
}
/**
* Provides a wrapper for the most common operations with the page elements.
*/
export class TestElement {
constructor(public elementFinder: ElementFinder) {}
/**
* Create a new instance with the element located by the id
*
* @param id The id of the element
* @returns test element wrapper
*/
static byId(id: string): TestElement {
return new TestElement(element(by.id(id)));
}
/**
* Create a new instance with the element located by the CSS class name
*
* @param selector The CSS class name to lookup
* @returns test element wrapper
*/
static byCss(selector: string): TestElement {
return new TestElement($(selector));
}
/**
* Create a new instance with the element that contains specific text
*
* @param selector the CSS selector
* @param text the text within the target element
* @returns test element wrapper
*/
static byText(selector: string, text: string): TestElement {
return new TestElement(element(by.cssContainingText(selector, text)));
}
/**
* Create a new instance with the element with specific HTML tag name
*
* @param selector the HTML tag name
* @returns test element wrapper
*/
static byTag(selector: string): TestElement {
return new TestElement(element(by.tagName(selector)));
}
/**
* Performs a click on this element
*/
async click() {
return click(this.elementFinder);
}
/**
* Checks that an element is present on the DOM of a page and visible
*
* @param waitTimeout How long to wait for the condition to be true
*/
async isVisible(waitTimeout?: number): Promise<boolean> {
try {
await waitUntilElementIsVisible(this.elementFinder, waitTimeout);
return true;
} catch {
return false;
}
}
/**
* Waits until the element is present on the DOM of a page and visible
*
* @param waitTimeout How long to wait for the condition to be true
*/
async waitVisible(waitTimeout?: number): Promise<any> {
return waitUntilElementIsVisible(this.elementFinder, waitTimeout);
}
/**
* Waits until the element is either invisible or not present on the DOM
*
* @param waitTimeout How long to wait for the condition to be true
*/
async waitNotVisible(waitTimeout?: number): Promise<any> {
return waitUntilElementIsNotVisible(this.elementFinder, waitTimeout);
}
/**
* Checks that an element is present on the DOM of a page
*
* @param waitTimeout How long to wait for the condition to be true
*/
async isPresent(waitTimeout?: number): Promise<boolean> {
try {
await waitUntilElementIsPresent(this.elementFinder, waitTimeout);
return true;
} catch {
return false;
}
}
/**
* Waits until the element is present on the DOM of a page
*
* @param waitTimeout How long to wait for the condition to be true
*/
async waitPresent(waitTimeout?: number): Promise<any> {
return waitUntilElementIsPresent(this.elementFinder, waitTimeout);
}
/**
* Waits until the element is not attached to the DOM of a page
*
* @param waitTimeout How long to wait for the condition to be true
*/
async waitNotPresent(waitTimeout?: number): Promise<any> {
return waitUntilElementIsNotPresent(this.elementFinder, waitTimeout);
}
/**
* Waits until the given text is present in the elements value
*
* @param value the text to check
*/
async waitHasValue(value: string): Promise<any> {
return waitUntilElementHasValue(this.elementFinder, value);
}
/**
* Query whether the DOM element represented by this instance is enabled.
*/
async isEnabled(): Promise<boolean> {
return this.elementFinder.isEnabled();
}
/**
* Query whether the DOM element represented by this instance is disabled.
*/
async isDisabled(): Promise<boolean> {
return !(await this.elementFinder.isEnabled());
}
/**
* Test whether this element is currently displayed.
*/
async isDisplayed(): Promise<boolean> {
try {
await this.elementFinder.isDisplayed();
return true;
} catch {
return false;
}
}
/**
* Query for the value of the given attribute of the element.
*
* @param attributeName The name of the attribute to query.
*/
async getAttribute(attributeName: string): Promise<string> {
return getAttribute(this.elementFinder, attributeName);
}
/**
* Get the visible (i.e. not hidden by CSS) innerText of this element, including sub-elements, without any leading or trailing whitespace.
*/
async getText(): Promise<string> {
return getText(this.elementFinder);
}
/**
* Gets the `value` attribute for the given input element
*
* @returns input value
*/
getInputValue(): Promise<string> {
return getInputValue(this.elementFinder);
}
/**
* Enter the text
*
* @param text the text to enter
*/
async typeText(text: string): Promise<void> {
await clearSendKeys(this.elementFinder, text);
}
/**
* Clears the input using Ctrl+A and Backspace combination
*/
async clearInput() {
await this.elementFinder.clear();
await this.elementFinder.sendKeys(' ', protractor.Key.CONTROL, 'a', protractor.Key.NULL, protractor.Key.BACK_SPACE);
}
}

View File

@@ -22,7 +22,6 @@
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
import { Logger } from '@alfresco/adf-testing';
import { AlfrescoApi, Comment, CommentsApi, NodesApi, TrashcanApi, SitesApi, SharedlinksApi } from '@alfresco/js-api';
import { browser } from 'protractor';
@@ -168,18 +167,18 @@ export class UserActions {
}
protected handleError(message: string, response: any) {
Logger.error(`\n--- ${message} error :`);
Logger.error('\t>>> username: ', this.username);
Logger.error('\t>>> JSON: ', JSON.stringify(browser.params.config));
console.error(`\n--- ${message} error :`);
console.error('\t>>> username: ', this.username);
console.error('\t>>> JSON: ', JSON.stringify(browser.params.config));
if (response.status && response.response) {
try {
Logger.error('\t>>> Status: ', response.status);
Logger.error('\t>>> Text: ', response.response.text);
Logger.error('\t>>> Method: ', response.response.error.method);
Logger.error('\t>>> Path: ', response.response.error.path);
console.error('\t>>> Status: ', response.status);
console.error('\t>>> Text: ', response.response.text);
console.error('\t>>> Method: ', response.response.error.method);
console.error('\t>>> Path: ', response.response.error.path);
} catch {
Logger.error('\t>>> ', response);
console.error('\t>>> ', response);
}
} else Logger.error('\t>>> ', response);
} else console.error('\t>>> ', response);
}
}

View File

@@ -23,10 +23,10 @@
*/
import { browser, protractor, ElementFinder, ExpectedConditions as EC, by, until, WebElement } from 'protractor';
import { BrowserVisibility, Logger } from '@alfresco/adf-testing';
import { BROWSER_WAIT_TIMEOUT } from '../configs';
import * as path from 'path';
import * as fs from 'fs';
import { waitUntilElementIsPresent, waitUntilElementIsVisible } from './browser-visibility';
const StreamZip = require('node-stream-zip');
const crypto = require('crypto');
@@ -55,7 +55,7 @@ export async function waitForStaleness(element: ElementFinder, errorMessage?: st
export const isPresentAndEnabled = async (element: ElementFinder): Promise<boolean> => {
try {
await BrowserVisibility.waitUntilElementIsPresent(element);
await waitUntilElementIsPresent(element);
return element.isEnabled();
} catch (error) {
return false;
@@ -64,7 +64,7 @@ export const isPresentAndEnabled = async (element: ElementFinder): Promise<boole
export const isPresentAndDisplayed = async (element: ElementFinder): Promise<boolean> => {
try {
await BrowserVisibility.waitUntilElementIsVisible(element);
await waitUntilElementIsVisible(element);
return true;
} catch (error) {
return false;
@@ -131,7 +131,7 @@ export class Utils {
if (fileExists) {
fs.rename(oldFilePath, newFilePath, function (err: any) {
if (err) {
Logger.error(`==== rename err : failed to rename file from ${oldName} to ${newName} : `, err);
console.error(`==== rename err : failed to rename file from ${oldName} to ${newName} : `, err);
}
});
}
@@ -148,7 +148,7 @@ export class Utils {
});
await zip.on('error', (err: any) => {
Logger.error(`=== unzip err : failed to unzip ${filename} - ${unzippedName} :`, err);
console.error(`=== unzip err : failed to unzip ${filename} - ${unzippedName} :`, err);
});
await zip.on('ready', async () => {