mirror of
https://github.com/Alfresco/alfresco-content-app.git
synced 2025-07-24 17:31:52 +00:00
[ACS-6510] playwright List View e2e test (#3566)
* [ACS-6435] playwright e2e for list views personal files * e2e test for trash page * e2e test for trash page * e2e test for file-libraries page * e2e test for file-libraries page fix * e2e test for file-libraries page fix * e2e test shared recent page * e2e test shared recent page fix * e2e test review comment fix * e2e test review fix flaky test fix * e2e test fail test fix * e2e test fail fix * test code fix * protractor list-view test enable * [ACS-6510] listview playwright e2e test * code fix * code fix * code fix * code fix * code fix * code fix * code fix for review * code fix for review
This commit is contained in:
@@ -41,7 +41,7 @@ export class FileActionsApi {
|
||||
return classObj;
|
||||
}
|
||||
|
||||
async uploadFile(fileLocation: string, fileName: string, parentFolderId: string): Promise<any> {
|
||||
async uploadFile(fileLocation: string, fileName: string, parentFolderId: string): Promise<NodeEntry> {
|
||||
const file = fs.createReadStream(fileLocation);
|
||||
return this.apiService.upload.uploadFile(file, '', parentFolderId, null, {
|
||||
name: fileName,
|
||||
@@ -50,7 +50,13 @@ export class FileActionsApi {
|
||||
});
|
||||
}
|
||||
|
||||
async uploadFileWithRename(fileLocation: string, newName: string, parentId: string = '-my-', title: string = '', description: string = '') {
|
||||
async uploadFileWithRename(
|
||||
fileLocation: string,
|
||||
newName: string,
|
||||
parentId: string = '-my-',
|
||||
title: string = '',
|
||||
description: string = ''
|
||||
): Promise<NodeEntry> {
|
||||
const file = fs.createReadStream(fileLocation);
|
||||
const nodeProps = {
|
||||
properties: {
|
||||
@@ -68,10 +74,11 @@ export class FileActionsApi {
|
||||
return await this.apiService.upload.uploadFile(file, '', parentId, nodeProps, opts);
|
||||
} catch (error) {
|
||||
Logger.error(`${this.constructor.name} ${this.uploadFileWithRename.name}`, error);
|
||||
return Promise.reject(error);
|
||||
}
|
||||
}
|
||||
|
||||
async lockNodes(nodeIds: string[], lockType: string = 'ALLOW_OWNER_CHANGES') {
|
||||
async lockNodes(nodeIds: string[], lockType: string = 'ALLOW_OWNER_CHANGES'): Promise<void> {
|
||||
try {
|
||||
for (const nodeId of nodeIds) {
|
||||
await this.apiService.nodes.lockNode(nodeId, { type: lockType });
|
||||
@@ -93,7 +100,7 @@ export class FileActionsApi {
|
||||
async getNodeProperty(nodeId: string, property: string): Promise<string> {
|
||||
try {
|
||||
const node = await this.getNodeById(nodeId);
|
||||
return (node.entry.properties?.[property]) || '';
|
||||
return node.entry.properties?.[property] || '';
|
||||
} catch (error) {
|
||||
Logger.error(`${this.constructor.name} ${this.getNodeProperty.name}`, error);
|
||||
return '';
|
||||
@@ -145,7 +152,7 @@ export class FileActionsApi {
|
||||
return this.apiService.search.search(data);
|
||||
} catch (error) {
|
||||
Logger.error(`SearchApi queryNodesNames : catch : `, error);
|
||||
return new ResultSetPaging;
|
||||
return new ResultSetPaging();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,4 +174,18 @@ export class FileActionsApi {
|
||||
Logger.error(`\tExpected: ${data.expect} items, but found ${error}`);
|
||||
}
|
||||
}
|
||||
|
||||
async updateNodeContent(nodeId: string, content: string, majorVersion: boolean = true, comment?: string, newName?: string): Promise<NodeEntry> {
|
||||
try {
|
||||
const opts: { [key: string]: string | boolean } = {
|
||||
majorVersion: majorVersion,
|
||||
comment: comment,
|
||||
name: newName
|
||||
};
|
||||
return await this.apiService.nodes.updateNodeContent(nodeId, content, opts);
|
||||
} catch (error) {
|
||||
console.error(`${this.constructor.name} ${this.updateNodeContent.name}`, error);
|
||||
return Promise.reject(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -81,6 +81,14 @@ export class NodesApi {
|
||||
}
|
||||
}
|
||||
|
||||
async deleteDeletedNode(name: string): Promise<void> {
|
||||
try {
|
||||
await this.apiService.trashCan.deleteDeletedNode(name);
|
||||
} catch (error) {
|
||||
console.error(`${this.constructor.name} ${this.deleteDeletedNode.name}: ${error}`);
|
||||
}
|
||||
}
|
||||
|
||||
private async createNode(
|
||||
nodeType: string,
|
||||
name: string,
|
||||
|
@@ -23,7 +23,16 @@
|
||||
*/
|
||||
|
||||
import { ApiClientFactory } from './api-client-factory';
|
||||
import { Site, SiteBodyCreate, SiteEntry, SiteMemberEntry, SiteMembershipBodyCreate, SiteMembershipBodyUpdate, SiteMembershipRequestBodyCreate, SiteMembershipRequestEntry } from '@alfresco/js-api';
|
||||
import {
|
||||
Site,
|
||||
SiteBodyCreate,
|
||||
SiteEntry,
|
||||
SiteMemberEntry,
|
||||
SiteMembershipBodyCreate,
|
||||
SiteMembershipBodyUpdate,
|
||||
SiteMembershipRequestBodyCreate,
|
||||
SiteMembershipRequestEntry
|
||||
} from '@alfresco/js-api';
|
||||
|
||||
export class SitesApi {
|
||||
private apiService: ApiClientFactory;
|
||||
@@ -88,7 +97,7 @@ export class SitesApi {
|
||||
return await this.apiService.sites.updateSiteMembership(siteId, userId, siteRole);
|
||||
} catch (error) {
|
||||
console.error(`SitesApi updateSiteMember : catch : `, error);
|
||||
return new SiteMemberEntry;
|
||||
return new SiteMemberEntry();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,7 +114,7 @@ export class SitesApi {
|
||||
return this.updateSiteMember(siteId, userId, role);
|
||||
} else {
|
||||
console.error(`SitesApi addSiteMember : catch : `, error);
|
||||
return new SiteMemberEntry;
|
||||
return new SiteMemberEntry();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -141,4 +150,12 @@ export class SitesApi {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
async deleteSiteMember(siteId: string, userId: string) {
|
||||
try {
|
||||
return await this.apiService.sites.deleteSiteMembership(siteId, userId);
|
||||
} catch (error) {
|
||||
console.error(`SitesApi deleteSiteMember : catch : `, error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -44,6 +44,11 @@ export class DataTableComponent extends BaseComponent {
|
||||
sortedColumnHeader = this.getChild(`.adf-datatable__header--sorted-asc .adf-datatable-cell-header-content .adf-datatable-cell-value,
|
||||
.adf-datatable__header--sorted-desc .adf-datatable-cell-header-content .adf-datatable-cell-value`);
|
||||
columnHeaders = this.getChild('.adf-datatable-row .adf-datatable-cell-header .adf-datatable-cell-value');
|
||||
emptyList = this.getChild('div.adf-no-content-container');
|
||||
emptyListTitle = this.getChild('.adf-empty-content__title');
|
||||
emptyListSubtitle = this.getChild('.adf-empty-content__subtitle');
|
||||
emptySearchText = this.getChild('.empty-search__text');
|
||||
emptyListTest = this.getChild('adf-custom-empty-content-template');
|
||||
|
||||
/** Locator for row (or rows) */
|
||||
getRowLocator = this.getChild(`adf-datatable-row`);
|
||||
@@ -123,17 +128,21 @@ export class DataTableComponent extends BaseComponent {
|
||||
|
||||
getSearchResultLinkByName = (name: string): Locator => this.getChild('.aca-search-results-row span[role="link"]', { hasText: name });
|
||||
|
||||
async sortBy(columnTitle: string, order: 'Ascending' | 'Descending'): Promise<void> {
|
||||
const columnHeaderLocator = this.getColumnHeaderByTitleLocator(columnTitle);
|
||||
await this.spinnerWaitForReload();
|
||||
await columnHeaderLocator.click();
|
||||
getColumnValuesByName = (name: string): Locator => this.getChild(`div[title="${name}"] span`);
|
||||
|
||||
const sortAttribute = await columnHeaderLocator.getAttribute('aria-sort');
|
||||
if (sortAttribute !== order) {
|
||||
await columnHeaderLocator.click();
|
||||
getColumnHeaderByName = (headerTitle: string): Locator =>
|
||||
this.getChild('.adf-datatable-row .adf-datatable-cell-header .adf-datatable-cell-value', { hasText: headerTitle });
|
||||
|
||||
async sortBy(label: string, order: 'asc' | 'desc'): Promise<void> {
|
||||
const sortColumn = await this.getSortedColumnHeaderText();
|
||||
let sortOrder = await this.getSortingOrder();
|
||||
if (sortColumn !== label) {
|
||||
await this.getColumnHeaderByName(label).click({ force: true });
|
||||
sortOrder = await this.getSortingOrder();
|
||||
}
|
||||
if (sortOrder !== order) {
|
||||
await this.getChild('span[class*="adf-datatable__header--sorted"]').click();
|
||||
}
|
||||
|
||||
await this.spinnerWaitForReload();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -281,4 +290,29 @@ export class DataTableComponent extends BaseComponent {
|
||||
async getRowAllInnerTexts(name: string): Promise<string> {
|
||||
return (await this.getRowByName(name).locator('span').allInnerTexts()).toString();
|
||||
}
|
||||
|
||||
async getFirstElementDetail(name: string): Promise<string> {
|
||||
const firstNode = this.getColumnValuesByName(name).first();
|
||||
return firstNode.innerText();
|
||||
}
|
||||
|
||||
async isEmpty(): Promise<boolean> {
|
||||
return this.emptyList.isVisible();
|
||||
}
|
||||
|
||||
async getEmptyStateTitle(): Promise<string> {
|
||||
return (await this.isEmpty()) ? this.emptyListTitle.innerText() : '';
|
||||
}
|
||||
|
||||
async getEmptyStateSubtitle(): Promise<string> {
|
||||
return (await this.isEmpty()) ? this.emptyListSubtitle.innerText() : '';
|
||||
}
|
||||
|
||||
async getEmptyListText(): Promise<string> {
|
||||
return (await this.isEmpty()) ? this.emptyListTest.innerText() : '';
|
||||
}
|
||||
|
||||
async getRowsCount(): Promise<number> {
|
||||
return this.getRowLocator.count();
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,36 @@
|
||||
/*!
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
import { Page } from '@playwright/test';
|
||||
import { BaseComponent } from './base.component';
|
||||
|
||||
export class ErrorComponent extends BaseComponent {
|
||||
private static rootElement = 'aca-page-layout';
|
||||
genericError = this.getChild('aca-generic-error');
|
||||
genericErrorTitle = this.getChild('.generic-error__title');
|
||||
|
||||
constructor(page: Page) {
|
||||
super(page, ErrorComponent.rootElement);
|
||||
}
|
||||
}
|
@@ -38,3 +38,4 @@ export * from './search/search-overlay.components';
|
||||
export * from './breadcrumb/breadcrumb.component';
|
||||
export * from './sidenav.component';
|
||||
export * from './aca-header.component';
|
||||
export * from './error.component';
|
||||
|
@@ -105,7 +105,7 @@ export class PaginationComponent extends BaseComponent {
|
||||
if (await this.isNextEnabled()) {
|
||||
await this.nextButton.click();
|
||||
}
|
||||
} catch(error) {
|
||||
} catch (error) {
|
||||
throw new Error(`Failed on previous click: ${error}`);
|
||||
}
|
||||
}
|
||||
@@ -115,7 +115,7 @@ export class PaginationComponent extends BaseComponent {
|
||||
if (await this.isPreviousEnabled()) {
|
||||
await this.previousButton.click();
|
||||
}
|
||||
} catch(error) {
|
||||
} catch (error) {
|
||||
throw new Error(`Failed on previous click: ${error}`);
|
||||
}
|
||||
}
|
||||
@@ -166,4 +166,12 @@ export class PaginationComponent extends BaseComponent {
|
||||
async closeMenu(): Promise<void> {
|
||||
await this.page.keyboard.press('Escape');
|
||||
}
|
||||
|
||||
async isRangePresent(): Promise<boolean> {
|
||||
return this.range.isVisible();
|
||||
}
|
||||
|
||||
async isMaxItemsPresent(): Promise<boolean> {
|
||||
return this.maxItems.isVisible();
|
||||
}
|
||||
}
|
||||
|
@@ -36,7 +36,8 @@ import {
|
||||
MatMenuComponent,
|
||||
ViewerComponent,
|
||||
SidenavComponent,
|
||||
PaginationComponent
|
||||
PaginationComponent,
|
||||
ErrorComponent
|
||||
} from '../components';
|
||||
|
||||
export class PersonalFilesPage extends BasePage {
|
||||
@@ -58,6 +59,7 @@ export class PersonalFilesPage extends BasePage {
|
||||
public sidenav = new SidenavComponent(this.page);
|
||||
public createFromTemplateDialogComponent = new CreateFromTemplateDialogComponent(this.page);
|
||||
public pagination = new PaginationComponent(this.page);
|
||||
public errorDialog = new ErrorComponent(this.page);
|
||||
|
||||
async selectCreateFolder(): Promise<void> {
|
||||
await this.acaHeader.createButton.click();
|
||||
|
@@ -24,7 +24,7 @@
|
||||
|
||||
import { Page } from '@playwright/test';
|
||||
import { BasePage } from './base.page';
|
||||
import { DataTableComponent, MatMenuComponent, ViewerComponent, SidenavComponent, Breadcrumb } from '../components';
|
||||
import { DataTableComponent, MatMenuComponent, ViewerComponent, SidenavComponent, Breadcrumb, PaginationComponent } from '../components';
|
||||
import { AcaHeader } from '../components/aca-header.component';
|
||||
import { AdfFolderDialogComponent, ViewerOverlayDialogComponent } from '../components/dialogs';
|
||||
|
||||
@@ -43,4 +43,5 @@ export class TrashPage extends BasePage {
|
||||
public viewerDialog = new ViewerOverlayDialogComponent(this.page);
|
||||
public sidenav = new SidenavComponent(this.page);
|
||||
public breadcrumb = new Breadcrumb(this.page);
|
||||
public pagination = new PaginationComponent(this.page);
|
||||
}
|
||||
|
Reference in New Issue
Block a user