[ACS-9065] [E2E] Added folder information tests in ACA (#4478)

* [ACS-9065] Added folder information tests in ACA

* [ACS-9065] fixed sonar issues

* [ACS-9065] Changed test describe name

* [ACS-9065] debugging dialog errors 1

* [ACS-9065] removed debugging reload

* [ACS-9065] renamed e2e file
This commit is contained in:
Adam Świderski 2025-04-03 10:02:43 +02:00 committed by GitHub
parent 66d6afd12a
commit ebbc868aa1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 386 additions and 4 deletions

View File

@ -148,6 +148,8 @@ jobs:
id: 17
- name: "smoke-test"
id: 18
- name: "folder-information-actions"
id: 19
steps:
- name: Checkout
uses: actions/checkout@v4

View File

@ -0,0 +1,26 @@
{
"extends": "../../../.eslintrc.json",
"ignorePatterns": [
"!**/*"
],
"overrides": [
{
"files": [
"*.ts"
],
"parserOptions": {
"project": [
"e2e/playwright/folder-information-actions/tsconfig.e2e.json"
],
"createDefaultProgram": true
},
"plugins": [
"rxjs",
"unicorn"
],
"rules": {
"@typescript-eslint/no-floating-promises": "off"
}
}
]
}

View File

@ -0,0 +1 @@
{}

View File

@ -0,0 +1,42 @@
/*!
* Copyright © 2005-2025 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 { PlaywrightTestConfig } from '@playwright/test';
import { CustomConfig, getGlobalConfig, getExcludedTestsRegExpArray } from '@alfresco/aca-playwright-shared';
import EXCLUDED_JSON from './exclude.tests.json';
const config: PlaywrightTestConfig<CustomConfig> = {
...getGlobalConfig,
grepInvert: getExcludedTestsRegExpArray(EXCLUDED_JSON, 'Folder Information Actions'),
projects: [
{
name: 'Folder Information Actions',
testDir: './src/tests',
use: {}
}
]
};
export default config;

View File

@ -0,0 +1,31 @@
{
"name": "folder-information-actions-e2e",
"$schema": "../../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "e2e/playwright/folder-information-actions",
"projectType": "application",
"targets": {
"e2e": {
"executor": "nx:run-commands",
"options": {
"commands": ["npx playwright test --config=e2e/playwright/folder-information-actions/playwright.config.ts"]
},
"configurations": {
"production": {
"devServerTarget": "content-ce:serve:production"
},
"ui": {
"args": ["--ui"]
},
"debug": {
"args": ["--debug"]
},
"headed": {
"args": ["--headed"]
}
}
},
"lint": {
"executor": "@angular-eslint/builder:lint"
}
}
}

View File

@ -0,0 +1,195 @@
/*!
* Copyright © 2005-2025 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 { expect } from '@playwright/test';
import {
ApiClientFactory,
NodesApi,
Utils,
test,
TrashcanApi,
TEST_FILES,
FileActionsApi,
PersonalFilesPage,
MyLibrariesPage,
SitesApi,
SearchPage
} from '@alfresco/aca-playwright-shared';
test.describe('Actions - Folder Information', () => {
const username = `user-e2e-${Utils.random()}`;
const emptyFolder = `folder17722-${Utils.random()}`;
const folder1File = `folder17715-${Utils.random()}`;
const folderXFiles = `folder17752-${Utils.random()}`;
const folderXFilesAndFolders = `folder17753-1-${Utils.random()}`;
const folderInsideFolder = `folder17753-2-${Utils.random()}`;
const folderInLibrary = `folder17758-${Utils.random()}`;
const libraryForFolder = `library17758-${Utils.random()}`;
const folderForSearch = `folder17759-${Utils.random()}`;
const folderNested1 = `folder17766-1-${Utils.random()}`;
const folderNested2 = `folder17766-1-${Utils.random()}`;
const folderNested3 = `folder17766-1-${Utils.random()}`;
const file1 = `file1-${Utils.random()}.docx`;
const file2 = `file2-${Utils.random()}.docx`;
const file3 = `file3-${Utils.random()}.docx`;
const file4 = `file4-${Utils.random()}.docx`;
const file5 = `file5-${Utils.random()}.docx`;
const file6 = `file6-${Utils.random()}.docx`;
const file7 = `file7-${Utils.random()}.docx`;
const file8 = `file8-${Utils.random()}.docx`;
const file9 = `file9-${Utils.random()}.docx`;
const file10 = `file10-${Utils.random()}.docx`;
const file11 = `file10-${Utils.random()}.docx`;
const file12 = `file10-${Utils.random()}.docx`;
const file13 = `file10-${Utils.random()}.docx`;
let nodesApi: NodesApi;
let trashcanApi: TrashcanApi;
let fileActionsApi: FileActionsApi;
let sitesApi: SitesApi;
let folder1FileId: string;
let folderXFilesId: string;
let folderXFilesAndFoldersId: string;
let folderInsideFolderId: string;
let folderInLibraryId: string;
let siteId: string;
let folderForSearchId: string;
let folderNested1Id: string;
let folderNested2Id: string;
let folderNested3Id: string;
test.beforeAll(async () => {
const apiService = new ApiClientFactory();
await apiService.setUpAcaBackend('admin');
await apiService.createUser({ username: username });
nodesApi = await NodesApi.initialize(username, username);
trashcanApi = await TrashcanApi.initialize(username, username);
fileActionsApi = await FileActionsApi.initialize(username, username);
sitesApi = await SitesApi.initialize(username, username);
siteId = (await sitesApi.createSite(libraryForFolder)).entry.id;
const docLibId = await sitesApi.getDocLibId(siteId);
await nodesApi.createFolder(emptyFolder, '-my-');
folder1FileId = (await nodesApi.createFolder(folder1File, '-my-')).entry.id;
folderXFilesId = (await nodesApi.createFolder(folderXFiles, '-my-')).entry.id;
folderXFilesAndFoldersId = (await nodesApi.createFolder(folderXFilesAndFolders, '-my-')).entry.id;
folderInsideFolderId = (await nodesApi.createFolder(folderInsideFolder, folderXFilesAndFoldersId)).entry.id;
folderInLibraryId = (await nodesApi.createFolder(folderInLibrary, docLibId)).entry.id;
folderForSearchId = (await nodesApi.createFolder(folderForSearch, '-my-')).entry.id;
folderNested1Id = (await nodesApi.createFolder(folderNested1, '-my-')).entry.id;
folderNested2Id = (await nodesApi.createFolder(folderNested2, folderNested1Id)).entry.id;
folderNested3Id = (await nodesApi.createFolder(folderNested3, folderNested2Id)).entry.id;
await fileActionsApi.uploadFileWithRename(TEST_FILES.DOCX.path, file1, folder1FileId);
await fileActionsApi.uploadFileWithRename(TEST_FILES.DOCX.path, file2, folderXFilesId);
await fileActionsApi.uploadFileWithRename(TEST_FILES.DOCX.path, file3, folderXFilesId);
await fileActionsApi.uploadFileWithRename(TEST_FILES.DOCX.path, file4, folderXFilesId);
await fileActionsApi.uploadFileWithRename(TEST_FILES.DOCX.path, file5, folderXFilesAndFoldersId);
await fileActionsApi.uploadFileWithRename(TEST_FILES.DOCX.path, file6, folderXFilesAndFoldersId);
await fileActionsApi.uploadFileWithRename(TEST_FILES.DOCX.path, file7, folderXFilesAndFoldersId);
await fileActionsApi.uploadFileWithRename(TEST_FILES.DOCX.path, file8, folderInsideFolderId);
await fileActionsApi.uploadFileWithRename(TEST_FILES.DOCX.path, file9, folderInsideFolderId);
await fileActionsApi.uploadFileWithRename(TEST_FILES.DOCX.path, file10, folderInLibraryId);
await fileActionsApi.uploadFileWithRename(TEST_FILES.DOCX.path, file11, folderForSearchId);
await fileActionsApi.uploadFileWithRename(TEST_FILES.DOCX.path, file12, folderForSearchId);
await fileActionsApi.uploadFileWithRename(TEST_FILES.DOCX.path, file13, folderNested3Id);
});
test.beforeEach(async ({ loginPage }) => {
await Utils.tryLoginUser(loginPage, username, username, 'Main beforeEach failed');
});
test.afterAll(async () => {
await Utils.deleteNodesSitesEmptyTrashcan(nodesApi, trashcanApi, 'afterAll failed');
});
async function checkFolderInformation(
page: PersonalFilesPage | MyLibrariesPage | SearchPage,
folderName: string,
expectedSize: string,
location: string,
isEmptyFolder?: 'isEmpty'
) {
await page.dataTable.selectItems(folderName);
await page.acaHeader.clickMoreActions();
await page.matMenu.clickMenuItem('Folder Information');
await expect(async () => {
expect(await page.folderInformationDialog.folderSize.textContent()).toContain(expectedSize);
}).toPass({
intervals: [1_000],
timeout: 5_000
});
if (!isEmptyFolder) {
expect(await page.folderInformationDialog.getFolderSizeNumber()).toBeGreaterThan(0);
}
expect(await page.folderInformationDialog.folderLocation.textContent()).toContain(location);
expect(await page.folderInformationDialog.folderCreationDate.textContent()).toContain('ago');
expect(await page.folderInformationDialog.folderModifiedDate.textContent()).toContain('ago');
await page.folderInformationDialog.doneButton.click();
await page.folderInformationDialog.folderName.waitFor({ state: 'hidden' });
}
test('[XAT-17722] Folder information Empty folder size and number of documents as 0', async ({ personalFiles }) => {
await personalFiles.navigate();
await checkFolderInformation(personalFiles, emptyFolder, '0 bytes for 0 files', `/Company Home/User Homes/${username}`, 'isEmpty');
});
test('[XAT-17715] Folder information correct folder size and number of documents - single file', async ({ personalFiles }) => {
await personalFiles.navigate();
await checkFolderInformation(personalFiles, folder1File, 'for 1 files', `/Company Home/User Homes/${username}`);
});
test('[XAT-17752] Folder information correct folder size and number of documents - multiple files', async ({ personalFiles }) => {
await personalFiles.navigate();
await checkFolderInformation(personalFiles, folderXFiles, 'for 3 files', `/Company Home/User Homes/${username}`);
});
test('[XAT-17753] Folder information correct folder size and number of documents - folder and files', async ({ personalFiles }) => {
await personalFiles.navigate();
await checkFolderInformation(personalFiles, folderXFilesAndFolders, 'for 5 files', `/Company Home/User Homes/${username}`);
});
test('[XAT-17758] Folder information correct folder size and number of documents - from libraries', async ({ myLibrariesPage }) => {
await myLibrariesPage.navigate();
await myLibrariesPage.dataTable.getRowByName(libraryForFolder).dblclick();
await checkFolderInformation(myLibrariesPage, folderInLibrary, 'for 1 files', `/Company Home/Sites/${libraryForFolder}/documentLibrary`);
});
test('[XAT-17759] Folder information correct folder size and number of documents - from search', async ({ personalFiles, searchPage }) => {
await personalFiles.navigate();
await searchPage.searchWithin(folderForSearch, 'folders');
await checkFolderInformation(searchPage, folderForSearch, 'for 2 files', `/Company Home/User Homes/${username}`);
});
test('[XAT-17766] Folder information correct folder size and number of documents - nested folders', async ({ personalFiles }) => {
await personalFiles.navigate();
await personalFiles.dataTable.getRowByName(folderNested1).dblclick();
await personalFiles.dataTable.getRowByName(folderNested2).dblclick();
await checkFolderInformation(
personalFiles,
folderNested3,
'for 1 files',
`/Company Home/User Homes/${username}/${folderNested1}/${folderNested2}`
);
});
});

View File

@ -0,0 +1,15 @@
{
"extends": "../../../tsconfig.adf.json",
"compilerOptions": {
"outDir": "../../out-tsc/e2e",
"baseUrl": "./",
"module": "commonjs",
"target": "es2017",
"types": ["jasmine", "jasminewd2", "node"],
"skipLibCheck": true,
"paths": {
"@alfresco/aca-playwright-shared": ["dist/@alfresco/aca-playwright-shared"]
}
},
"exclude": ["node_modules"]
}

View File

@ -0,0 +1,15 @@
{
"extends": "../../../tsconfig.json",
"compilerOptions": {
"outDir": "../../out-tsc/e2e",
"baseUrl": "./",
"module": "commonjs",
"target": "es2017",
"types": ["jasmine", "jasminewd2", "node", "@playwright/test"],
"skipLibCheck": true,
"paths": {
"@alfresco/aca-playwright-shared": ["dist/@alfresco/aca-playwright-shared"]
}
},
"exclude": ["node_modules"]
}

View File

@ -0,0 +1,49 @@
/*!
* Copyright © 2005-2025 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 FolderInformationDialogComponent extends BaseComponent {
private static readonly rootElement = '[data-automation-id="adf-dialog-container"]';
constructor(page: Page) {
super(page, FolderInformationDialogComponent.rootElement);
}
folderName = this.getChild('.aca-folder-info-header');
doneButton = this.getChild('[data-automation-id="adf-dialog-actions-confirm"]');
folderSize = this.getChild('[data-automation-id="folder-info-size"]');
folderLocation = this.getChild('[data-automation-id="folder-info-location"]');
folderCreationDate = this.getChild('[data-automation-id="folder-info-creation-date"]');
folderModifiedDate = this.getChild('[data-automation-id="folder-info-modify-date"]');
async getFolderSizeNumber(): Promise<number> {
const textContent = await this.folderSize.textContent();
if (!textContent) {
throw new Error('Folder size text content is null or undefined');
}
return parseInt(textContent.split(' ')[0].replace(/,/g, ''), 10);
}
}

View File

@ -36,4 +36,4 @@ export * from './upload-dialog.component';
export * from './delete-trash-dialog.component';
export * from './link-rules.component';
export * from './edit-dialog.component';
export * from './manage-versions-dialog.component';
export * from './folder-information-dialog.component';

View File

@ -36,7 +36,8 @@ import {
Breadcrumb,
SidenavComponent,
CreateFromTemplateDialogComponent,
AdfConfirmDialogComponent
AdfConfirmDialogComponent,
FolderInformationDialogComponent
} from '../components';
export class MyLibrariesPage extends BasePage {
@ -58,6 +59,7 @@ export class MyLibrariesPage extends BasePage {
public contentNodeSelector = new ContentNodeSelectorDialog(this.page);
public createFromTemplateDialogComponent = new CreateFromTemplateDialogComponent(this.page);
public confirmDialogComponent = new AdfConfirmDialogComponent(this.page);
public folderInformationDialog = new FolderInformationDialogComponent(this.page);
async selectCreateLibrary(): Promise<void> {
await this.acaHeader.createButton.click();

View File

@ -45,7 +45,8 @@ import {
ManageVersionsDialog,
UploadDialog,
SnackBarComponent,
EditDialog
EditDialog,
FolderInformationDialogComponent
} from '../components';
export class PersonalFilesPage extends BasePage {
@ -76,6 +77,7 @@ export class PersonalFilesPage extends BasePage {
public uploadDialog = new UploadDialog(this.page);
public snackBar = new SnackBarComponent(this.page);
public editDialog = new EditDialog(this.page);
public folderInformationDialog = new FolderInformationDialogComponent(this.page);
async selectCreateFolder(): Promise<void> {
await this.acaHeader.createButton.click();

View File

@ -38,7 +38,8 @@ import {
SearchFiltersDate,
SearchFiltersLocation,
SearchFiltersLogic,
SearchFiltersProperties
SearchFiltersProperties,
FolderInformationDialogComponent
} from '../components';
import { AcaHeader } from '../components/aca-header.component';
import { AdfConfirmDialogComponent, AdfFolderDialogComponent, UploadNewVersionDialog, ManageVersionsDialog } from '../components/dialogs';
@ -71,6 +72,7 @@ export class SearchPage extends BasePage {
public confirmDialogComponent = new AdfConfirmDialogComponent(this.page);
public uploadNewVersionDialog = new UploadNewVersionDialog(this.page);
public manageVersionsDialog = new ManageVersionsDialog(this.page);
public folderInformationDialog = new FolderInformationDialogComponent(this.page);
async searchWithin(searchText: string, searchType?: SearchType): Promise<void> {
await this.acaHeader.searchButton.click();