mirror of
https://github.com/Alfresco/alfresco-content-app.git
synced 2025-09-17 14:21:14 +00:00
[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:
46
projects/aca-testing-shared/src/utilities/api.ts
Normal file
46
projects/aca-testing-shared/src/utilities/api.ts
Normal 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);
|
||||
}
|
84
projects/aca-testing-shared/src/utilities/browser-actions.ts
Normal file
84
projects/aca-testing-shared/src/utilities/browser-actions.ts
Normal 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`);
|
||||
}
|
||||
}
|
@@ -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()}`
|
||||
);
|
||||
}
|
@@ -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';
|
||||
|
88
projects/aca-testing-shared/src/utilities/logger.ts
Normal file
88
projects/aca-testing-shared/src/utilities/logger.ts
Normal 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(''));
|
||||
}
|
||||
}
|
@@ -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}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -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}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
|
@@ -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}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -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`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -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`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
255
projects/aca-testing-shared/src/utilities/test-element.ts
Normal file
255
projects/aca-testing-shared/src/utilities/test-element.ts
Normal 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 element’s 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);
|
||||
}
|
||||
}
|
@@ -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);
|
||||
}
|
||||
}
|
||||
|
@@ -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 () => {
|
||||
|
Reference in New Issue
Block a user