From ff38c7d19cd35c89c5951a9f17636c55a385b807 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20=C5=9Awiderski?= Date: Mon, 30 Mar 2026 09:40:54 +0200 Subject: [PATCH] [ACS-11233] Testing week test cases automated in ACA (#5113) * [ACS-11233] Testing week test cases automated in ACA * [ACS-11233] last test additions from testing week * [ACS-11233] sonar fix 1 * eslint configuration for e2e tests * [ACS-11233] sonar fix 2 * [ACS-11233] sonar fix 3 * [ACS-11233] added viewer actions as a seperate test suite * [ACS-11233] added viewer actions to pr yml * [ACS-11233] deleted autocorrection * [ACS-11233] review fix 1 * [ACS-11233] review fix 2 * [ACS-11233] small test fixes and report portal upload timeout change * [ACS-11233] reportportal fix 2 * [ACS-11233] viewer tests fixes * [ACS-11233] review fix 3 * [ACS-11233] review fix 4 * [ACS-11233] deleted angular inject test 1 * [ACS-11233] viewer tests fix 3 --- .github/workflows/pull-request.yml | 2 + e2e/playwright/README.md | 2 +- .../src/tests/update-rules.e2e.ts | 47 +- .../list-views/src/tests/favorites.e2e.ts | 80 ++- .../src/tests/personal-files.e2e.ts | 68 +- .../list-views/src/tests/recent-files.e2e.ts | 4 +- .../tests/special-permissions-actions.e2e.ts | 6 +- e2e/playwright/viewer-actions/.eslintrc.json | 22 + .../viewer-actions/exclude.tests.json | 9 + .../viewer-actions/playwright.config.ts | 36 + e2e/playwright/viewer-actions/project.json | 31 + .../src/tests/viewer-action.e2e.ts | 546 +++++++++++++++ .../viewer-actions/tsconfig.e2e.adf.json | 15 + .../viewer-actions/tsconfig.e2e.json | 15 + e2e/playwright/viewer/exclude.tests.json | 4 - .../viewer/src/tests/viewer-action.e2e.ts | 237 ------- .../viewer/src/tests/viewer-protected.e2e.ts | 5 +- .../src/tests/viewer-version-actions.e2e.ts | 10 +- e2e/playwright/viewer/src/tests/viewer.e2e.ts | 625 +++++++++++++----- .../src/api/file-actions.ts | 6 +- .../src/api/nodes-api.ts | 12 + .../src/api/search-api.ts | 50 +- .../src/base-config/report-portal.config.ts | 3 +- .../dataTable/data-table.component.ts | 1 + .../manage-versions-dialog.component.ts | 27 +- .../components/viewer.component.ts | 11 +- .../aca-playwright-shared/src/utils/utils.ts | 4 + 27 files changed, 1401 insertions(+), 477 deletions(-) create mode 100644 e2e/playwright/viewer-actions/.eslintrc.json create mode 100644 e2e/playwright/viewer-actions/exclude.tests.json create mode 100644 e2e/playwright/viewer-actions/playwright.config.ts create mode 100644 e2e/playwright/viewer-actions/project.json create mode 100644 e2e/playwright/viewer-actions/src/tests/viewer-action.e2e.ts create mode 100644 e2e/playwright/viewer-actions/tsconfig.e2e.adf.json create mode 100644 e2e/playwright/viewer-actions/tsconfig.e2e.json delete mode 100644 e2e/playwright/viewer/src/tests/viewer-action.e2e.ts diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index 60b311032..3ab822d11 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -159,6 +159,8 @@ jobs: id: 18 - name: "folder-information-actions" id: 19 + - name: "viewer-actions" + id: 20 steps: - name: Free hosted runner disk space uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@f4f88654f4529442e95151ad820016dd6f9f87ed # v15.6.2 diff --git a/e2e/playwright/README.md b/e2e/playwright/README.md index cf8417891..b2237a107 100644 --- a/e2e/playwright/README.md +++ b/e2e/playwright/README.md @@ -163,7 +163,7 @@ When tests run in CI, results are available in two places: **GitHub Actions** an CI e2e test results are automatically reported to Report Portal for analysis and historical tracking. The Report Portal URL is available in the GitHub Actions workflow run under "Run e2e Playwright" section. -**Sample URL format**: `https://reportportal.envalfresco.com/ui/#alfresco-content-app/launches/all/` +**Sample URL format**: `https://reportportal-dev.studio.dev.experience.hyland.com/ui/#alfresco-content-app/launches/all/` - Project name: `alfresco-content-app` - Tests are reported only in CI environments (not locally) diff --git a/e2e/playwright/folder-rules/src/tests/update-rules.e2e.ts b/e2e/playwright/folder-rules/src/tests/update-rules.e2e.ts index 628d5af48..4245c7310 100644 --- a/e2e/playwright/folder-rules/src/tests/update-rules.e2e.ts +++ b/e2e/playwright/folder-rules/src/tests/update-rules.e2e.ts @@ -25,7 +25,7 @@ import { ApiClientFactory, test, Utils, NodesApi, TrashcanApi, ActionType, RulesApi, Field, Comparator } from '@alfresco/aca-playwright-shared'; import { expect } from '@playwright/test'; -test.use({ launchOptions: { slowMo: 300 } }); +test.use({ launchOptions: { slowMo: 500 } }); test.describe('Rules - Manage Rules', () => { const apiClientFactory = new ApiClientFactory(); @@ -35,7 +35,12 @@ test.describe('Rules - Manage Rules', () => { const username = `user-e2e-${Utils.random()}`; const folderName897_1 = `folder-XAT-897-1-${Utils.random()}`; const folderName897_2 = `folder-XAT-897-2-${Utils.random()}`; - const randomFolderName1 = `folder-name-${Utils.random()}`; + const folderName898 = `folder-XAT-898-${Utils.random()}`; + const folderName899 = `folder-XAT-899-${Utils.random()}`; + const folderName900 = `folder-XAT-900-${Utils.random()}`; + const folderName901 = `folder-XAT-901-${Utils.random()}`; + const folderName902 = `folder-XAT-902-${Utils.random()}`; + const folderName903 = `folder-XAT-903-${Utils.random()}`; const randomRuleName897 = `playwright-rule-897-${Utils.random()}`; const randomRuleName898 = `playwright-rule-898-${Utils.random()}`; const randomRuleName899 = `playwright-rule-899-${Utils.random()}`; @@ -46,7 +51,12 @@ test.describe('Rules - Manage Rules', () => { let folderName897Id1: string; let folderName897Id2: string; - let randomFolderId: string; + let folderId898: string; + let folderId899: string; + let folderId900: string; + let folderId901: string; + let folderId902: string; + let folderId903: string; test.beforeAll(async () => { try { @@ -62,15 +72,20 @@ test.describe('Rules - Manage Rules', () => { await apiClientFactory.setUpAcaBackend(username, username); folderName897Id1 = (await nodesApi.createFolder(folderName897_1)).entry.id; folderName897Id2 = (await nodesApi.createFolder(folderName897_2)).entry.id; - randomFolderId = (await nodesApi.createFolder(randomFolderName1)).entry.id; + folderId898 = (await nodesApi.createFolder(folderName898)).entry.id; + folderId899 = (await nodesApi.createFolder(folderName899)).entry.id; + folderId900 = (await nodesApi.createFolder(folderName900)).entry.id; + folderId901 = (await nodesApi.createFolder(folderName901)).entry.id; + folderId902 = (await nodesApi.createFolder(folderName902)).entry.id; + folderId903 = (await nodesApi.createFolder(folderName903)).entry.id; await rulesApi.createRuleWithDestinationFolder(folderName897Id1, randomRuleName897, 'move', folderName897Id2); - await rulesApi.createRandomRule(randomFolderId, randomRuleName898); - await rulesApi.createRandomRuleWithMultipleActions(randomFolderId, randomRuleName899, 3); - await rulesApi.createRuleWithRandomAspects(randomFolderId, randomRuleName900); - await rulesApi.createRandomRuleWithMultipleActions(randomFolderId, randomRuleName901, 3); - await rulesApi.createRandomRule(randomFolderId, randomRuleName902); - await rulesApi.createRandomRuleWithMultipleConditions(randomFolderId, randomRuleName903, 3); + await rulesApi.createRandomRule(folderId898, randomRuleName898); + await rulesApi.createRandomRuleWithMultipleActions(folderId899, randomRuleName899, 3); + await rulesApi.createRuleWithRandomAspects(folderId900, randomRuleName900); + await rulesApi.createRandomRuleWithMultipleActions(folderId901, randomRuleName901, 3); + await rulesApi.createRandomRule(folderId902, randomRuleName902); + await rulesApi.createRandomRuleWithMultipleConditions(folderId903, randomRuleName903, 3); await nodesApi.deleteNodeById(folderName897Id2); }); @@ -92,7 +107,7 @@ test.describe('Rules - Manage Rules', () => { }); test('[XAT-898] Cancel updating rule dialog', async ({ personalFiles, nodesPage }) => { - await personalFiles.dataTable.performActionFromExpandableMenu(randomFolderName1, 'Manage rules'); + await personalFiles.dataTable.performActionFromExpandableMenu(folderName898, 'Manage rules'); await nodesPage.manageRules.ruleDetailsEditButton.click(); await nodesPage.manageRulesDialog.ruleNameInputLocator.fill('new name'); await nodesPage.manageRulesDialog.cancelRuleButton.click(); @@ -100,7 +115,7 @@ test.describe('Rules - Manage Rules', () => { }); test('[XAT-899] Update rule by removing existing actions', async ({ personalFiles, nodesPage }) => { - await personalFiles.dataTable.performActionFromExpandableMenu(randomFolderName1, 'Manage rules'); + await personalFiles.dataTable.performActionFromExpandableMenu(folderName899, 'Manage rules'); await nodesPage.manageRules.getGroupsList(randomRuleName899).click(); await nodesPage.manageRules.ruleDetailsEditButton.click(); await nodesPage.manageRulesDialog.deleteActions(2); @@ -113,7 +128,7 @@ test.describe('Rules - Manage Rules', () => { }); test('[XAT-900] Update a rule by removing existing aspects', async ({ personalFiles, nodesPage }) => { - await personalFiles.dataTable.performActionFromExpandableMenu(randomFolderName1, 'Manage rules'); + await personalFiles.dataTable.performActionFromExpandableMenu(folderName900, 'Manage rules'); await nodesPage.manageRules.getGroupsList(randomRuleName900).click(); await nodesPage.manageRules.ruleDetailsEditButton.click(); await nodesPage.manageRulesDialog.deleteActions(2); @@ -127,7 +142,7 @@ test.describe('Rules - Manage Rules', () => { }); test('[XAT-901] Prevent rule updating after clicking on cancel during selecting destination folder', async ({ personalFiles, nodesPage }) => { - await personalFiles.dataTable.performActionFromExpandableMenu(randomFolderName1, 'Manage rules'); + await personalFiles.dataTable.performActionFromExpandableMenu(folderName901, 'Manage rules'); await nodesPage.manageRules.getGroupsList(randomRuleName901).click(); await nodesPage.manageRules.ruleDetailsEditButton.click(); await nodesPage.manageRulesDialog.deleteActions(2); @@ -139,7 +154,7 @@ test.describe('Rules - Manage Rules', () => { }); test('[XAT-902] Prevent rule updating when required fields are empty', async ({ personalFiles, nodesPage }) => { - await personalFiles.dataTable.performActionFromExpandableMenu(randomFolderName1, 'Manage rules'); + await personalFiles.dataTable.performActionFromExpandableMenu(folderName902, 'Manage rules'); await nodesPage.manageRules.getGroupsList(randomRuleName902).click(); await nodesPage.manageRules.ruleDetailsEditButton.click(); await nodesPage.actionsDropdown.selectAction(ActionType.AddAspect, 1); @@ -147,7 +162,7 @@ test.describe('Rules - Manage Rules', () => { }); test('[XAT-903] [XAT-904] Edit existing conditions', async ({ personalFiles, nodesPage }) => { - await personalFiles.dataTable.performActionFromExpandableMenu(randomFolderName1, 'Manage rules'); + await personalFiles.dataTable.performActionFromExpandableMenu(folderName903, 'Manage rules'); await nodesPage.manageRules.getGroupsList(randomRuleName903).click(); await nodesPage.manageRules.ruleDetailsEditButton.click(); await nodesPage.manageRulesDialog.deleteConditions(2); diff --git a/e2e/playwright/list-views/src/tests/favorites.e2e.ts b/e2e/playwright/list-views/src/tests/favorites.e2e.ts index d3e9ab9b7..a2caf1f85 100644 --- a/e2e/playwright/list-views/src/tests/favorites.e2e.ts +++ b/e2e/playwright/list-views/src/tests/favorites.e2e.ts @@ -30,6 +30,10 @@ test.describe('Favorites Files', () => { let nodesApi: NodesApi; let trashcanApi: TrashcanApi; let siteActionsAdmin: SitesApi; + let favoritesActions: FavoritesPageApi; + let nodesApiAdmin: NodesApi; + let apiClientFactory: ApiClientFactory; + let parentId: string; const username = `user-${Utils.random()}`; const siteName = `site-${Utils.random()}`; const favFolderName = `favFolder-${Utils.random()}`; @@ -42,36 +46,16 @@ test.describe('Favorites Files', () => { test.beforeAll(async () => { try { test.setTimeout(timeouts.extendedTest); - const apiClientFactory = new ApiClientFactory(); + apiClientFactory = new ApiClientFactory(); await apiClientFactory.setUpAcaBackend('admin'); await apiClientFactory.createUser({ username }); nodesApi = await NodesApi.initialize(username, username); trashcanApi = await TrashcanApi.initialize(username, username); - const nodesApiAdmin = await NodesApi.initialize('admin'); + nodesApiAdmin = await NodesApi.initialize('admin'); siteActionsAdmin = await SitesApi.initialize('admin'); - const favoritesActions = await FavoritesPageApi.initialize(username, username); - const consumerFavoritesTotalItems = await favoritesActions.getFavoritesTotalItems(username); - const folderFavId = (await nodesApi.createFolder(favFolderName)).entry.id; - const parentId = (await nodesApi.createFolder(parentFolder)).entry.id; - await siteActionsAdmin.createSite(siteName, Site.VisibilityEnum.PUBLIC); - const docLibId = await siteActionsAdmin.getDocLibId(siteName); - await siteActionsAdmin.addSiteMember(siteName, username, Site.RoleEnum.SiteManager); - await favoritesActions.addFavoritesByIds('folder', [folderFavId]); - const file1Id = (await nodesApiAdmin.createFile(fileName1, docLibId)).entry.id; - const file2Id = (await nodesApi.createFile(fileName2, parentId)).entry.id; - const file3Id = (await nodesApi.createFile(fileName3, parentId)).entry.id; - const file4Id = (await nodesApi.createFile(fileName4, parentId)).entry.id; + favoritesActions = await FavoritesPageApi.initialize(username, username); - await favoritesActions.addFavoritesByIds('file', [file1Id]); - await favoritesActions.addFavoriteById('file', file2Id); - await favoritesActions.addFavoriteById('file', file3Id); - await favoritesActions.addFavoriteById('file', file4Id); - await nodesApi.deleteNodes([file3Id, file4Id], false); - await apiClientFactory.trashCan.restoreDeletedNode(file4Id); - await Promise.all([ - favoritesActions.isFavoriteWithRetry(username, folderFavId, { expect: true }), - favoritesActions.waitForApi(username, { expect: consumerFavoritesTotalItems + 4 }) - ]); + parentId = (await nodesApi.createFolder(parentFolder)).entry.id; } catch (error) { console.error(`beforeAll failed : ${error}`); } @@ -85,7 +69,47 @@ test.describe('Favorites Files', () => { await Utils.deleteNodesSitesEmptyTrashcan(nodesApi, trashcanApi, 'afterAll failed', siteActionsAdmin, [siteName]); }); + test.describe(`Deleted favorite files in data list`, () => { + test.beforeAll(async () => { + const file3Id = (await nodesApi.createFile(fileName3, parentId)).entry.id; + const file4Id = (await nodesApi.createFile(fileName4, parentId)).entry.id; + await favoritesActions.addFavoriteById('file', file3Id); + await favoritesActions.addFavoriteById('file', file4Id); + await nodesApi.deleteNodes([file3Id, file4Id], false); + await apiClientFactory.trashCan.restoreDeletedNode(file4Id); + }); + + test.beforeEach(async ({ favoritePage }) => { + await favoritePage.navigate(); + }); + + test(`[XAT-4456] Deleted favorite files and folders do not appear in the list`, async ({ favoritePage }) => { + expect(await favoritePage.dataTable.getRowByName(fileName3).isHidden(), `${fileName3} is displayed`).toBe(true); + }); + + test(`[XAT-4457] Favorite files and folders restored from trashcan are displayed in the list`, async ({ favoritePage }) => { + expect(await favoritePage.dataTable.isItemPresent(fileName4), `${fileName4} not displayed`).toBe(true); + }); + }); + test.describe(`Regular user's Favorites files`, () => { + test.beforeAll(async () => { + const consumerFavoritesTotalItems = await favoritesActions.getFavoritesTotalItems(username); + const folderFavId = (await nodesApi.createFolder(favFolderName)).entry.id; + await siteActionsAdmin.createSite(siteName, Site.VisibilityEnum.PUBLIC); + const docLibId = await siteActionsAdmin.getDocLibId(siteName); + await siteActionsAdmin.addSiteMember(siteName, username, Site.RoleEnum.SiteManager); + await favoritesActions.addFavoritesByIds('folder', [folderFavId]); + const file1Id = (await nodesApiAdmin.createFile(fileName1, docLibId)).entry.id; + const file2Id = (await nodesApi.createFile(fileName2, parentId)).entry.id; + await favoritesActions.addFavoritesByIds('file', [file1Id]); + await favoritesActions.addFavoriteById('file', file2Id); + await Promise.all([ + favoritesActions.isFavoriteWithRetry(username, folderFavId, { expect: true }), + favoritesActions.waitForApi(username, { expect: consumerFavoritesTotalItems + 4 }) + ]); + }); + test.beforeEach(async ({ favoritePage }) => { await favoritePage.navigate(); }); @@ -96,14 +120,6 @@ test.describe('Favorites Files', () => { expect(actualColumns).toEqual(expectedColumns); }); - test(`[XAT-4456] Deleted favorite files and folders do not appear in the list`, async ({ favoritePage }) => { - expect(await favoritePage.dataTable.isItemPresent(fileName3), `${fileName3} is displayed`).not.toBe(true); - }); - - test(`[XAT-4457] Favorite files and folders restored from trashcan are displayed in the list`, async ({ favoritePage }) => { - expect(await favoritePage.dataTable.isItemPresent(fileName4), `${fileName4} not displayed`).toBe(true); - }); - test('[XAT-4459] Location column displays the parent folder of the file as link', async ({ favoritePage }) => { expect(await favoritePage.dataTable.getItemLocationText(fileName2)).toEqual(parentFolder); expect(await favoritePage.dataTable.getItemLocationText(favFolderName)).toEqual('Personal Files'); diff --git a/e2e/playwright/list-views/src/tests/personal-files.e2e.ts b/e2e/playwright/list-views/src/tests/personal-files.e2e.ts index d463785c3..98e7ad757 100644 --- a/e2e/playwright/list-views/src/tests/personal-files.e2e.ts +++ b/e2e/playwright/list-views/src/tests/personal-files.e2e.ts @@ -23,11 +23,12 @@ */ import { expect } from '@playwright/test'; -import { APP_ROUTES, ApiClientFactory, NodesApi, SIDEBAR_LABELS, Utils, test, TrashcanApi } from '@alfresco/aca-playwright-shared'; +import { APP_ROUTES, ApiClientFactory, NodesApi, SIDEBAR_LABELS, Utils, test, TrashcanApi, SearchApi } from '@alfresco/aca-playwright-shared'; test.describe('Personal Files', () => { let nodesApi: NodesApi; let trashcanApi: TrashcanApi; + let searchApi: SearchApi; const username = `user-${Utils.random()}`; const userFolder = `user-folder-${Utils.random()}`; @@ -38,6 +39,7 @@ test.describe('Personal Files', () => { await apiClientFactory.createUser({ username }); nodesApi = await NodesApi.initialize(username, username); trashcanApi = await TrashcanApi.initialize(username, username); + searchApi = await SearchApi.initialize(username, username); await nodesApi.createFolder(userFolder); } catch (error) { console.error(`beforeAll failed : ${error}`); @@ -76,5 +78,69 @@ test.describe('Personal Files', () => { await personalFiles.reload(); expect(personalFiles.page.url()).toContain(APP_ROUTES.PERSONAL_FILES); }); + + test('[XAT-4518] Invalid URL', async ({ personalFiles }) => { + await personalFiles.navigate({ remoteUrl: `#/personal-files/nonexistentpage-${Utils.random()}` }); + await expect(personalFiles.dataTable.noPermissionsView).toBeVisible(); + }); + }); + + test.describe(`Folder name abbreviation`, () => { + const abbreviateFolderMain = `XAT-4385-folder-${Utils.random()}`; + const abbreviateFolder2 = `XAT-4385-folder-${Utils.random()}-2`; + const abbreviateFolder3 = `XAT-4385-folder-${Utils.random()}-3`; + const abbreviateFolder4 = `XAT-4385-folder-${Utils.random()}-4`; + const abbreviateFolder5 = `XAT-4385-folder-${Utils.random()}-5`; + + let abbreviateFolder5Id: string; + + test.beforeAll(async () => { + const abbreviateFolderMainId = (await nodesApi.createFolder(abbreviateFolderMain)).entry.id; + const abbreviateFolder2Id = (await nodesApi.createFolder(abbreviateFolder2, abbreviateFolderMainId)).entry.id; + const abbreviateFolder3Id = (await nodesApi.createFolder(abbreviateFolder3, abbreviateFolder2Id)).entry.id; + const abbreviateFolder4Id = (await nodesApi.createFolder(abbreviateFolder4, abbreviateFolder3Id)).entry.id; + abbreviateFolder5Id = (await nodesApi.createFolder(abbreviateFolder5, abbreviateFolder4Id)).entry.id; + }); + + test.beforeEach(async ({ loginPage }) => { + await Utils.tryLoginUser(loginPage, username, username, 'beforeEach failed'); + }); + + test('[XAT-4385] Folder names abbreviate when path is too long to fit the screen', async ({ personalFiles }) => { + await personalFiles.navigate({ remoteUrl: `#/personal-files/${abbreviateFolder5Id}` }); + await personalFiles.breadcrumb.currentItem.waitFor(); + const hasOverflow = await personalFiles.breadcrumb.currentItem.evaluate( + (folderNameElement) => folderNameElement.scrollWidth > folderNameElement.clientWidth + ); + expect(hasOverflow).toBe(true); + }); + }); + + test.describe(`Navigate to parent folder after pagination`, () => { + const abbreviateFolderMain = `XAT-4527-folder-${Utils.random()}`; + const abbreviateFolder2 = `XAT-4527-folder-${Utils.random()}-2`; + + let abbreviateFolder2Id: string; + + test.beforeAll(async () => { + const abbreviateFolderMainId = (await nodesApi.createFolder(abbreviateFolderMain)).entry.id; + abbreviateFolder2Id = (await nodesApi.createFolder(abbreviateFolder2, abbreviateFolderMainId)).entry.id; + await nodesApi.createMultipleFiles(30, abbreviateFolder2Id); + await searchApi.waitForFolderPathIndexing(abbreviateFolder2Id, { nodesExpected: 30 }); + }); + + test.beforeEach(async ({ loginPage }) => { + await Utils.tryLoginUser(loginPage, username, username, 'beforeEach failed'); + }); + + test('[XAT-4527] Should be able to navigate to the parent folder when pagination is set to 25', async ({ personalFiles }) => { + await personalFiles.navigate({ remoteUrl: `#/personal-files/${abbreviateFolder2Id}` }); + await personalFiles.breadcrumb.currentItem.waitFor(); + await personalFiles.pagination.clickOnNextPage(); + expect(await personalFiles.pagination.getCurrentPage()).toBe('Page 2'); + await personalFiles.breadcrumb.clickItem(abbreviateFolderMain); + await personalFiles.spinner.spinnerWaitForReload(); + expect(await personalFiles.pagination.getRange()).toContain('Showing 1-1'); + }); }); }); diff --git a/e2e/playwright/list-views/src/tests/recent-files.e2e.ts b/e2e/playwright/list-views/src/tests/recent-files.e2e.ts index 5360e6bc4..37b50853d 100755 --- a/e2e/playwright/list-views/src/tests/recent-files.e2e.ts +++ b/e2e/playwright/list-views/src/tests/recent-files.e2e.ts @@ -23,7 +23,7 @@ */ import { expect } from '@playwright/test'; -import { ApiClientFactory, NodesApi, SearchPageApi, SitesApi, TrashcanApi, Utils, test, timeouts } from '@alfresco/aca-playwright-shared'; +import { ApiClientFactory, NodesApi, SearchApi, SitesApi, TrashcanApi, Utils, test, timeouts } from '@alfresco/aca-playwright-shared'; import { Site } from '@alfresco/js-api'; test.describe('Recent Files', () => { @@ -69,7 +69,7 @@ test.describe('Recent Files', () => { const folderSiteId = (await nodeActionsUser.createFolder(folderSite, docLibId)).entry.id; await nodeActionsUser.createFile(fileSite, folderSiteId); - const searchApi = await SearchPageApi.initialize(username, username); + const searchApi = await SearchApi.initialize(username, username); await searchApi.waitForApi(username, { expect: 3 }); }); diff --git a/e2e/playwright/special-permissions-actions-available/src/tests/special-permissions-actions.e2e.ts b/e2e/playwright/special-permissions-actions-available/src/tests/special-permissions-actions.e2e.ts index aad84cbf7..9210b3b5f 100644 --- a/e2e/playwright/special-permissions-actions-available/src/tests/special-permissions-actions.e2e.ts +++ b/e2e/playwright/special-permissions-actions-available/src/tests/special-permissions-actions.e2e.ts @@ -34,7 +34,7 @@ import { SitesApi, test, SharedLinksApi, - SearchPageApi, + SearchApi, timeouts, Utils } from '@alfresco/aca-playwright-shared'; @@ -78,7 +78,7 @@ test.describe('Special permissions : ', () => { let consumerShareActions: SharedLinksApi; let managerSiteActions: SitesApi; let managerFileActions: FileActionsApi; - let managerSearchActions: SearchPageApi; + let managerSearchActions: SearchApi; test.beforeAll(async () => { test.setTimeout(timeouts.extendedLongTest); @@ -94,7 +94,7 @@ test.describe('Special permissions : ', () => { collaboratorFavoritesActions = await FavoritesPageApi.initialize(userCollaborator, userCollaborator); demotedUserFavoritesActions = await FavoritesPageApi.initialize(userDemoted, userDemoted); managerFavoritesActions = await FavoritesPageApi.initialize(userManager, userManager); - managerSearchActions = await SearchPageApi.initialize(userManager, userManager); + managerSearchActions = await SearchApi.initialize(userManager, userManager); managerSiteActions = await SitesApi.initialize(userManager, userManager); managerFileActions = await FileActionsApi.initialize(userManager, userManager); managerUserShareActions = await SharedLinksApi.initialize(userManager, userManager); diff --git a/e2e/playwright/viewer-actions/.eslintrc.json b/e2e/playwright/viewer-actions/.eslintrc.json new file mode 100644 index 000000000..2f8356750 --- /dev/null +++ b/e2e/playwright/viewer-actions/.eslintrc.json @@ -0,0 +1,22 @@ +{ + "extends": "../../../.eslintrc.json", + "ignorePatterns": [ + "!**/*" + ], + "overrides": [ + { + "files": [ + "*.ts" + ], + "extends": ["../../../.eslintrc.e2e.json"], + "parserOptions": { + "project": [ + "e2e/playwright/viewer-actions/tsconfig.e2e.json" + ] + }, + "rules": { + "@typescript-eslint/no-floating-promises": "off" + } + } + ] +} diff --git a/e2e/playwright/viewer-actions/exclude.tests.json b/e2e/playwright/viewer-actions/exclude.tests.json new file mode 100644 index 000000000..3395da8bb --- /dev/null +++ b/e2e/playwright/viewer-actions/exclude.tests.json @@ -0,0 +1,9 @@ +{ + "all": {}, + "firefox": { + "XAT-5417": "https://hyland.atlassian.net/browse/ACS-10917" + }, + "webkit": { + "XAT-5417": "https://hyland.atlassian.net/browse/ACS-10917" + } +} diff --git a/e2e/playwright/viewer-actions/playwright.config.ts b/e2e/playwright/viewer-actions/playwright.config.ts new file mode 100644 index 000000000..582b4a095 --- /dev/null +++ b/e2e/playwright/viewer-actions/playwright.config.ts @@ -0,0 +1,36 @@ +/*! + * 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 . + */ + +import { PlaywrightTestConfig } from '@playwright/test'; +import { CustomConfig, getGlobalConfig, getExcludedTestsRegExpArray, createSuiteProjects } from '@alfresco/aca-playwright-shared'; +import EXCLUDED_JSON from './exclude.tests.json'; + +const config: PlaywrightTestConfig = { + ...getGlobalConfig, + + grepInvert: getExcludedTestsRegExpArray(EXCLUDED_JSON, 'Viewer Actions'), + projects: createSuiteProjects('Viewer Actions', './src/tests', { users: ['hruser'] }) +}; + +export default config; diff --git a/e2e/playwright/viewer-actions/project.json b/e2e/playwright/viewer-actions/project.json new file mode 100644 index 000000000..1ac220974 --- /dev/null +++ b/e2e/playwright/viewer-actions/project.json @@ -0,0 +1,31 @@ +{ + "name": "viewer-actions-e2e", + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "e2e/playwright/viewer-actions/src", + "projectType": "application", + "targets": { + "e2e": { + "executor": "nx:run-commands", + "options": { + "commands": ["playwright test --config=e2e/playwright/viewer-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" + } + } +} diff --git a/e2e/playwright/viewer-actions/src/tests/viewer-action.e2e.ts b/e2e/playwright/viewer-actions/src/tests/viewer-action.e2e.ts new file mode 100644 index 000000000..17d3c2188 --- /dev/null +++ b/e2e/playwright/viewer-actions/src/tests/viewer-action.e2e.ts @@ -0,0 +1,546 @@ +/*! + * 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 . + */ + +import { expect } from '@playwright/test'; +import { + ApiClientFactory, + FavoritesPageApi, + FileActionsApi, + NodesApi, + PersonalFilesPage, + SharedLinksApi, + TrashcanApi, + test, + TEST_FILES, + timeouts, + Utils +} from '@alfresco/aca-playwright-shared'; + +async function initializeApis(username: string): Promise<{ nodesApi: NodesApi; trashcanApi: TrashcanApi; fileActionsApi: FileActionsApi }> { + const apiClientFactory = new ApiClientFactory(); + await apiClientFactory.setUpAcaBackend('admin'); + await apiClientFactory.createUser({ username }); + const nodesApi = await NodesApi.initialize(username, username); + const trashcanApi = await TrashcanApi.initialize(username, username); + const fileActionsApi = await FileActionsApi.initialize(username, username); + return { nodesApi, trashcanApi, fileActionsApi }; +} + +async function openFileInViewer(page: PersonalFilesPage, fileName: string): Promise { + await page.dataTable.performClickFolderOrFileToOpen(fileName); + await page.viewer.waitForViewerToOpen(); +} + +async function clickUploadButtonAndWaitForApi(page: PersonalFilesPage): Promise { + await Promise.all([ + Utils.waitForApiResponse(page, 'content', 200), + Utils.waitForApiResponse(page, 'attachment', 200), + page.uploadNewVersionDialog.uploadButton.click() + ]); +} + +async function uploadMajorVersionAndVerify(page: PersonalFilesPage, newVersionName: string, description?: string): Promise { + await Utils.uploadFileNewVersion(page, newVersionName, 'jpg'); + await page.uploadNewVersionDialog.majorOption.click(); + if (description) { + await page.uploadNewVersionDialog.description.fill(description); + } + await clickUploadButtonAndWaitForApi(page); + await page.uploadNewVersionDialog.uploadButton.waitFor({ state: 'detached' }); + await expect(page.uploadNewVersionDialog.cancelButton).toHaveCount(0); + expect(await page.viewer.isViewerOpened(), 'Viewer is not open').toBe(true); + expect(await page.viewer.getFileTitle()).toContain(newVersionName); +} + +async function navigateAndOpenFile(page: PersonalFilesPage, folderId: string, fileName: string): Promise { + await page.navigate({ remoteUrl: `#/personal-files/${folderId}` }); + await openFileInViewer(page, fileName); +} + +async function openManageVersionDialog(page: PersonalFilesPage): Promise { + await page.acaHeader.clickViewerMoreActions(); + await page.matMenu.clickMenuItem('Manage Versions'); + await page.manageVersionsDialog.waitForDialog(); +} + +async function uploadVersionAndOpenHistory(page: PersonalFilesPage, newVersionName: string, description?: string): Promise { + await uploadMajorVersionAndVerify(page, newVersionName, description); + await openManageVersionDialog(page); +} + +test.describe('viewer action file', () => { + test.describe('Personal Files - general viewer actions', () => { + const username = `user-${Utils.random()}`; + const randomDocxName = `${TEST_FILES.DOCX.name}-${Utils.random()}`; + let folderIdActions: string; + let nodesApi: NodesApi; + let trashcanApi: TrashcanApi; + + test.beforeAll(async () => { + try { + const apis = await initializeApis(username); + nodesApi = apis.nodesApi; + const { fileActionsApi } = apis; + trashcanApi = apis.trashcanApi; + folderIdActions = (await nodesApi.createFolder(`viewer-action-5415-5416-5417-${Utils.random()}`)).entry.id; + await fileActionsApi.uploadFile(TEST_FILES.DOCX.path, randomDocxName, folderIdActions); + } catch (error) { + console.error(`beforeAll failed: ${error}`); + throw error; + } + }); + + test.beforeEach(async ({ personalFiles, loginPage }) => { + await Utils.tryLoginUser(loginPage, username, username, 'beforeEach failed'); + await personalFiles.navigate({ remoteUrl: `#/personal-files/${folderIdActions}` }); + }); + + test.afterAll(async () => { + await Utils.deleteNodesSitesEmptyTrashcan(nodesApi, trashcanApi, 'afterAll failed'); + }); + + test('[XAT-5417] Viewer - Download action - Personal Files', async ({ personalFiles }) => { + await openFileInViewer(personalFiles, randomDocxName); + const downloadPromise = personalFiles.page.waitForEvent('download'); + await personalFiles.acaHeader.downloadButtonViewer.click(); + const download = await downloadPromise; + expect(download.suggestedFilename()).toBe(randomDocxName); + }); + + test('[XAT-5415] Full screen action', async ({ personalFiles }) => { + await openFileInViewer(personalFiles, randomDocxName); + await personalFiles.acaHeader.fullScreenButton.click(); + expect(await personalFiles.viewer.isViewerOpened(), 'Viewer is closed after pressing Full screen').toBe(true); + }); + + test('[XAT-5416] Pressing ESC in the viewer closes only the action dialog', async ({ personalFiles }) => { + await openFileInViewer(personalFiles, randomDocxName); + await personalFiles.acaHeader.clickViewerMoreActions(); + await personalFiles.viewerDialog.clickActionsCopy(); + expect(await personalFiles.viewerDialog.isCopyDialogOpen(), 'Dialog is not open').toBe(true); + await personalFiles.page.keyboard.press('Escape'); + expect(await personalFiles.viewerDialog.isCopyDialogClose(), 'Dialog is not open').toBe(false); + expect(await personalFiles.viewer.isViewerOpened(), 'Viewer should be opened').toBe(true); + }); + }); + + test.describe('Personal Files - Delete action', () => { + const username = `user-${Utils.random()}`; + const randomDocxDelete = `${TEST_FILES.DOCX.name}-${Utils.random()}`; + const randomDocxName = `${TEST_FILES.DOCX.name}-${Utils.random()}`; + let folderId: string; + let nodesApi: NodesApi; + let trashcanApi: TrashcanApi; + + test.beforeAll(async () => { + try { + const apis = await initializeApis(username); + trashcanApi = apis.trashcanApi; + const { fileActionsApi } = apis; + nodesApi = apis.nodesApi; + folderId = (await nodesApi.createFolder(`viewer-action-5421-${Utils.random()}`)).entry.id; + await fileActionsApi.uploadFile(TEST_FILES.DOCX.path, randomDocxName, folderId); + await fileActionsApi.uploadFile(TEST_FILES.DOCX.path, randomDocxDelete, folderId); + } catch (error) { + console.error(`beforeAll failed: ${error}`); + throw error; + } + }); + + test.beforeEach(async ({ personalFiles, loginPage }) => { + await Utils.tryLoginUser(loginPage, username, username, 'beforeEach failed'); + await personalFiles.navigate({ remoteUrl: `#/personal-files/${folderId}` }); + }); + + test.afterAll(async () => { + await Utils.deleteNodesSitesEmptyTrashcan(nodesApi, trashcanApi, 'afterAll failed'); + }); + + test('[XAT-5421] Viewer - Delete action - Personal Files', async ({ personalFiles, trashPage }) => { + await openFileInViewer(personalFiles, randomDocxDelete); + await personalFiles.acaHeader.clickViewerMoreActions(); + await personalFiles.viewerDialog.deleteMenuButton.click(); + await personalFiles.snackBar.getByMessageLocator(randomDocxDelete).waitFor({ state: 'attached' }); + const deleteName = await personalFiles.snackBar.getByMessageLocator(randomDocxDelete).innerText(); + expect(deleteName).toContain(`${randomDocxDelete} deleted`); + await personalFiles.dataTable.getCellLinkByName(randomDocxName).waitFor({ state: 'attached' }); + await expect(personalFiles.dataTable.getCellLinkByName(randomDocxDelete), 'file should not visible').toBeHidden(); + await trashPage.navigate({ waitUntil: 'domcontentloaded' }); + expect(await trashPage.dataTable.isItemPresent(randomDocxDelete), 'Item should be present in Trash').toBe(true); + }); + }); + + test.describe('Personal Files - Edit Offline action', () => { + const username = `user-${Utils.random()}`; + const fileForEditOffline = `playwright-file1-${Utils.random()}.docx`; + let folderIdOffline: string; + let nodesApi: NodesApi; + let trashcanApi: TrashcanApi; + + test.beforeAll(async () => { + try { + const apis = await initializeApis(username); + const { fileActionsApi } = apis; + + nodesApi = apis.nodesApi; + trashcanApi = apis.trashcanApi; + folderIdOffline = (await nodesApi.createFolder(`viewer-action-5423-${Utils.random()}`)).entry.id; + await fileActionsApi.uploadFile(TEST_FILES.DOCX.path, fileForEditOffline, folderIdOffline); + } catch (error) { + console.error(`beforeAll failed: ${error}`); + throw error; + } + }); + + test.beforeEach(async ({ personalFiles, loginPage }) => { + await Utils.tryLoginUser(loginPage, username, username, 'beforeEach failed'); + await personalFiles.navigate({ remoteUrl: `#/personal-files/${folderIdOffline}` }); + }); + + test.afterAll(async () => { + await Utils.deleteNodesSitesEmptyTrashcan(nodesApi, trashcanApi, 'afterAll failed'); + }); + + test('[XAT-5423] Viewer - Edit Offline action - Personal Files', async ({ personalFiles }) => { + await openFileInViewer(personalFiles, fileForEditOffline); + await personalFiles.acaHeader.clickViewerMoreActions(); + await personalFiles.matMenu.clickMenuItem('Edit Offline'); + const downloadPromise = personalFiles.page.waitForEvent('download'); + await personalFiles.acaHeader.downloadButtonViewer.click(); + const download = await downloadPromise; + expect(download.suggestedFilename(), 'File should found in download location').toBe(fileForEditOffline); + expect(await personalFiles.viewer.isViewerOpened(), 'Viewer is closed after pressing Full screen').toBe(true); + await personalFiles.acaHeader.clickViewerMoreActions(); + expect(await personalFiles.matMenu.isMenuItemVisible('Cancel Editing'), 'Cancel Editing menu should be visible').toBe(true); + }); + }); + + test.describe('Personal Files - Cancel Editing action', () => { + const username = `user-${Utils.random()}`; + const fileForCancelEditing = `playwright-file2-${Utils.random()}.docx`; + let folderIdCancelEdit: string; + let nodesApi: NodesApi; + let trashcanApi: TrashcanApi; + + test.beforeAll(async () => { + try { + const apis = await initializeApis(username); + nodesApi = apis.nodesApi; + trashcanApi = apis.trashcanApi; + + const { fileActionsApi } = apis; + folderIdCancelEdit = (await nodesApi.createFolder(`viewer-action-5424-${Utils.random()}`)).entry.id; + const fileForCancelEditingId = (await fileActionsApi.uploadFile(TEST_FILES.DOCX.path, fileForCancelEditing, folderIdCancelEdit)).entry.id; + await fileActionsApi.lockNodes([fileForCancelEditingId]); + await fileActionsApi.isFileLockedWriteWithRetry(fileForCancelEditingId, true); + } catch (error) { + console.error(`beforeAll failed: ${error}`); + throw error; + } + }); + + test.beforeEach(async ({ personalFiles, loginPage }) => { + await Utils.tryLoginUser(loginPage, username, username, 'beforeEach failed'); + await personalFiles.navigate({ remoteUrl: `#/personal-files/${folderIdCancelEdit}` }); + }); + + test.afterAll(async () => { + await Utils.deleteNodesSitesEmptyTrashcan(nodesApi, trashcanApi, 'afterAll failed'); + }); + + test('[XAT-5424] Viewer - Cancel Editing action - Personal Files', async ({ personalFiles }) => { + await openFileInViewer(personalFiles, fileForCancelEditing); + await personalFiles.acaHeader.clickViewerMoreActions(); + await personalFiles.matMenu.clickMenuItem('Cancel Editing'); + await personalFiles.acaHeader.clickViewerMoreActions(); + expect(await personalFiles.matMenu.isMenuItemVisible('Edit Offline'), 'Edit offline menu should be visible').toBe(true); + }); + }); + + test.describe('Personal Files - Upload new version', () => { + const username = `user-${Utils.random()}`; + const file5465 = `file-5465-${Utils.random()}.jpg`; + const file5465NewVersion = TEST_FILES.JPG_FILE.name; + const file5713 = `file-5713-${Utils.random()}.jpg`; + const file5713NewVersion = TEST_FILES.JPG_FILE.name; + const file5714 = `file-5714-${Utils.random()}.jpg`; + const file5714NewVersion = TEST_FILES.JPG_FILE.name; + const file17781 = `file-17781-${Utils.random()}.jpg`; + const file17781NewVersion = TEST_FILES.JPG_FILE.name; + const file5717 = `file-5717-${Utils.random()}.jpg`; + const file5717NewVersion = TEST_FILES.JPG_FILE.name; + const file5720 = `file-5720-${Utils.random()}.jpg`; + const file5720NewVersion = TEST_FILES.JPG_FILE.name; + let file5465Id: string; + let file17781Id: string; + let folder5465Id: string; + let folder5713Id: string; + let folder5714Id: string; + let folder5717Id: string; + let folder17781Id: string; + let folder5720Id: string; + let nodesApi: NodesApi; + let trashcanApi: TrashcanApi; + + test.beforeAll(async () => { + try { + const apis = await initializeApis(username); + nodesApi = apis.nodesApi; + trashcanApi = apis.trashcanApi; + const { fileActionsApi } = apis; + folder5465Id = (await nodesApi.createFolder(`viewer-action-5465-${Utils.random()}`)).entry.id; + folder17781Id = (await nodesApi.createFolder(`viewer-action-17781-${Utils.random()}`)).entry.id; + folder5713Id = (await nodesApi.createFolder(`viewer-action-5713-${Utils.random()}`)).entry.id; + folder5714Id = (await nodesApi.createFolder(`viewer-action-5714-${Utils.random()}`)).entry.id; + folder5717Id = (await nodesApi.createFolder(`viewer-action-5717-${Utils.random()}`)).entry.id; + folder5720Id = (await nodesApi.createFolder(`viewer-action-5720-${Utils.random()}`)).entry.id; + file5465Id = (await fileActionsApi.uploadFile(TEST_FILES.JPG_FILE.path, file5465, folder5465Id)).entry.id; + file17781Id = (await fileActionsApi.uploadFileWithRename(TEST_FILES.JPG_FILE.path, file17781, folder17781Id)).entry.id; + await fileActionsApi.uploadFileWithRename(TEST_FILES.JPG_FILE.path, file5713, folder5713Id); + await fileActionsApi.uploadFileWithRename(TEST_FILES.JPG_FILE.path, file5714, folder5714Id); + await fileActionsApi.uploadFileWithRename(TEST_FILES.JPG_FILE.path, file5717, folder5717Id); + await fileActionsApi.uploadFileWithRename(TEST_FILES.JPG_FILE.path, file5720, folder5720Id); + await fileActionsApi.lockNodes([file17781Id]); + } catch (error) { + console.error(`beforeAll failed: ${error}`); + throw error; + } + }); + + test.beforeEach(async ({ loginPage }) => { + await Utils.tryLoginUser(loginPage, username, username, 'beforeEach failed'); + }); + + test.afterAll(async () => { + await Utils.deleteNodesSitesEmptyTrashcan(nodesApi, trashcanApi, 'afterAll failed'); + }); + + test('[XAT-5465] Upload new version action - major', async ({ personalFiles, nodesApiAction }) => { + await navigateAndOpenFile(personalFiles, folder5465Id, file5465); + await uploadMajorVersionAndVerify(personalFiles, file5465NewVersion, 'new major version description'); + expect(await nodesApiAction.getNodeProperty(file5465Id, 'cm:versionType'), 'File has incorrect version type').toEqual('MAJOR'); + expect(await nodesApiAction.getNodeProperty(file5465Id, 'cm:versionLabel'), 'File has incorrect version label').toEqual('2.0'); + }); + + test('[XAT-17781] Upload new version action when node is locked', async ({ personalFiles }) => { + await navigateAndOpenFile(personalFiles, folder17781Id, file17781); + await Utils.uploadFileNewVersion(personalFiles, file17781NewVersion, 'jpg'); + await clickUploadButtonAndWaitForApi(personalFiles); + await personalFiles.uploadNewVersionDialog.uploadButton.waitFor({ state: 'detached' }); + expect(await personalFiles.viewer.isViewerOpened(), 'Viewer is not open').toBe(true); + expect(await personalFiles.viewer.getFileTitle()).toContain(file17781NewVersion); + await personalFiles.acaHeader.clickViewerMoreActions(); + await expect(personalFiles.matMenu.getMenuItemFromHeaderMenu('Cancel Editing'), `'Cancel Editing' button shouldn't be shown`).toBeHidden(); + await expect(personalFiles.matMenu.getMenuItemFromHeaderMenu('Edit Offline'), `'Edit Offline' should be shown`).toBeVisible(); + }); + + test('[XAT-5713] Viewer: User can download a previous version of a file', async ({ personalFiles }) => { + await navigateAndOpenFile(personalFiles, folder5713Id, file5713); + await uploadVersionAndOpenHistory(personalFiles, file5713NewVersion); + await personalFiles.manageVersionsDialog.clickListActionButtonForVersion('1.0'); + const [download] = await Promise.all([personalFiles.page.waitForEvent('download'), personalFiles.matMenu.clickMenuItem('Download')]); + expect(download.suggestedFilename()).toBe(file5713); + }); + + test('[XAT-5714] Viewer: User can restore the current version of a file to a previous version with permissions', async ({ personalFiles }) => { + await navigateAndOpenFile(personalFiles, folder5714Id, file5714); + await Utils.uploadFileNewVersion(personalFiles, file5714NewVersion, 'jpg'); + await clickUploadButtonAndWaitForApi(personalFiles); + await openManageVersionDialog(personalFiles); + await personalFiles.manageVersionsDialog.clickListActionButtonForVersion('1.0'); + await Promise.all([Utils.waitForApiResponse(personalFiles, 'revert', 200), personalFiles.matMenu.clickMenuItem('Restore')]); + await personalFiles.manageVersionsDialog.waitForProgressBarToDisappear(); + expect(await personalFiles.manageVersionsDialog.isVersionPresent('2.0')).toBe(true); + }); + + test('[XAT-5717] Viewer: User can delete a version of a file with permissions', async ({ personalFiles }) => { + await navigateAndOpenFile(personalFiles, folder5717Id, file5717); + await Promise.all([ + Utils.waitForApiResponse(personalFiles, 'content', 200), + Utils.waitForApiResponse(personalFiles, 'attachment', 200), + uploadMajorVersionAndVerify(personalFiles, file5717NewVersion) + ]); + await openManageVersionDialog(personalFiles); + await personalFiles.manageVersionsDialog.clickListActionButtonForVersion('1.0'); + await personalFiles.matMenu.clickMenuItem('Delete'); + await Promise.all([ + personalFiles.page.waitForResponse((response) => response.url().includes('1.0') && response.status() === 204), + personalFiles.confirmDialog.okButton.click() + ]); + await personalFiles.manageVersionsDialog.waitForProgressBarToDisappear(); + expect(await personalFiles.manageVersionsDialog.isVersionPresent('2.0')).toBe(true); + expect(await personalFiles.manageVersionsDialog.isVersionPresent('1.0')).toBe(false); + }); + + test('[XAT-5720] Viewer: User can write comments when user is uploading a new version for a file', async ({ personalFiles }) => { + await navigateAndOpenFile(personalFiles, folder5720Id, file5720); + await uploadVersionAndOpenHistory(personalFiles, file5720NewVersion, 'version with comment'); + await personalFiles.manageVersionsDialog.clickListActionButtonForVersion('1.0'); + expect(await personalFiles.manageVersionsDialog.isDescriptionPresent('2.0')).toBe(true); + }); + }); + + test.describe('Shared Files - Favorite action', () => { + const username = `user-${Utils.random()}`; + const randomDocxNameShare = `${TEST_FILES.DOCX.name}-${Utils.random()}`; + let folderId: string; + let nodesApi: NodesApi; + let trashcanApi: TrashcanApi; + + test.beforeAll(async () => { + try { + const apis = await initializeApis(username); + nodesApi = apis.nodesApi; + trashcanApi = apis.trashcanApi; + const { fileActionsApi } = apis; + const shareActions = await SharedLinksApi.initialize(username, username); + folderId = (await nodesApi.createFolder(`viewer-action-5442-${Utils.random()}`)).entry.id; + const fileDocxShareId = (await fileActionsApi.uploadFile(TEST_FILES.DOCX.path, randomDocxNameShare, folderId)).entry.id; + await shareActions.shareFileById(fileDocxShareId); + } catch (error) { + console.error(`beforeAll failed: ${error}`); + throw error; + } + }); + + test.beforeEach(async ({ loginPage }) => { + await Utils.tryLoginUser(loginPage, username, username, 'beforeEach failed'); + }); + + test.afterAll(async () => { + await Utils.deleteNodesSitesEmptyTrashcan(nodesApi, trashcanApi, 'afterAll failed'); + }); + + test('[XAT-5442] Favorite action from Shared Files', async ({ sharedPage, favoritePage }) => { + await sharedPage.navigate({ waitUntil: 'domcontentloaded' }); + await sharedPage.dataTable.performClickFolderOrFileToOpen(randomDocxNameShare); + expect(await sharedPage.viewer.isViewerOpened(), 'Viewer should be opened').toBe(true); + await sharedPage.acaHeader.clickViewerMoreActions(); + await favoritePage.viewerDialog.favoriteMenuButton.waitFor({ state: 'attached', timeout: timeouts.normal }); + await sharedPage.viewerDialog.favoriteMenuButton.click(); + await favoritePage.viewerDialog.favoriteMenuButton.waitFor({ state: 'detached', timeout: timeouts.normal }); + await sharedPage.acaHeader.clickViewerMoreActions(); + await favoritePage.viewerDialog.removeFavoriteMenuButton.waitFor({ state: 'attached', timeout: timeouts.normal }); + await expect(sharedPage.viewerDialog.removeFavoriteMenuButton, 'Item should be remove favorite').toBeVisible(); + await sharedPage.page.keyboard.press('Escape'); + await favoritePage.navigate({ waitUntil: 'domcontentloaded' }); + expect(await favoritePage.dataTable.isItemPresent(randomDocxNameShare), 'Item is not present in Favorites list').toBe(true); + }); + }); + + test.describe('Favorites - Share action', () => { + const username = `user-${Utils.random()}`; + const randomDocxNameFavorite = `${TEST_FILES.DOCX.name}-${Utils.random()}`; + let folderId: string; + let nodesApi: NodesApi; + let trashcanApi: TrashcanApi; + + test.beforeAll(async () => { + try { + const apis = await initializeApis(username); + nodesApi = apis.nodesApi; + trashcanApi = apis.trashcanApi; + const { fileActionsApi } = apis; + const favoritesActions = await FavoritesPageApi.initialize(username, username); + folderId = (await nodesApi.createFolder(`viewer-action-5462-${Utils.random()}`)).entry.id; + const randomDocxNameFavoriteId = (await fileActionsApi.uploadFile(TEST_FILES.DOCX.path, randomDocxNameFavorite, folderId)).entry.id; + await favoritesActions.addFavoriteById('file', randomDocxNameFavoriteId); + await favoritesActions.isFavoriteWithRetry(username, randomDocxNameFavoriteId, { expect: true }); + } catch (error) { + console.error(`beforeAll failed: ${error}`); + throw error; + } + }); + + test.beforeEach(async ({ loginPage }) => { + await Utils.tryLoginUser(loginPage, username, username, 'beforeEach failed'); + }); + + test.afterAll(async () => { + await Utils.deleteNodesSitesEmptyTrashcan(nodesApi, trashcanApi, 'afterAll failed'); + }); + + test('[XAT-5462] Share action from Favorites', async ({ favoritePage }) => { + await favoritePage.navigate({ waitUntil: 'domcontentloaded' }); + await favoritePage.dataTable.performClickFolderOrFileToOpen(randomDocxNameFavorite); + expect(await favoritePage.viewer.isViewerOpened(), 'Viewer should be opened').toBe(true); + await favoritePage.viewer.shareButton.waitFor({ state: 'attached', timeout: timeouts.normal }); + await favoritePage.viewer.shareButton.click(); + await favoritePage.viewerDialog.shareDialogTitle.waitFor({ state: 'attached', timeout: timeouts.normal }); + await expect(favoritePage.viewerDialog.shareDialogTitle, 'Share dialog should be open').toBeVisible(); + await favoritePage.viewerDialog.shareDialogClose.click(); + await favoritePage.viewerDialog.shareDialogClose.waitFor({ state: 'detached', timeout: timeouts.large }); + await expect(favoritePage.viewerDialog.shareDialogTitle, 'Share dialog should be open').toBeHidden(); + }); + }); + + test.describe('Recent Files - Copy action', () => { + const username = `user-${Utils.random()}`; + const docxRecentFiles = `docxRF-${Utils.random()}.docx`; + const destination = `viewer-action-destRF-${Utils.random()}`; + let folderId: string; + let destinationId: string; + let nodesApi: NodesApi; + let trashcanApi: TrashcanApi; + + test.beforeAll(async () => { + try { + const apis = await initializeApis(username); + nodesApi = apis.nodesApi; + trashcanApi = apis.trashcanApi; + const { fileActionsApi } = apis; + folderId = (await nodesApi.createFolder(`viewer-action-5448-${Utils.random()}`)).entry.id; + destinationId = (await nodesApi.createFolder(destination)).entry.id; + await fileActionsApi.uploadFileWithRename(TEST_FILES.DOCX.path, docxRecentFiles, folderId); + } catch (error) { + console.error(`beforeAll failed: ${error}`); + throw error; + } + }); + + test.beforeEach(async ({ loginPage }) => { + await Utils.tryLoginUser(loginPage, username, username, 'beforeEach failed'); + }); + + test.afterAll(async () => { + await Utils.deleteNodesSitesEmptyTrashcan(nodesApi, trashcanApi, 'afterAll failed'); + }); + + test('[XAT-5448] Copy action from Recent Files', async ({ recentFilesPage, personalFiles }) => { + await recentFilesPage.navigate(); + await recentFilesPage.dataTable.performClickFolderOrFileToOpen(docxRecentFiles); + expect(await recentFilesPage.viewer.isViewerOpened(), 'Viewer is not opened').toBe(true); + await recentFilesPage.acaHeader.clickViewerMoreActions(); + await recentFilesPage.matMenu.clickMenuItem('Copy'); + await expect(recentFilesPage.contentNodeSelector.actionButton, 'Dialog is not open').toBeVisible(); + await recentFilesPage.contentNodeSelector.selectLocation('Personal Files'); + await recentFilesPage.contentNodeSelector.selectDestination(destination); + await recentFilesPage.contentNodeSelector.actionButton.click(); + expect(await recentFilesPage.snackBar.message.innerText()).toContain('Copied 1 item'); + await recentFilesPage.viewer.closeButtonLocator.click(); + await personalFiles.navigate({ remoteUrl: `#/personal-files/${destinationId}` }); + expect(await personalFiles.dataTable.isItemPresent(docxRecentFiles), 'Item is not present in destination').toBe(true); + }); + }); +}); diff --git a/e2e/playwright/viewer-actions/tsconfig.e2e.adf.json b/e2e/playwright/viewer-actions/tsconfig.e2e.adf.json new file mode 100644 index 000000000..47ea883b4 --- /dev/null +++ b/e2e/playwright/viewer-actions/tsconfig.e2e.adf.json @@ -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"] +} diff --git a/e2e/playwright/viewer-actions/tsconfig.e2e.json b/e2e/playwright/viewer-actions/tsconfig.e2e.json new file mode 100644 index 000000000..16d87d8ec --- /dev/null +++ b/e2e/playwright/viewer-actions/tsconfig.e2e.json @@ -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"] +} diff --git a/e2e/playwright/viewer/exclude.tests.json b/e2e/playwright/viewer/exclude.tests.json index f15998d7f..dc10659bc 100644 --- a/e2e/playwright/viewer/exclude.tests.json +++ b/e2e/playwright/viewer/exclude.tests.json @@ -2,15 +2,12 @@ "all": { "XAT-5501": "https://hyland.atlassian.net/browse/ACS-9889", "XAT-5499": "https://hyland.atlassian.net/browse/ACS-9889", - "XAT-5465": "https://hyland.atlassian.net/browse/ACS-9889", - "XAT-17781": "https://hyland.atlassian.net/browse/ACS-9889", "XAT-17181": "https://hyland.atlassian.net/browse/ACS-9889", "XAT-17640": "https://hyland.atlassian.net/browse/ACS-9889", "XAT-17644": "https://hyland.atlassian.net/browse/ACS-9889", "XAT-17182": "https://hyland.atlassian.net/browse/ACS-9889" }, "firefox": { - "XAT-5417": "https://hyland.atlassian.net/browse/ACS-10917", "XAT-17177": "https://hyland.atlassian.net/browse/ACS-10917", "XAT-17178": "https://hyland.atlassian.net/browse/ACS-10917", "XAT-17179": "https://hyland.atlassian.net/browse/ACS-10917", @@ -26,7 +23,6 @@ "XAT-5510": "https://hyland.atlassian.net/browse/ACS-10917" }, "webkit": { - "XAT-5417": "https://hyland.atlassian.net/browse/ACS-10917", "XAT-17177": "https://hyland.atlassian.net/browse/ACS-10917", "XAT-17178": "https://hyland.atlassian.net/browse/ACS-10917", "XAT-17179": "https://hyland.atlassian.net/browse/ACS-10917", diff --git a/e2e/playwright/viewer/src/tests/viewer-action.e2e.ts b/e2e/playwright/viewer/src/tests/viewer-action.e2e.ts deleted file mode 100644 index cea76d5a6..000000000 --- a/e2e/playwright/viewer/src/tests/viewer-action.e2e.ts +++ /dev/null @@ -1,237 +0,0 @@ -/*! - * 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 . - */ - -import { expect } from '@playwright/test'; -import { ApiClientFactory, getUserState, test, TEST_FILES, timeouts, Utils } from '@alfresco/aca-playwright-shared'; - -test.use({ storageState: getUserState('hruser') }); - -test.describe('viewer action file', () => { - const apiClientFactory = new ApiClientFactory(); - const randomFolderName = `viewer-action-${Utils.random()}`; - const randomDocxName = `${TEST_FILES.DOCX.name}-${Utils.random()}`; - const randomDocxNameFavorite = `${TEST_FILES.DOCX.name}-${Utils.random()}`; - const randomDocxNameShare = `${TEST_FILES.DOCX.name}-${Utils.random()}`; - const randomDocxDelete = `${TEST_FILES.DOCX.name}-${Utils.random()}`; - const fileForEditOffline = `playwright-file1-${Utils.random()}.docx`; - const fileForCancelEditing = `playwright-file2-${Utils.random()}.docx`; - let folderId: string; - let fileDocxShareId: string; - let randomDocxNameFavoriteId: string; - let fileForCancelEditingId: string; - const filePersonalFiles = `file3-${Utils.random()}.jpg`; - let filePersonalFilesId: string; - const filePersonalFiles2 = TEST_FILES.JPG_FILE.name; - const fileNewVersionLocked = `file4-${Utils.random()}.jpg`; - const fileNewVersionLocked2 = TEST_FILES.JPG_FILE.name; - let fileNewVersionLockedId: string; - const destination = `viewer-action-destRF-${Utils.random()}`; - let destinationId: string; - const docxRecentFiles = `docxRF-${Utils.random()}.docx`; - - test.beforeAll(async ({ fileAction, favoritesPageAction, shareAction }) => { - await apiClientFactory.setUpAcaBackend('hruser'); - const node = await apiClientFactory.nodes.createNode('-my-', { name: randomFolderName, nodeType: 'cm:folder', relativePath: '/' }); - destinationId = (await apiClientFactory.nodes.createNode('-my-', { name: destination, nodeType: 'cm:folder', relativePath: '/' })).entry.id; - folderId = node.entry.id; - - fileDocxShareId = (await fileAction.uploadFile(TEST_FILES.DOCX.path, randomDocxNameShare, folderId)).entry.id; - filePersonalFilesId = (await fileAction.uploadFile(TEST_FILES.JPG_FILE.path, filePersonalFiles, folderId)).entry.id; - fileNewVersionLockedId = (await fileAction.uploadFileWithRename(TEST_FILES.JPG_FILE.path, fileNewVersionLocked, folderId)).entry.id; - await fileAction.uploadFileWithRename(TEST_FILES.DOCX.path, docxRecentFiles, folderId); - await shareAction.shareFileById(fileDocxShareId); - fileForCancelEditingId = (await fileAction.uploadFile(TEST_FILES.DOCX.path, fileForCancelEditing, folderId)).entry.id; - await fileAction.lockNodes([fileForCancelEditingId, fileNewVersionLockedId]); - await fileAction.uploadFile(TEST_FILES.DOCX.path, randomDocxName, folderId); - await fileAction.uploadFile(TEST_FILES.DOCX.path, randomDocxDelete, folderId); - const fileFavoritesNode = await fileAction.uploadFile(TEST_FILES.DOCX.path, randomDocxNameFavorite, folderId); - randomDocxNameFavoriteId = fileFavoritesNode.entry.id; - await fileAction.uploadFile(TEST_FILES.DOCX.path, fileForEditOffline, folderId); - await favoritesPageAction.addFavoriteById('file', randomDocxNameFavoriteId); - await favoritesPageAction.isFavoriteWithRetry('hruser', randomDocxNameFavoriteId, { expect: true }); - await fileAction.isFileLockedWriteWithRetry(fileForCancelEditingId, true); - }); - - test.beforeEach(async ({ personalFiles }) => { - await personalFiles.navigate({ remoteUrl: `#/personal-files/${folderId}` }); - }); - - test.afterAll(async () => { - await apiClientFactory.nodes.deleteNode(folderId, { permanent: true }); - await apiClientFactory.nodes.deleteNode(destinationId, { permanent: true }); - }); - - test('[XAT-5417] Viewer - Download action - Personal Files', async ({ personalFiles }) => { - await personalFiles.dataTable.performClickFolderOrFileToOpen(randomDocxName); - await personalFiles.viewer.waitForViewerToOpen(); - const downloadPromise = personalFiles.page.waitForEvent('download'); - await personalFiles.acaHeader.downloadButtonViewer.click(); - const download = await downloadPromise; - expect(download.suggestedFilename()).toBe(randomDocxName); - }); - - test('[XAT-5421] Viewer - Delete action - Personal Files', async ({ personalFiles, trashPage }) => { - await personalFiles.dataTable.performClickFolderOrFileToOpen(randomDocxDelete); - await personalFiles.viewer.waitForViewerToOpen(); - - await personalFiles.acaHeader.clickViewerMoreActions(); - await personalFiles.viewerDialog.deleteMenuButton.click(); - await personalFiles.snackBar.getByMessageLocator(randomDocxDelete).waitFor({ state: 'attached' }); - const deleteName = await personalFiles.snackBar.getByMessageLocator(randomDocxDelete).innerText(); - expect(deleteName).toContain(`${randomDocxDelete} deleted`); - await personalFiles.dataTable.getCellLinkByName(randomDocxName).waitFor({ state: 'attached' }); - await expect(personalFiles.dataTable.getCellLinkByName(randomDocxDelete), 'file should not visible').toBeHidden(); - await trashPage.navigate({ waitUntil: 'domcontentloaded' }); - expect(await trashPage.dataTable.isItemPresent(randomDocxDelete), 'Item should be present in Trash').toBe(true); - }); - - test('[XAT-5423] Viewer - Edit Offline action - Personal Files', async ({ personalFiles }) => { - await personalFiles.dataTable.performClickFolderOrFileToOpen(fileForEditOffline); - await personalFiles.viewer.waitForViewerToOpen(); - await personalFiles.acaHeader.clickViewerMoreActions(); - await personalFiles.matMenu.clickMenuItem('Edit Offline'); - - const downloadPromise = personalFiles.page.waitForEvent('download'); - await personalFiles.acaHeader.downloadButtonViewer.click(); - const download = await downloadPromise; - expect(download.suggestedFilename(), 'File should found in download location').toBe(fileForEditOffline); - expect(await personalFiles.viewer.isViewerOpened(), 'Viewer is closed after pressing Full screen').toBe(true); - await personalFiles.acaHeader.clickViewerMoreActions(); - expect(await personalFiles.matMenu.isMenuItemVisible('Cancel Editing'), 'Cancel Editing menu should be visible').toBe(true); - }); - - test('[XAT-5424] Viewer - Cancel Editing action - Personal Files', async ({ personalFiles }) => { - await personalFiles.dataTable.performClickFolderOrFileToOpen(fileForCancelEditing); - await personalFiles.viewer.waitForViewerToOpen(); - await personalFiles.acaHeader.clickViewerMoreActions(); - await personalFiles.matMenu.clickMenuItem('Cancel Editing'); - await personalFiles.acaHeader.clickViewerMoreActions(); - expect(await personalFiles.matMenu.isMenuItemVisible('Edit Offline'), 'Edit offline menu should be visible').toBe(true); - }); - - test('[XAT-5415] Full screen action', async ({ personalFiles }) => { - await personalFiles.dataTable.performClickFolderOrFileToOpen(randomDocxName); - await personalFiles.viewer.waitForViewerToOpen(); - await personalFiles.acaHeader.fullScreenButton.click(); - expect(await personalFiles.viewer.isViewerOpened(), 'Viewer is closed after pressing Full screen').toBe(true); - }); - - test('[XAT-5416] Pressing ESC in the viewer closes only the action dialog', async ({ personalFiles }) => { - await personalFiles.dataTable.performClickFolderOrFileToOpen(randomDocxName); - await personalFiles.viewer.waitForViewerToOpen(); - await personalFiles.acaHeader.clickViewerMoreActions(); - await personalFiles.viewerDialog.clickActionsCopy(); - expect(await personalFiles.viewerDialog.isCopyDialogOpen(), 'Dialog is not open').toBe(true); - await personalFiles.page.keyboard.press('Escape'); - expect(await personalFiles.viewerDialog.isCopyDialogClose(), 'Dialog is not open').toBe(false); - expect(await personalFiles.viewer.isViewerOpened(), 'Viewer should be opened').toBe(true); - }); - - test('[XAT-5442] Favorite action from Shared Files', async ({ sharedPage, favoritePage }) => { - await sharedPage.navigate({ waitUntil: 'domcontentloaded' }); - await sharedPage.dataTable.performClickFolderOrFileToOpen(randomDocxNameShare); - expect(await sharedPage.viewer.isViewerOpened(), 'Viewer should be opened').toBe(true); - - await sharedPage.acaHeader.clickViewerMoreActions(); - - await favoritePage.viewerDialog.favoriteMenuButton.waitFor({ state: 'attached', timeout: timeouts.normal }); - await sharedPage.viewerDialog.favoriteMenuButton.click(); - await favoritePage.viewerDialog.favoriteMenuButton.waitFor({ state: 'detached', timeout: timeouts.normal }); - - await sharedPage.acaHeader.clickViewerMoreActions(); - await favoritePage.viewerDialog.removeFavoriteMenuButton.waitFor({ state: 'attached', timeout: timeouts.normal }); - await expect(sharedPage.viewerDialog.removeFavoriteMenuButton, 'Item should be remove favorite').toBeVisible(); - await sharedPage.page.keyboard.press('Escape'); - await favoritePage.navigate({ waitUntil: 'domcontentloaded' }); - expect(await favoritePage.dataTable.isItemPresent(randomDocxNameShare), 'Item is not present in Favorites list').toBe(true); - }); - - test('[XAT-5462] Share action from Favorites', async ({ favoritePage }) => { - await favoritePage.navigate({ waitUntil: 'domcontentloaded' }); - await favoritePage.dataTable.performClickFolderOrFileToOpen(randomDocxNameFavorite); - expect(await favoritePage.viewer.isViewerOpened(), 'Viewer should be opened').toBe(true); - await favoritePage.viewer.shareButton.waitFor({ state: 'attached', timeout: timeouts.normal }); - await favoritePage.viewer.shareButton.click(); - await favoritePage.viewerDialog.shareDialogTitle.waitFor({ state: 'attached', timeout: timeouts.normal }); - await expect(favoritePage.viewerDialog.shareDialogTitle, 'Share dialog should be open').toBeVisible(); - await favoritePage.viewerDialog.shareDialogClose.click(); - await favoritePage.viewerDialog.shareDialogClose.waitFor({ state: 'detached', timeout: timeouts.large }); - await expect(favoritePage.viewerDialog.shareDialogTitle, 'Share dialog should be open').toBeHidden(); - }); - - test('[XAT-5465] Upload new version action - major', async ({ personalFiles, nodesApiAction }) => { - await personalFiles.dataTable.performClickFolderOrFileToOpen(filePersonalFiles); - await personalFiles.viewer.waitForViewerToOpen('wait for viewer content'); - - await Utils.uploadFileNewVersion(personalFiles, filePersonalFiles2, 'jpg'); - - await personalFiles.uploadNewVersionDialog.majorOption.click(); - await personalFiles.uploadNewVersionDialog.description.fill('new major version description'); - await personalFiles.uploadNewVersionDialog.uploadButton.click(); - await personalFiles.uploadNewVersionDialog.uploadButton.waitFor({ state: 'detached' }); - await expect(personalFiles.uploadNewVersionDialog.cancelButton).toHaveCount(0); - expect(await personalFiles.viewer.isViewerOpened(), 'Viewer is not open').toBe(true); - await Utils.waitForApiResponse(personalFiles, 'content', 200); - - expect(await personalFiles.viewer.getFileTitle()).toContain(filePersonalFiles2); - expect(await nodesApiAction.getNodeProperty(filePersonalFilesId, 'cm:versionType'), 'File has incorrect version type').toEqual('MAJOR'); - expect(await nodesApiAction.getNodeProperty(filePersonalFilesId, 'cm:versionLabel'), 'File has incorrect version label').toEqual('2.0'); - }); - - test('[XAT-17781] Upload new version action when node is locked', async ({ personalFiles }) => { - await personalFiles.dataTable.performClickFolderOrFileToOpen(fileNewVersionLocked); - await personalFiles.viewer.waitForViewerToOpen('wait for viewer content'); - - await Utils.uploadFileNewVersion(personalFiles, fileNewVersionLocked2, 'jpg'); - - await personalFiles.uploadNewVersionDialog.uploadButton.click(); - await personalFiles.uploadNewVersionDialog.uploadButton.waitFor({ state: 'detached' }); - await expect(personalFiles.uploadNewVersionDialog.cancelButton).toHaveCount(0); - - await personalFiles.viewer.waitForViewerToOpen(); - await Utils.waitForApiResponse(personalFiles, 'content', 200); - expect(await personalFiles.viewer.getFileTitle()).toContain(fileNewVersionLocked2); - - await personalFiles.acaHeader.clickViewerMoreActions(); - await expect(personalFiles.matMenu.getMenuItemFromHeaderMenu('Cancel Editing'), `'Cancel Editing' button shouldn't be shown`).toBeHidden(); - await expect(personalFiles.matMenu.getMenuItemFromHeaderMenu('Edit Offline'), `'Edit Offline' should be shown`).toBeVisible(); - }); - - test('[XAT-5448] Copy action from Recent Files', async ({ recentFilesPage, personalFiles }) => { - await recentFilesPage.navigate(); - await recentFilesPage.dataTable.performClickFolderOrFileToOpen(docxRecentFiles); - expect(await recentFilesPage.viewer.isViewerOpened(), 'Viewer is not opened').toBe(true); - - await recentFilesPage.acaHeader.clickViewerMoreActions(); - await recentFilesPage.matMenu.clickMenuItem('Copy'); - await expect(recentFilesPage.contentNodeSelector.actionButton, 'Dialog is not open').toBeVisible(); - await recentFilesPage.contentNodeSelector.selectLocation('Personal Files'); - await recentFilesPage.contentNodeSelector.selectDestination(destination); - await recentFilesPage.contentNodeSelector.actionButton.click(); - expect(await recentFilesPage.snackBar.message.innerText()).toContain('Copied 1 item'); - await recentFilesPage.viewer.closeButtonLocator.click(); - await personalFiles.navigate({ remoteUrl: `#/personal-files/${destinationId}` }); - expect(await personalFiles.dataTable.isItemPresent(docxRecentFiles), 'Item is not present in destination').toBe(true); - }); -}); diff --git a/e2e/playwright/viewer/src/tests/viewer-protected.e2e.ts b/e2e/playwright/viewer/src/tests/viewer-protected.e2e.ts index 24b4133ad..5f7c4aa16 100644 --- a/e2e/playwright/viewer/src/tests/viewer-protected.e2e.ts +++ b/e2e/playwright/viewer/src/tests/viewer-protected.e2e.ts @@ -81,9 +81,10 @@ test.describe('viewer file', () => { }); test('[XAT-5470] Refresh the page while Password dialog is open', async ({ personalFiles }) => { + await personalFiles.viewer.viewerLocator.waitFor({ state: 'visible' }); await personalFiles.passwordDialog.enterPassword(TEST_FILES.PDF_PROTECTED.password); - await personalFiles.reload({ waitUntil: 'domcontentloaded' }); - await personalFiles.viewer.waitForViewerToOpen(); + + await personalFiles.page.waitForLoadState('networkidle'); expect(await personalFiles.viewer.isPdfViewerContentDisplayed(), 'file content is displayed').toBe(false); expect(await personalFiles.passwordDialog.isDialogOpen(), 'Password dialog not open').toBe(true); diff --git a/e2e/playwright/viewer/src/tests/viewer-version-actions.e2e.ts b/e2e/playwright/viewer/src/tests/viewer-version-actions.e2e.ts index 708f8d9cb..6b074dab5 100644 --- a/e2e/playwright/viewer/src/tests/viewer-version-actions.e2e.ts +++ b/e2e/playwright/viewer/src/tests/viewer-version-actions.e2e.ts @@ -60,7 +60,7 @@ test.describe('Version actions', () => { await page.dataTable.selectItems(filenameAfterUpdate); await page.acaHeader.clickMoreActions(); await page.matMenu.clickMenuItem('Manage Versions'); - await page.manageVersionsDialog.viewFileVersion('1.0'); + await page.manageVersionsDialog.clickListActionButtonForVersion('1.0'); await page.matMenu.clickMenuItem('View'); } @@ -109,7 +109,7 @@ test.describe('Version actions', () => { test('[XAT-5497] Previous document version title should be the same in Preview mode as in Version Manager - Personal Files', async ({ personalFiles }) => { - await personalFiles.viewer.waitForViewerToOpen('wait for viewer content'); + await personalFiles.viewer.waitForViewerToOpen(); expect(await personalFiles.viewer.getFileTitle()).toContain(filenameBeforeUpdate); }); @@ -133,7 +133,7 @@ test.describe('Version actions', () => { test('[XAT-5500] Previous document version title should be the same in Preview mode as in Version Manager - Recent Files', async ({ recentFilesPage }) => { - await recentFilesPage.viewer.waitForViewerToOpen('wait for viewer content'); + await recentFilesPage.viewer.waitForViewerToOpen(); expect(await recentFilesPage.viewer.getFileTitle()).toContain(filenameBeforeUpdate); }); @@ -157,7 +157,7 @@ test.describe('Version actions', () => { test('[XAT-5503] Previous document version title should be the same in Preview mode as in Version Manager - Favorites', async ({ favoritePage }) => { - await favoritePage.viewer.waitForViewerToOpen('wait for viewer content'); + await favoritePage.viewer.waitForViewerToOpen(); expect(await favoritePage.viewer.getFileTitle()).toContain(filenameBeforeUpdate); }); @@ -205,7 +205,7 @@ test.describe('Version actions', () => { test('[XAT-5509] Previous document version title should be the same in Preview mode as in Version Manager - Search Results', async ({ searchPage }) => { - await searchPage.viewer.waitForViewerToOpen('wait for viewer content'); + await searchPage.viewer.waitForViewerToOpen(); expect(await searchPage.viewer.getFileTitle()).toContain(filenameBeforeUpdate); }); diff --git a/e2e/playwright/viewer/src/tests/viewer.e2e.ts b/e2e/playwright/viewer/src/tests/viewer.e2e.ts index 7fd3303b6..973f6e411 100644 --- a/e2e/playwright/viewer/src/tests/viewer.e2e.ts +++ b/e2e/playwright/viewer/src/tests/viewer.e2e.ts @@ -38,195 +38,504 @@ import { } from '@alfresco/aca-playwright-shared'; import { Site } from '@alfresco/js-api'; +async function initializeApis(username: string): Promise<{ nodesApi: NodesApi; trashcanApi: TrashcanApi; fileActionsApi: FileActionsApi }> { + const apiClientFactory = new ApiClientFactory(); + await apiClientFactory.setUpAcaBackend('admin'); + await apiClientFactory.createUser({ username }); + const nodesApi = await NodesApi.initialize(username, username); + const trashcanApi = await TrashcanApi.initialize(username, username); + const fileActionsApi = await FileActionsApi.initialize(username, username); + return { nodesApi, trashcanApi, fileActionsApi }; +} + test.describe('viewer file', () => { - const username = `user-${Utils.random()}`; - const randomDocxName = `${TEST_FILES.DOCX.name}-${Utils.random()}`; - const randomJpgName = `${TEST_FILES.JPG_FILE.name}-${Utils.random()}`; - const siteUser = `siteUser-${Utils.random()}`; - const fileInSite = TEST_FILES.DOCX.name; - const siteAdmin = `siteAdmin-${Utils.random()}`; - const fileAdmin = TEST_FILES.XLSX.name; - let fileAdminId: string; - let docLibId: string; - let docLibSiteUserId: string; - let folderId: string; - let fileDocxId: string; - let fileJpgId: string; - let nodesApi: NodesApi; - let trashcanApi: TrashcanApi; - let siteActionsAdmin: SitesApi; - let siteActionsUser: SitesApi; + test.describe('Open viewer from Personal Files', () => { + const username = `user-${Utils.random()}`; + const randomDocxName = `${TEST_FILES.DOCX.name}-${Utils.random()}`; + let folderViewerId: string; + let nodesApiViewer: NodesApi; + let trashcanApiViewer: TrashcanApi; - test.beforeAll(async () => { - test.setTimeout(timeouts.extendedTest); - const randomFolderName = `viewer-${Utils.random()}`; - const apiClientFactory = new ApiClientFactory(); - await apiClientFactory.setUpAcaBackend('admin'); - try { - await apiClientFactory.createUser({ username }); - } catch (exception) { - if (JSON.parse(exception.message).error.statusCode !== 409) { - throw new Error(`----- beforeAll failed : ${exception}`); + test.beforeAll(async () => { + try { + const apis = await initializeApis(username); + nodesApiViewer = apis.nodesApi; + trashcanApiViewer = apis.trashcanApi; + const { fileActionsApi } = apis; + folderViewerId = (await nodesApiViewer.createFolder(`viewer-${Utils.random()}`)).entry.id; + await fileActionsApi.uploadFile(TEST_FILES.DOCX.path, randomDocxName, folderViewerId); + await fileActionsApi.waitForNodes(randomDocxName, { expect: 1 }); + } catch (error) { + console.error(`beforeAll failed: ${error}`); + throw error; } - } - nodesApi = await NodesApi.initialize(username, username); - const fileActionApi = await FileActionsApi.initialize(username, username); - trashcanApi = await TrashcanApi.initialize(username, username); - const shareActions = await SharedLinksApi.initialize(username, username); - const favoritesActions = await FavoritesPageApi.initialize(username, username); - siteActionsUser = await SitesApi.initialize(username, username); - siteActionsAdmin = await SitesApi.initialize('admin'); - const fileActionApiAdmin = await FileActionsApi.initialize('admin'); - const node = await nodesApi.createFolder(randomFolderName); - folderId = node.entry.id; - const fileDoc = await fileActionApi.uploadFile(TEST_FILES.DOCX.path, randomDocxName, folderId); - fileDocxId = fileDoc.entry.id; - const fileJpg = await fileActionApi.uploadFile(TEST_FILES.JPG_FILE.path, randomJpgName, folderId); - fileJpgId = fileJpg.entry.id; - const consumerFavoritesTotalItems = await favoritesActions.getFavoritesTotalItems(username); - await shareActions.shareFileById(fileDocxId); - await favoritesActions.addFavoriteById('file', fileDocxId); + }); - try { - await siteActionsAdmin.createSite(siteAdmin, Site.VisibilityEnum.PRIVATE); - } catch (exception) { - if (JSON.parse(exception.message).error.statusCode !== 409) { - throw new Error(`----- beforeAll failed : ${exception}`); + test.beforeEach(async ({ personalFiles, loginPage }) => { + await Utils.tryLoginUser(loginPage, username, username, 'beforeEach failed'); + await personalFiles.navigate({ remoteUrl: `#/personal-files/${folderViewerId}` }); + }); + + test.afterAll(async () => { + await Utils.deleteNodesSitesEmptyTrashcan(nodesApiViewer, trashcanApiViewer, 'afterAll failed'); + }); + + test('[XAT-5471] Viewer opens on double clicking on a file from Personal Files', async ({ personalFiles }) => { + await personalFiles.dataTable.performClickFolderOrFileToOpen(randomDocxName); + expect(await personalFiles.viewer.isViewerOpened(), 'Viewer is not opened').toBe(true); + }); + + test('[XAT-5472] Viewer opens when clicking the View action for a file', async ({ personalFiles }) => { + await personalFiles.dataTable.getRowByName(randomDocxName).click(); + await personalFiles.acaHeader.viewButton.click(); + await personalFiles.dataTable.spinnerWaitForReload(); + expect(await personalFiles.viewer.isViewerOpened(), 'Viewer is not opened').toBe(true); + }); + + test('[XAT-5473] The viewer general elements are displayed correctly', async ({ personalFiles }) => { + await personalFiles.dataTable.performClickFolderOrFileToOpen(randomDocxName); + expect(await personalFiles.viewer.isViewerOpened()).toBe(true); + await personalFiles.dataTable.spinnerWaitForReload(); + expect(await personalFiles.viewer.isCloseButtonDisplayed(), 'Close button is not displayed').toBe(true); + expect(await personalFiles.viewer.isFileTitleDisplayed(), 'File title is not displayed').toBe(true); + }); + + test('[XAT-5474] Close the viewer', async ({ personalFiles }) => { + await personalFiles.dataTable.performClickFolderOrFileToOpen(randomDocxName); + expect(await personalFiles.viewer.isViewerOpened(), 'Viewer is not opened').toBe(true); + expect(await personalFiles.viewer.getCloseButtonTooltip()).toEqual('Close'); + await personalFiles.viewer.closeButtonLocator.click(); + await expect(personalFiles.dataTable.getCellLinkByName(randomDocxName), 'Viewer did not close').toBeVisible(); + }); + }); + + test.describe('Navigate between files', () => { + const username = `user-${Utils.random()}`; + const file1 = `file-${Utils.random()}.txt`; + const file2 = `file2-${Utils.random()}.txt`; + const file3 = `file3-${Utils.random()}.txt`; + let folder2Id: string; + let folder3Id: string; + let nodesApi: NodesApi; + let trashcanApi: TrashcanApi; + + test.beforeAll(async () => { + try { + const apis = await initializeApis(username); + nodesApi = apis.nodesApi; + trashcanApi = apis.trashcanApi; + folder2Id = (await nodesApi.createFolder(`viewer2-${Utils.random()}`)).entry.id; + folder3Id = (await nodesApi.createFolder(`viewer3-${Utils.random()}`)).entry.id; + await nodesApi.createFile(file1, folder2Id); + await nodesApi.createFile(file2, folder2Id); + await nodesApi.createFile(file3, folder3Id); + } catch (error) { + console.error(`beforeAll failed: ${error}`); + throw error; } - } + }); - docLibId = await siteActionsAdmin.getDocLibId(siteAdmin); + test.beforeEach(async ({ loginPage }) => { + await Utils.tryLoginUser(loginPage, username, username, 'beforeEach failed'); + }); - try { - fileAdminId = (await fileActionApiAdmin.uploadFile(TEST_FILES.DOCX.path, fileAdmin, docLibId)).entry.id; - } catch (exception) { - if (JSON.parse(exception.message).error.statusCode !== 409) { - throw new Error(`----- beforeAll failed : ${exception}`); + test.afterAll(async () => { + await Utils.deleteNodesSitesEmptyTrashcan(nodesApi, trashcanApi, 'afterAll failed'); + }); + + test('[XAT-5408] Next / Previous File buttons are displayed and work when viewer is opened for a file from a list of files', async ({ + personalFiles + }) => { + await personalFiles.navigate({ remoteUrl: `#/personal-files/${folder2Id}` }); + await personalFiles.dataTable.performClickFolderOrFileToOpen(file1); + expect(await personalFiles.viewer.isViewerOpened(), 'Viewer is not opened').toBe(true); + expect(await personalFiles.viewer.fileTitleButtonLocator.textContent()).toContain(file1); + await personalFiles.viewer.nextFileButton.or(personalFiles.viewer.previousFileButton).first().click(); + await personalFiles.viewer.waitForViewerLoaderToFinish(); + expect(await personalFiles.viewer.fileTitleButtonLocator.textContent()).not.toContain(file1); + await personalFiles.viewer.nextFileButton.or(personalFiles.viewer.previousFileButton).first().click(); + await personalFiles.viewer.waitForViewerLoaderToFinish(); + expect(await personalFiles.viewer.fileTitleButtonLocator.textContent()).toContain(file1); + }); + + test('[XAT-5409] Previous File button is not displayed when file is first in the list', async ({ personalFiles }) => { + await personalFiles.navigate({ remoteUrl: `#/personal-files/${folder2Id}` }); + await personalFiles.dataTable.performClickFolderOrFileToOpen(file1); + expect(await personalFiles.viewer.isViewerOpened(), 'Viewer is not opened').toBe(true); + if (await personalFiles.viewer.previousFileButton.isVisible()) { + await personalFiles.viewer.previousFileButton.click(); + await personalFiles.viewer.waitForViewerLoaderToFinish(); } - } + await expect(personalFiles.viewer.nextFileButton).toBeVisible(); + await expect(personalFiles.viewer.previousFileButton).toBeHidden(); + }); - try { - await siteActionsUser.createSite(siteUser, Site.VisibilityEnum.PUBLIC); - } catch (exception) { - if (JSON.parse(exception.message).error.statusCode !== 409) { - throw new Error(`----- beforeAll failed : ${exception}`); + test('[XAT-5410] Next File button is not displayed when file is last in the list view', async ({ personalFiles }) => { + await personalFiles.navigate({ remoteUrl: `#/personal-files/${folder2Id}` }); + await personalFiles.dataTable.performClickFolderOrFileToOpen(file1); + expect(await personalFiles.viewer.isViewerOpened(), 'Viewer is not opened').toBe(true); + if (await personalFiles.viewer.nextFileButton.isVisible()) { + await personalFiles.viewer.nextFileButton.click(); + await personalFiles.viewer.waitForViewerLoaderToFinish(); } - } + await expect(personalFiles.viewer.previousFileButton).toBeVisible(); + await expect(personalFiles.viewer.nextFileButton).toBeHidden(); + }); - docLibSiteUserId = await siteActionsUser.getDocLibId(siteUser); + test('[XAT-5411] Next / Previous File buttons are not displayed when no other files', async ({ personalFiles }) => { + await personalFiles.navigate({ remoteUrl: `#/personal-files/${folder3Id}` }); + await personalFiles.dataTable.performClickFolderOrFileToOpen(file3); + expect(await personalFiles.viewer.isViewerOpened(), 'Viewer is not opened').toBe(true); + await expect(personalFiles.viewer.fileTitleButtonLocator).toBeVisible(); + await expect(personalFiles.viewer.previousFileButton).toBeHidden(); + await expect(personalFiles.viewer.nextFileButton).toBeHidden(); + }); + }); - try { - await fileActionApi.uploadFile(TEST_FILES.DOCX.path, fileInSite, docLibSiteUserId); - } catch (exception) { - if (JSON.parse(exception.message).error.statusCode !== 409) { - throw new Error(`----- beforeAll failed : ${exception}`); + test.describe('Navigate between files - permissions', () => { + const username1 = `user1-${Utils.random()}`; + const username2 = `user2-${Utils.random()}`; + const file1 = `file-${Utils.random()}.txt`; + const file2 = `file2-${Utils.random()}.txt`; + const file3 = `file3-${Utils.random()}.txt`; + let folderId: string; + let nodesApi1: NodesApi; + let trashcanApi1: TrashcanApi; + let sitesApi1: SitesApi; + let site1Id: string; + let user2Id: string; + + test.beforeAll(async () => { + try { + const apiClientFactory = new ApiClientFactory(); + await apiClientFactory.setUpAcaBackend('admin'); + await apiClientFactory.createUser({ username: username1 }); + user2Id = (await apiClientFactory.createUser({ username: username2 })).entry.id; + nodesApi1 = await NodesApi.initialize(username1, username1); + trashcanApi1 = await TrashcanApi.initialize(username1, username1); + sitesApi1 = await SitesApi.initialize(username1, username1); + site1Id = (await sitesApi1.createSite(`viewer-site-${Utils.random()}`, 'PRIVATE')).entry.id; + const site1DocLibId = await sitesApi1.getDocLibId(site1Id); + await sitesApi1.addSiteMember(site1Id, user2Id, 'SiteConsumer'); + folderId = (await nodesApi1.createFolder(`viewer-permissions-${Utils.random()}`, site1DocLibId)).entry.id; + await nodesApi1.createFile(file1, folderId); + await nodesApi1.createFile(file2, folderId); + await nodesApi1.createFile(file3, folderId); + } catch (error) { + console.error(`beforeAll failed: ${error}`); + throw error; } - } + }); - await Promise.all([ - favoritesActions.isFavoriteWithRetry(username, fileDocxId, { expect: true }), - favoritesActions.waitForApi(username, { expect: consumerFavoritesTotalItems + 2 }) - ]); - await shareActions.waitForFilesToBeShared([fileDocxId]); - await fileActionApi.waitForNodes(randomDocxName, { expect: 1 }); + test.beforeEach(async ({ loginPage }) => { + await Utils.tryLoginUser(loginPage, username2, username2, 'beforeEach failed'); + }); + + test.afterAll(async () => { + await Utils.deleteNodesSitesEmptyTrashcan(nodesApi1, trashcanApi1, 'afterAll failed'); + await sitesApi1.deleteSites([site1Id]); + }); + + test('[XAT-5412] Next/Previous File buttons when user has insufficient permissions', async ({ personalFiles }) => { + await personalFiles.navigate({ remoteUrl: `#/libraries/${folderId}` }); + await personalFiles.dataTable.performClickFolderOrFileToOpen(file2); + expect(await personalFiles.viewer.isViewerOpened(), 'Viewer is not opened').toBe(true); + await expect(personalFiles.viewer.fileTitleButtonLocator).toBeVisible(); + await expect(personalFiles.viewer.previousFileButton.or(personalFiles.viewer.nextFileButton).first()).toBeVisible(); + await sitesApi1.deleteSiteMember(site1Id, user2Id); + await personalFiles.viewer.previousFileButton.or(personalFiles.viewer.nextFileButton).first().click(); + await expect(personalFiles.viewer.noPermissionsView.or(personalFiles.dataTable.noPermissionsView)).toBeVisible(); + }); }); - test.beforeEach(async ({ personalFiles, loginPage }) => { - await Utils.tryLoginUser(loginPage, username, username, 'beforeEach failed'); - await personalFiles.navigate({ remoteUrl: `#/personal-files/${folderId}` }); + test.describe('Open viewer via preview URL', () => { + const username = `user-${Utils.random()}`; + const randomJpgName = `${TEST_FILES.JPG_FILE.name}-${Utils.random()}`; + let folderId: string; + let fileJpgId: string; + let nodesApi: NodesApi; + let trashcanApi: TrashcanApi; + + test.beforeAll(async () => { + try { + const apis = await initializeApis(username); + nodesApi = apis.nodesApi; + trashcanApi = apis.trashcanApi; + const { fileActionsApi } = apis; + folderId = (await nodesApi.createFolder(`viewer-${Utils.random()}`)).entry.id; + fileJpgId = (await fileActionsApi.uploadFile(TEST_FILES.JPG_FILE.path, randomJpgName, folderId)).entry.id; + } catch (error) { + console.error(`beforeAll failed: ${error}`); + throw error; + } + }); + + test.beforeEach(async ({ loginPage }) => { + await Utils.tryLoginUser(loginPage, username, username, 'beforeEach failed'); + }); + + test.afterAll(async () => { + await Utils.deleteNodesSitesEmptyTrashcan(nodesApi, trashcanApi, 'afterAll failed'); + }); + + test('[XAT-5476] Viewer opens when accessing the preview URL for a file', async ({ personalFiles }) => { + const previewURL = `#/personal-files/${folderId}/(viewer:view/${fileJpgId})`; + await personalFiles.navigate({ remoteUrl: previewURL }); + await personalFiles.viewer.waitForViewerLoaderToFinish(timeouts.fortySeconds); + await expect(personalFiles.viewer.fileTitleButtonLocator).toContainText(randomJpgName); + }); }); - test.afterAll(async () => { - await Utils.deleteNodesSitesEmptyTrashcan(nodesApi, trashcanApi, 'afterAll failed', siteActionsUser, [docLibSiteUserId]); - await Utils.deleteNodesSitesEmptyTrashcan(nodesApi, trashcanApi, 'afterAll failed', siteActionsAdmin, [docLibId]); + test.describe('Open viewer from Recent Files', () => { + const username = `user-${Utils.random()}`; + const randomDocxName = `${TEST_FILES.DOCX.name}-${Utils.random()}`; + let folderRecentId: string; + let nodesApiRecent: NodesApi; + let trashcanApiRecent: TrashcanApi; + + test.beforeAll(async () => { + try { + const apis = await initializeApis(username); + nodesApiRecent = apis.nodesApi; + trashcanApiRecent = apis.trashcanApi; + const { fileActionsApi } = apis; + folderRecentId = (await nodesApiRecent.createFolder(`viewer-${Utils.random()}`)).entry.id; + await fileActionsApi.uploadFile(TEST_FILES.DOCX.path, randomDocxName, folderRecentId); + await fileActionsApi.waitForNodes(randomDocxName, { expect: 1 }); + } catch (error) { + console.error(`beforeAll failed: ${error}`); + throw error; + } + }); + + test.beforeEach(async ({ personalFiles, loginPage }) => { + await Utils.tryLoginUser(loginPage, username, username, 'beforeEach failed'); + await personalFiles.navigate({ remoteUrl: `#/personal-files/${folderRecentId}` }); + }); + + test.afterAll(async () => { + await Utils.deleteNodesSitesEmptyTrashcan(nodesApiRecent, trashcanApiRecent, 'afterAll failed'); + }); + + test('[XAT-5479] Viewer opens for a file from Recent Files', async ({ personalFiles, recentFilesPage }) => { + await personalFiles.dataTable.performClickFolderOrFileToOpen(randomDocxName); + expect(await personalFiles.viewer.getCloseButtonTooltip()).toEqual('Close'); + await recentFilesPage.navigate(); + await recentFilesPage.reload(); + await recentFilesPage.dataTable.performClickFolderOrFileToOpen(randomDocxName); + expect(await recentFilesPage.viewer.isViewerOpened(), 'Viewer is not opened').toBe(true); + expect(await recentFilesPage.viewer.isCloseButtonDisplayed(), 'Close button is not displayed').toBe(true); + expect(await recentFilesPage.viewer.isFileTitleDisplayed(), 'File title is not displayed').toBe(true); + }); }); - test('[XAT-5471] Viewer opens on double clicking on a file from Personal Files', async ({ personalFiles }) => { - await personalFiles.dataTable.performClickFolderOrFileToOpen(randomDocxName); - expect(await personalFiles.viewer.isViewerOpened(), 'Viewer is not opened').toBe(true); + test.describe('Open viewer from Search Results', () => { + const username = `user-${Utils.random()}`; + const randomDocxName = `${TEST_FILES.DOCX.name}-${Utils.random()}`; + let nodesApi: NodesApi; + let trashcanApi: TrashcanApi; + + test.beforeAll(async () => { + try { + const apis = await initializeApis(username); + nodesApi = apis.nodesApi; + trashcanApi = apis.trashcanApi; + const { fileActionsApi } = apis; + const folderId = (await nodesApi.createFolder(`viewer-${Utils.random()}`)).entry.id; + await fileActionsApi.uploadFile(TEST_FILES.DOCX.path, randomDocxName, folderId); + await fileActionsApi.waitForNodes(randomDocxName, { expect: 1 }); + } catch (error) { + console.error(`beforeAll failed: ${error}`); + throw error; + } + }); + + test.beforeEach(async ({ loginPage }) => { + await Utils.tryLoginUser(loginPage, username, username, 'beforeEach failed'); + }); + + test.afterAll(async () => { + await Utils.deleteNodesSitesEmptyTrashcan(nodesApi, trashcanApi, 'afterAll failed'); + }); + + test('[XAT-5482] Viewer opens for a file from Search Results', async ({ searchPage }) => { + await searchPage.searchWithin(randomDocxName, 'filesAndFolders'); + await searchPage.dataTable.goThroughPagesLookingForRowWithName(randomDocxName); + await searchPage.dataTable.performClickFolderOrFileToOpen(randomDocxName); + expect(await searchPage.viewer.isViewerOpened(), 'Viewer is not opened').toBe(true); + expect(await searchPage.viewer.isCloseButtonDisplayed(), 'Close button is not displayed').toBe(true); + expect(await searchPage.viewer.isFileTitleDisplayed(), 'File title is not displayed').toBe(true); + }); }); - test('[XAT-5472] Viewer opens when clicking the View action for a file', async ({ personalFiles }) => { - await personalFiles.dataTable.getRowByName(randomDocxName).click(); - await personalFiles.acaHeader.viewButton.click(); - await personalFiles.dataTable.spinnerWaitForReload(); - expect(await personalFiles.viewer.isViewerOpened(), 'Viewer is not opened').toBe(true); + test.describe('Open viewer from Shared Files', () => { + const username = `user-${Utils.random()}`; + const randomDocxName = `${TEST_FILES.DOCX.name}-${Utils.random()}`; + let nodesApi: NodesApi; + let trashcanApi: TrashcanApi; + + test.beforeAll(async () => { + try { + const apis = await initializeApis(username); + nodesApi = apis.nodesApi; + trashcanApi = apis.trashcanApi; + const { fileActionsApi } = apis; + const shareActions = await SharedLinksApi.initialize(username, username); + const folderId = (await nodesApi.createFolder(`viewer-${Utils.random()}`)).entry.id; + const fileDocxId = (await fileActionsApi.uploadFile(TEST_FILES.DOCX.path, randomDocxName, folderId)).entry.id; + await shareActions.shareFileById(fileDocxId); + await shareActions.waitForFilesToBeShared([fileDocxId]); + } catch (error) { + console.error(`beforeAll failed: ${error}`); + throw error; + } + }); + + test.beforeEach(async ({ loginPage }) => { + await Utils.tryLoginUser(loginPage, username, username, 'beforeEach failed'); + }); + + test.afterAll(async () => { + await Utils.deleteNodesSitesEmptyTrashcan(nodesApi, trashcanApi, 'afterAll failed'); + }); + + test('[XAT-5480] Viewer opens for a file from Shared Files', async ({ sharedPage }) => { + await sharedPage.navigate(); + await sharedPage.reload({ waitUntil: 'domcontentloaded' }); + await sharedPage.dataTable.goThroughPagesLookingForRowWithName(randomDocxName); + await sharedPage.dataTable.performClickFolderOrFileToOpen(randomDocxName); + expect(await sharedPage.viewer.isViewerOpened(), 'Viewer is not opened').toBe(true); + expect(await sharedPage.viewer.isCloseButtonDisplayed(), 'Close button is not displayed').toBe(true); + expect(await sharedPage.viewer.isFileTitleDisplayed(), 'File title is not displayed').toBe(true); + }); }); - test('[XAT-5473] The viewer general elements are displayed correctly', async ({ personalFiles }) => { - await personalFiles.dataTable.performClickFolderOrFileToOpen(randomDocxName); - expect(await personalFiles.viewer.isViewerOpened()).toBe(true); - await personalFiles.dataTable.spinnerWaitForReload(); - expect(await personalFiles.viewer.isCloseButtonDisplayed(), 'Close button is not displayed').toBe(true); - expect(await personalFiles.viewer.isFileTitleDisplayed(), 'File title is not displayed').toBe(true); + test.describe('Open viewer from Favorites', () => { + const username = `user-${Utils.random()}`; + const randomDocxName = `${TEST_FILES.DOCX.name}-${Utils.random()}`; + let nodesApi: NodesApi; + let trashcanApi: TrashcanApi; + + test.beforeAll(async () => { + try { + const apis = await initializeApis(username); + nodesApi = apis.nodesApi; + trashcanApi = apis.trashcanApi; + const { fileActionsApi } = apis; + const favoritesActions = await FavoritesPageApi.initialize(username, username); + const folderId = (await nodesApi.createFolder(`viewer-${Utils.random()}`)).entry.id; + const fileDocxId = (await fileActionsApi.uploadFile(TEST_FILES.DOCX.path, randomDocxName, folderId)).entry.id; + const consumerFavoritesTotalItems = await favoritesActions.getFavoritesTotalItems(username); + await favoritesActions.addFavoriteById('file', fileDocxId); + await Promise.all([ + favoritesActions.isFavoriteWithRetry(username, fileDocxId, { expect: true }), + favoritesActions.waitForApi(username, { expect: consumerFavoritesTotalItems + 1 }) + ]); + } catch (error) { + console.error(`beforeAll failed: ${error}`); + throw error; + } + }); + + test.beforeEach(async ({ loginPage }) => { + await Utils.tryLoginUser(loginPage, username, username, 'beforeEach failed'); + }); + + test.afterAll(async () => { + await Utils.deleteNodesSitesEmptyTrashcan(nodesApi, trashcanApi, 'afterAll failed'); + }); + + test('[XAT-5481] Viewer opens for a file from Favorites', async ({ favoritePage }) => { + await favoritePage.navigate({ waitUntil: 'domcontentloaded' }); + await favoritePage.dataTable.goThroughPagesLookingForRowWithName(randomDocxName); + await favoritePage.dataTable.performClickFolderOrFileToOpen(randomDocxName); + expect(await favoritePage.viewer.isViewerOpened(), 'Viewer is not opened').toBe(true); + expect(await favoritePage.viewer.isCloseButtonDisplayed(), 'Close button is not displayed').toBe(true); + expect(await favoritePage.viewer.isFileTitleDisplayed(), 'File title is not displayed').toBe(true); + }); }); - test('[XAT-5474] Close the viewer', async ({ personalFiles }) => { - await personalFiles.dataTable.performClickFolderOrFileToOpen(randomDocxName); - expect(await personalFiles.viewer.isViewerOpened(), 'Viewer is not opened').toBe(true); - expect(await personalFiles.viewer.getCloseButtonTooltip()).toEqual('Close'); - await personalFiles.viewer.closeButtonLocator.click(); - await expect(personalFiles.dataTable.getCellLinkByName(randomDocxName), 'Viewer did not close').toBeVisible(); + test.describe('Viewer does not open without permissions', () => { + const username = `user-${Utils.random()}`; + const siteAdmin = `siteAdmin-${Utils.random()}`; + const fileAdmin = TEST_FILES.XLSX.name; + let docLibId: string; + let fileAdminId: string; + let nodesApi: NodesApi; + let trashcanApi: TrashcanApi; + let siteActionsAdmin: SitesApi; + + test.beforeAll(async () => { + try { + const apis = await initializeApis(username); + nodesApi = apis.nodesApi; + trashcanApi = apis.trashcanApi; + siteActionsAdmin = await SitesApi.initialize('admin'); + const fileActionsApiAdmin = await FileActionsApi.initialize('admin'); + await siteActionsAdmin.createSite(siteAdmin, Site.VisibilityEnum.PRIVATE); + docLibId = await siteActionsAdmin.getDocLibId(siteAdmin); + fileAdminId = (await fileActionsApiAdmin.uploadFile(TEST_FILES.DOCX.path, fileAdmin, docLibId)).entry.id; + } catch (error) { + console.error(`beforeAll failed: ${error}`); + throw error; + } + }); + + test.beforeEach(async ({ loginPage }) => { + await Utils.tryLoginUser(loginPage, username, username, 'beforeEach failed'); + }); + + test.afterAll(async () => { + await Utils.deleteNodesSitesEmptyTrashcan(nodesApi, trashcanApi, 'afterAll failed', siteActionsAdmin, [docLibId]); + }); + + test('[XAT-5477] Viewer does not open when accessing the preview URL for a file without permissions', async ({ personalFiles }) => { + const previewURL = `#/libraries/${docLibId}/(viewer:view/${fileAdminId})`; + await personalFiles.navigate({ remoteUrl: `${previewURL}` }); + await expect(personalFiles.viewer.viewerLocator, 'Viewer should not be opened!').toBeHidden(); + }); }); - test('[XAT-5479] Viewer opens for a file from Recent Files', async ({ personalFiles, recentFilesPage }) => { - await personalFiles.dataTable.performClickFolderOrFileToOpen(randomDocxName); - expect(await personalFiles.viewer.getCloseButtonTooltip()).toEqual('Close'); - await recentFilesPage.navigate(); - await recentFilesPage.reload(); - await recentFilesPage.dataTable.performClickFolderOrFileToOpen(randomDocxName); - expect(await recentFilesPage.viewer.isViewerOpened(), 'Viewer is not opened').toBe(true); - expect(await recentFilesPage.viewer.isCloseButtonDisplayed(), 'Close button is not displayed').toBe(true); - expect(await recentFilesPage.viewer.isFileTitleDisplayed(), 'File title is not displayed').toBe(true); - }); + test.describe('Open viewer from File Libraries', () => { + const username = `user-${Utils.random()}`; + const siteUser = `siteUser-${Utils.random()}`; + const fileInSite = TEST_FILES.DOCX.name; + let docLibSiteUserId: string; + let nodesApi: NodesApi; + let trashcanApi: TrashcanApi; + let siteActionsUser: SitesApi; - test('[XAT-5482] Viewer opens for a file from Search Results', async ({ searchPage }) => { - await searchPage.searchWithin(randomDocxName, 'filesAndFolders'); - await searchPage.dataTable.goThroughPagesLookingForRowWithName(randomDocxName); - await searchPage.dataTable.performClickFolderOrFileToOpen(randomDocxName); - expect(await searchPage.viewer.isViewerOpened(), 'Viewer is not opened').toBe(true); - expect(await searchPage.viewer.isCloseButtonDisplayed(), 'Close button is not displayed').toBe(true); - expect(await searchPage.viewer.isFileTitleDisplayed(), 'File title is not displayed').toBe(true); - }); + test.beforeAll(async () => { + try { + const apis = await initializeApis(username); + nodesApi = apis.nodesApi; + trashcanApi = apis.trashcanApi; + const { fileActionsApi } = apis; + siteActionsUser = await SitesApi.initialize(username, username); + await siteActionsUser.createSite(siteUser, Site.VisibilityEnum.PUBLIC); + docLibSiteUserId = await siteActionsUser.getDocLibId(siteUser); + await fileActionsApi.uploadFile(TEST_FILES.DOCX.path, fileInSite, docLibSiteUserId); + } catch (error) { + console.error(`beforeAll failed: ${error}`); + throw error; + } + }); - test('[XAT-5476] Viewer opens when accessing the preview URL for a file', async ({ personalFiles }) => { - const previewURL = `#/personal-files/${folderId}/(viewer:view/${fileJpgId})`; - await personalFiles.navigate({ remoteUrl: previewURL }); - await personalFiles.viewer.waitForViewerLoaderToFinish(timeouts.fortySeconds); - await expect(personalFiles.viewer.fileTitleButtonLocator).toContainText(randomJpgName); - }); + test.beforeEach(async ({ loginPage }) => { + await Utils.tryLoginUser(loginPage, username, username, 'beforeEach failed'); + }); - test('[XAT-5480] Viewer opens for a file from Shared Files', async ({ sharedPage }) => { - await sharedPage.navigate(); - await sharedPage.reload({ waitUntil: 'domcontentloaded' }); - await sharedPage.dataTable.goThroughPagesLookingForRowWithName(randomDocxName); - await sharedPage.dataTable.performClickFolderOrFileToOpen(randomDocxName); - expect(await sharedPage.viewer.isViewerOpened(), 'Viewer is not opened').toBe(true); - expect(await sharedPage.viewer.isCloseButtonDisplayed(), 'Close button is not displayed').toBe(true); - expect(await sharedPage.viewer.isFileTitleDisplayed(), 'File title is not displayed').toBe(true); - }); + test.afterAll(async () => { + await Utils.deleteNodesSitesEmptyTrashcan(nodesApi, trashcanApi, 'afterAll failed', siteActionsUser, [docLibSiteUserId]); + }); - test('[XAT-5481] Viewer opens for a file from Favorites', async ({ favoritePage }) => { - await favoritePage.navigate({ waitUntil: 'domcontentloaded' }); - await favoritePage.dataTable.goThroughPagesLookingForRowWithName(randomDocxName); - await favoritePage.dataTable.performClickFolderOrFileToOpen(randomDocxName); - expect(await favoritePage.viewer.isViewerOpened(), 'Viewer is not opened').toBe(true); - expect(await favoritePage.viewer.isCloseButtonDisplayed(), 'Close button is not displayed').toBe(true); - expect(await favoritePage.viewer.isFileTitleDisplayed(), 'File title is not displayed').toBe(true); - }); - - test('[XAT-5477] Viewer does not open when accessing the preview URL for a file without permissions', async ({ personalFiles }) => { - const previewURL = `#/libraries/${docLibId}/(viewer:view/${fileAdminId})`; - await personalFiles.navigate({ remoteUrl: `${previewURL}` }); - await expect(personalFiles.viewer.viewerLocator, 'Viewer should not be opened!').toBeHidden(); - }); - - test('[XAT-5478] Viewer opens for a file from File Libraries', async ({ myLibrariesPage }) => { - await myLibrariesPage.navigate(); - await myLibrariesPage.dataTable.performClickFolderOrFileToOpen(siteUser); - await myLibrariesPage.dataTable.performClickFolderOrFileToOpen(fileInSite); - expect(await myLibrariesPage.viewer.isViewerOpened(), 'Viewer is not opened').toBe(true); - expect(await myLibrariesPage.viewer.isCloseButtonDisplayed(), 'Close button is not displayed').toBe(true); - expect(await myLibrariesPage.viewer.isFileTitleDisplayed(), 'File title is not displayed').toBe(true); + test('[XAT-5478] Viewer opens for a file from File Libraries', async ({ myLibrariesPage }) => { + await myLibrariesPage.navigate(); + await myLibrariesPage.dataTable.performClickFolderOrFileToOpen(siteUser); + await myLibrariesPage.dataTable.performClickFolderOrFileToOpen(fileInSite); + expect(await myLibrariesPage.viewer.isViewerOpened(), 'Viewer is not opened').toBe(true); + expect(await myLibrariesPage.viewer.isCloseButtonDisplayed(), 'Close button is not displayed').toBe(true); + expect(await myLibrariesPage.viewer.isFileTitleDisplayed(), 'File title is not displayed').toBe(true); + }); }); }); diff --git a/projects/aca-playwright-shared/src/api/file-actions.ts b/projects/aca-playwright-shared/src/api/file-actions.ts index 8ddd161f6..9c44a9a54 100644 --- a/projects/aca-playwright-shared/src/api/file-actions.ts +++ b/projects/aca-playwright-shared/src/api/file-actions.ts @@ -159,9 +159,9 @@ export class FileActionsApi { try { await waitForApi(apiCall, predicate, 30, 2500); - console.log(`waitForNodes: Found ${data.expect} nodes with search term "${searchTerm}"`); - } catch (error) { - console.error(`Error: ${error}`); + } catch { + const actual = await apiCall(); + throw new Error(`waitForNodes: Timed out waiting for "${searchTerm}" — expected ${data.expect} nodes, found ${actual}`); } } diff --git a/projects/aca-playwright-shared/src/api/nodes-api.ts b/projects/aca-playwright-shared/src/api/nodes-api.ts index 4563e0a29..ead138497 100755 --- a/projects/aca-playwright-shared/src/api/nodes-api.ts +++ b/projects/aca-playwright-shared/src/api/nodes-api.ts @@ -25,6 +25,7 @@ import { ApiClientFactory } from './api-client-factory'; import { NodeChildAssociationPaging, NodeEntry, NodePaging, NodesIncludeQuery, NodeBodyUpdate } from '@alfresco/js-api'; import { NodeContentTree, flattenNodeContentTree } from './node-content-tree'; +import { Utils } from '../utils'; export class NodesApi { private readonly apiService: ApiClientFactory; @@ -81,6 +82,17 @@ export class NodesApi { } } + async createMultipleFiles(count: number, parentId = '-my-'): Promise { + const createdFiles: NodeEntry[] = []; + for (let i = 0; i < count; i++) { + const file = await this.createFile(`file-${Utils.random()}-${i}`, parentId); + if (file) { + createdFiles.push(file); + } + } + return createdFiles; + } + async createFolders(names: string[], relativePath = '/'): Promise { try { return await this.createContent({ folders: names }, relativePath); diff --git a/projects/aca-playwright-shared/src/api/search-api.ts b/projects/aca-playwright-shared/src/api/search-api.ts index 70c9b1e77..a80243183 100755 --- a/projects/aca-playwright-shared/src/api/search-api.ts +++ b/projects/aca-playwright-shared/src/api/search-api.ts @@ -24,16 +24,16 @@ import { ApiClientFactory } from './api-client-factory'; import { Utils } from '../utils'; -import { ResultSetPaging } from '@alfresco/js-api'; +import { ResultSetPaging, SearchRequest } from '@alfresco/js-api'; -export class SearchPageApi { +export class SearchApi { private readonly apiService: ApiClientFactory; constructor() { this.apiService = new ApiClientFactory(); } - static async initialize(userName: string, password?: string): Promise { - const classObj = new SearchPageApi(); + static async initialize(userName: string, password?: string): Promise { + const classObj = new SearchApi(); await classObj.apiService.setUpAcaBackend(userName, password); return classObj; } @@ -76,4 +76,46 @@ export class SearchPageApi { return await Utils.retryCall(searchFiles); } catch {} } + + async waitForFolderPathIndexing(folderId: string, options: { nodesExpected: number }, maxRetries?: number): Promise { + try { + const query: SearchRequest = { + query: { + query: `ANCESTOR:'workspace://SpacesStore/${folderId}' and TYPE:content`, + language: 'afts' + } + }; + + const retryLimit = maxRetries ?? 100; + let retryCount = 0; + let result: ResultSetPaging; + + do { + result = await this.apiService.search.search(query); + const currentCount = result.list.pagination.count; + + if (currentCount !== options.nodesExpected) { + retryCount++; + + if (retryCount % 30 === 0) { + console.info( + `waitForFolderPathIndexing: After ${retryCount} seconds, expected ${options.nodesExpected} nodes but found ${currentCount} in folder ${folderId}` + ); + } + + if (retryCount >= retryLimit) { + throw new Error(`Expected ${options.nodesExpected} nodes but found ${currentCount} after ${retryLimit} retries`); + } + + await Utils.delayInSeconds(1); + } + } while (result.list.pagination.count !== options.nodesExpected); + + console.info(`waitForFolderPathIndexing: Found expected ${options.nodesExpected} nodes in folder ${folderId}`); + return result.list.pagination.count; + } catch (error) { + console.error(`waitForFolderPathIndexing failed for folderId "${folderId}": ${error}`); + throw error; + } + } } diff --git a/projects/aca-playwright-shared/src/base-config/report-portal.config.ts b/projects/aca-playwright-shared/src/base-config/report-portal.config.ts index 3b037f3c7..eff879dc5 100644 --- a/projects/aca-playwright-shared/src/base-config/report-portal.config.ts +++ b/projects/aca-playwright-shared/src/base-config/report-portal.config.ts @@ -47,7 +47,8 @@ export const getReportPortalConfig = () => { includeTestSteps: true, skipPassed: true, restClientConfig: { - timeout: timeouts.extendedTest + timeout: timeouts.sixtySeconds, + retry: 0 }, attributes, description: `[Run ${env.GITHUB_RUN_ID}](${env.GITHUB_SERVER_URL}/${env.GITHUB_REPOSITORY}/actions/runs/${env.GITHUB_RUN_ID}) - ${browser} - Failures only` diff --git a/projects/aca-playwright-shared/src/page-objects/components/dataTable/data-table.component.ts b/projects/aca-playwright-shared/src/page-objects/components/dataTable/data-table.component.ts index a5b13fa3f..b172a0238 100644 --- a/projects/aca-playwright-shared/src/page-objects/components/dataTable/data-table.component.ts +++ b/projects/aca-playwright-shared/src/page-objects/components/dataTable/data-table.component.ts @@ -55,6 +55,7 @@ export class DataTableComponent extends BaseComponent { searchFileName = '.search-file-name'; searchFileDescription = '[data-automation-id="search-results-entry-description"]'; searchFileContent = '.aca-result-content'; + noPermissionsView = this.page.locator('aca-generic-error'); /** Locator for row (or rows) */ getRowLocator = this.page.getByRole('rowgroup').nth(1).locator('adf-datatable-row'); diff --git a/projects/aca-playwright-shared/src/page-objects/components/dialogs/manage-versions-dialog.component.ts b/projects/aca-playwright-shared/src/page-objects/components/dialogs/manage-versions-dialog.component.ts index dbd06910f..cc90c64a6 100755 --- a/projects/aca-playwright-shared/src/page-objects/components/dialogs/manage-versions-dialog.component.ts +++ b/projects/aca-playwright-shared/src/page-objects/components/dialogs/manage-versions-dialog.component.ts @@ -28,9 +28,30 @@ import { BaseComponent } from '../base.component'; export class ManageVersionsDialog extends BaseComponent { private static readonly rootElement = '.adf-new-version-uploader-dialog'; - async viewFileVersion(version: string): Promise { - const versionActionsButton = this.getChild(`[id="adf-version-list-action-menu-button-${version}"]`); - await versionActionsButton.click(); + async clickListActionButtonForVersion(version: string): Promise { + await this.getChild(`[id="adf-version-list-action-menu-button-${version}"]`).click(); + } + + async isVersionPresent(version: string): Promise { + return this.getChild(`[id="adf-version-list-item-version-${version}"]`).isVisible(); + } + + async isDescriptionPresent(version: string): Promise { + return this.getChild(`[id="adf-version-list-item-comment-${version}"]`).isVisible(); + } + + async waitForProgressBarToDisappear(attachedTimeout = 5000): Promise { + const loadingBar = this.getChild('[data-automation-id="version-history-loading-bar"]'); + try { + await loadingBar.waitFor({ state: 'attached', timeout: attachedTimeout }); + } catch { + return; + } + await loadingBar.waitFor({ state: 'detached' }); + } + + async waitForDialog(): Promise { + await this.page.locator('[data-automation-id="new-version-uploader-dialog-title"]').waitFor(); } constructor(page: Page) { diff --git a/projects/aca-playwright-shared/src/page-objects/components/viewer.component.ts b/projects/aca-playwright-shared/src/page-objects/components/viewer.component.ts index 5b89be4d7..ee0cc47d2 100644 --- a/projects/aca-playwright-shared/src/page-objects/components/viewer.component.ts +++ b/projects/aca-playwright-shared/src/page-objects/components/viewer.component.ts @@ -32,7 +32,7 @@ export class ViewerComponent extends BaseComponent { public viewerLocator = this.getChild('adf-viewer-render'); public closeButtonLocator = this.getChild('.adf-viewer-close-button'); - public fileTitleButtonLocator = this.getChild('.adf-viewer__file-title'); + public fileTitleButtonLocator = this.getChild('#adf-viewer-display-name'); public pdfViewerContentPages = this.getChild('.adf-pdf-viewer__content .page'); public shareButton = this.getChild('button[id="share-action-button"]'); public downloadButton = this.getChild('button[id="app.viewer.download"]'); @@ -50,6 +50,9 @@ export class ViewerComponent extends BaseComponent { public zoomScale = this.getChild('[data-automation-id="adf-page-scale"]'); public zoomResetButton = this.getChild('#viewer-reset-button'); public fitToPageButton = this.getChild('#viewer-scale-page-button'); + public nextFileButton = this.getChild('[data-automation-id="adf-toolbar-next-file"]'); + public previousFileButton = this.getChild('[data-automation-id="adf-toolbar-pref-file"]'); + public noPermissionsView = this.getChild('aca-generic-error'); toolbar = new AcaHeader(this.page); @@ -67,10 +70,8 @@ export class ViewerComponent extends BaseComponent { return this.viewerLocator.isVisible(); } - async waitForViewerToOpen(waitForViewerContent?: 'wait for viewer content'): Promise { - if (waitForViewerContent) { - await this.waitForViewerLoaderToFinish(); - } + async waitForViewerToOpen(): Promise { + await this.waitForViewerLoaderToFinish(); await this.viewerLocator.waitFor({ state: 'visible', timeout: timeouts.large }); } diff --git a/projects/aca-playwright-shared/src/utils/utils.ts b/projects/aca-playwright-shared/src/utils/utils.ts index aa555c6f1..026e0b3b5 100644 --- a/projects/aca-playwright-shared/src/utils/utils.ts +++ b/projects/aca-playwright-shared/src/utils/utils.ts @@ -194,4 +194,8 @@ export class Utils { ) { await contentPage.page.waitForResponse((response) => response.url().includes(urlSubstring) && response.status() === statusCode); } + + static async delayInSeconds(seconds: number): Promise { + await new Promise((resolve) => setTimeout(resolve, seconds * 1000)); + } }