From bda0cf98f5722a3e9062b4c8c49e5228d4ad6f32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20=C5=9Awiderski?= Date: Wed, 8 Jul 2026 09:52:41 +0200 Subject: [PATCH] [ACS-12075] more multibrowser stabilization pt 3 (#5256) * [ACS-12075] more multibrowser stabilization pt 3 * [ACS-12075] copilot review fixes 1 * [ACS-12075] deploy local acs newest version test * [ACS-12075] deploy local acs newest version test 2 * [ACS-12075] deploy local acs newest version test 3 * [ACS-12075] Big batch of tests improvements * [ACS=12075] last batch of changes * [ACS-12075] viewer test download fixes * [ACS-12075] updated download funtionality in ACA with proper download name * [ACS-12075] reverted deploy local acs changes * [ACS-12075] updated playwright * [ACS-12075] deleted changes related to frontend + review fixes 4 * [ACS-12075] updated npm and node --- .../src/tests/create-rules.e2e.ts | 463 ++++++++++-------- .../src/tests/delete-view-rules.e2e.ts | 2 +- .../src/tests/transform-rules.e2e.ts | 6 +- .../src/tests/update-rules.e2e.ts | 9 +- .../navigation/src/tests/breadcrumb.e2e.ts | 228 +++++---- .../navigation/src/tests/sidebar.e2e.ts | 140 +++--- .../navigation/src/tests/single-click.e2e.ts | 141 ++++-- .../src/tests/search-highlighting.e2e.ts | 15 +- .../share/unshare-file-search-results.e2e.ts | 2 +- .../smoke-test/src/tests/viewer/viewer.e2e.ts | 11 +- .../tests/special-permissions-actions.e2e.ts | 2 +- .../src/tests/viewer-action.e2e.ts | 6 +- .../src/tests/viewer-version-actions.e2e.ts | 32 +- .../tests/viewer-zoom-functionality.e2e.ts | 2 +- e2e/playwright/viewer/src/tests/viewer.e2e.ts | 2 +- package-lock.json | 2 +- package.json | 2 +- .../src/api/api-client-factory.ts | 4 +- .../src/api/file-actions.ts | 11 +- .../src/api/nodes-api.ts | 13 +- .../src/api/search-api.ts | 133 ++++- .../src/api/shared-links-api.ts | 4 +- .../src/api/sites-api.ts | 11 +- .../src/base-config/playwright.config.ts | 2 +- .../components/actions-dropdown.component.ts | 66 ++- .../breadcrumb/breadcrumb.component.ts | 2 +- .../components/conditions.component.ts | 23 + 27 files changed, 871 insertions(+), 463 deletions(-) diff --git a/e2e/playwright/folder-rules/src/tests/create-rules.e2e.ts b/e2e/playwright/folder-rules/src/tests/create-rules.e2e.ts index 09695e455..06f633f0e 100644 --- a/e2e/playwright/folder-rules/src/tests/create-rules.e2e.ts +++ b/e2e/playwright/folder-rules/src/tests/create-rules.e2e.ts @@ -25,7 +25,7 @@ import { expect } from '@playwright/test'; import { ActionType, ApiClientFactory, test, Utils, TrashcanApi, NodesApi, Comparator, Field } from '@alfresco/aca-playwright-shared'; -test.use({ launchOptions: { slowMo: 300 } }); +test.use({ launchOptions: { slowMo: 500 } }); test.describe('Folder Rules Actions', () => { const apiClientFactory = new ApiClientFactory(); @@ -82,29 +82,10 @@ test.describe('Folder Rules Actions', () => { nodesApi = await NodesApi.initialize(username, username); trashcanApi = await TrashcanApi.initialize(username, username); } catch (error) { - console.error(`beforeAll failed : ${error}`); - throw error; + const errorMessage = `beforeAll failed : ${JSON.stringify(error)}`; + console.error(errorMessage); + throw new Error(errorMessage); } - - folder883Id = (await nodesApi.createFolder(folder883)).entry.id; - folder884Id = (await nodesApi.createFolder(folder884)).entry.id; - folder884SecondId = (await nodesApi.createFolder(folder884Second)).entry.id; - folder885Id = (await nodesApi.createFolder(folder885)).entry.id; - folder885ChildId = (await nodesApi.createFolder(folder885Child, folder885Id)).entry.id; - folder886Id = (await nodesApi.createFolder(folder886)).entry.id; - folder887Id = (await nodesApi.createFolder(folder887)).entry.id; - folder888Id = (await nodesApi.createFolder(folder888)).entry.id; - folder889Id = (await nodesApi.createFolder(folder889)).entry.id; - folder889SecondId = (await nodesApi.createFolder(folder889Second)).entry.id; - folder890Id = (await nodesApi.createFolder(folder890)).entry.id; - folder891Id = (await nodesApi.createFolder(folder891)).entry.id; - folder892Id = (await nodesApi.createFolder(folder892)).entry.id; - folder893Id = (await nodesApi.createFolder(folder893)).entry.id; - folder894Id = (await nodesApi.createFolder(folder894)).entry.id; - folder895Id = (await nodesApi.createFolder(folder895)).entry.id; - folder896Id = (await nodesApi.createFolder(folder896)).entry.id; - folder910Id = (await nodesApi.createFolder(folder910)).entry.id; - await nodesApi.createFile(copyFileName, folder889Id); }); test.beforeEach(async ({ loginPage }) => { @@ -116,219 +97,309 @@ test.describe('Folder Rules Actions', () => { await Utils.deleteNodesSitesEmptyTrashcan(nodesApi, trashcanApi, 'afterAll failed'); }); - test('[XAT-883] Create a rule with symbols in its name and description', async ({ personalFiles, nodesPage }) => { - await personalFiles.navigate({ remoteUrl: `#/nodes/${folder883Id}/rules` }); - await nodesPage.rulesToolbar.clickCreateRuleButton(); - await nodesPage.manageRulesDialog.ruleNameInputLocator.fill(testString); - await nodesPage.manageRulesDialog.ruleDescriptionInputLocator.fill(testString); + test.describe('[XAT-883] - Folder Rules Actions', () => { + test.beforeAll(async () => { + folder883Id = (await nodesApi.createFolder(folder883)).entry.id; + }); - await nodesPage.actionsDropdown.selectAction(ActionType.IncrementCounter, 0); - await nodesPage.manageRulesDialog.createRuleButton.click(); + test('[XAT-883] Create a rule with symbols in its name and description', async ({ personalFiles, nodesPage }) => { + await personalFiles.navigate({ remoteUrl: `#/nodes/${folder883Id}/rules` }); + await nodesPage.rulesToolbar.clickCreateRuleButton(); + await nodesPage.manageRulesDialog.ruleNameInputLocator.fill(testString); + await nodesPage.manageRulesDialog.ruleDescriptionInputLocator.fill(testString); - await expect(nodesPage.manageRules.getGroupsList(testString)).toBeVisible(); + await nodesPage.actionsDropdown.selectActions([ActionType.IncrementCounter]); + await nodesPage.manageRulesDialog.createRuleButton.click(); + + await expect(nodesPage.manageRules.getGroupsList(testString)).toBeVisible(); + }); }); - test('[XAT-884] Create a rule and link it to an existing folder', async ({ personalFiles, nodesPage }) => { - await personalFiles.navigate({ remoteUrl: `#/nodes/${folder884Id}/rules` }); - await nodesPage.rulesToolbar.clickCreateRuleButton(); - await nodesPage.manageRulesDialog.ruleNameInputLocator.fill(randomRuleName); - await nodesPage.actionsDropdown.selectAction(ActionType.IncrementCounter, 0); - await nodesPage.manageRulesDialog.createRuleButton.click(); + test.describe('[XAT-884] - Folder Rules Actions', () => { + test.beforeAll(async () => { + folder884Id = (await nodesApi.createFolder(folder884)).entry.id; + folder884SecondId = (await nodesApi.createFolder(folder884Second)).entry.id; + }); - await personalFiles.navigate({ remoteUrl: `#/nodes/${folder884SecondId}/rules` }); - await nodesPage.rulesToolbar.clickLinkRulesButton(); - await nodesPage.linkRulesDialog.waitForLinkRules(); - await nodesPage.linkRulesDialog.getFolderIcon.click(); - await nodesPage.linkRulesDialog.getOptionLocator(username).click(); - await nodesPage.linkRulesDialog.selectDestination(folder884); - await nodesPage.linkRulesDialog.selectFolderButton.click(); + test('[XAT-884] Create a rule and link it to an existing folder', async ({ personalFiles, nodesPage }) => { + await personalFiles.navigate({ remoteUrl: `#/nodes/${folder884Id}/rules` }); + await nodesPage.rulesToolbar.clickCreateRuleButton(); + await nodesPage.manageRulesDialog.ruleNameInputLocator.fill(randomRuleName); + await nodesPage.actionsDropdown.selectActions([ActionType.IncrementCounter]); + await nodesPage.manageRulesDialog.createRuleButton.click(); - await nodesPage.manageRules.checkIfRuleIsOnTheList(randomRuleName); + await personalFiles.navigate({ remoteUrl: `#/nodes/${folder884SecondId}/rules` }); + await nodesPage.rulesToolbar.clickLinkRulesButton(); + await nodesPage.linkRulesDialog.waitForLinkRules(); + await nodesPage.linkRulesDialog.getFolderIcon.click(); + await nodesPage.linkRulesDialog.getOptionLocator(username).click(); + await nodesPage.linkRulesDialog.selectDestination(folder884); + await nodesPage.linkRulesDialog.selectFolderButton.click(); + + await nodesPage.manageRules.checkIfRuleIsOnTheList(randomRuleName); + }); }); - test('[XAT-885] Create a rule in a folder and inherit it in a subfolder (Rule applies to subfolders)', async ({ personalFiles, nodesPage }) => { - await personalFiles.navigate({ remoteUrl: `#/nodes/${folder885Id}/rules` }); - await nodesPage.rulesToolbar.clickCreateRuleButton(); - await nodesPage.manageRulesDialog.ruleNameInputLocator.fill(randomRuleName); - await nodesPage.actionsDropdown.selectAction(ActionType.IncrementCounter, 0); - await nodesPage.manageRulesDialog.ruleSubfoldersCheckbox.click(); - await nodesPage.manageRulesDialog.createRuleButton.click(); + test.describe('[XAT-885] - Folder Rules Actions', () => { + test.beforeAll(async () => { + folder885Id = (await nodesApi.createFolder(folder885)).entry.id; + folder885ChildId = (await nodesApi.createFolder(folder885Child, folder885Id)).entry.id; + }); - await personalFiles.navigate({ remoteUrl: `#/nodes/${folder885ChildId}/rules` }); - await nodesPage.manageRules.checkIfRuleIsOnTheList(randomRuleName); + test('[XAT-885] Create a rule in a folder and inherit it in a subfolder (Rule applies to subfolders)', async ({ personalFiles, nodesPage }) => { + await personalFiles.navigate({ remoteUrl: `#/nodes/${folder885Id}/rules` }); + await nodesPage.rulesToolbar.clickCreateRuleButton(); + await nodesPage.manageRulesDialog.ruleNameInputLocator.fill(randomRuleName); + await nodesPage.actionsDropdown.selectActions([ActionType.IncrementCounter]); + await nodesPage.manageRulesDialog.ruleSubfoldersCheckbox.click(); + await nodesPage.manageRulesDialog.createRuleButton.click(); + + await personalFiles.navigate({ remoteUrl: `#/nodes/${folder885ChildId}/rules` }); + await nodesPage.manageRules.checkIfRuleIsOnTheList(randomRuleName); + }); }); - test('[XAT-886] Create a rule and press cancel', async ({ personalFiles, nodesPage }) => { - await personalFiles.navigate({ remoteUrl: `#/nodes/${folder886Id}/rules` }); - await nodesPage.rulesToolbar.clickCreateRuleButton(); - await expect(nodesPage.manageRulesDialog.createRuleButton).toBeDisabled(); - await nodesPage.manageRulesDialog.cancelRuleButton.click(); - expect(await nodesPage.manageRules.checkIfRuleListEmpty()).toBe(true); + test.describe('[XAT-886] - Folder Rules Actions', () => { + test.beforeAll(async () => { + folder886Id = (await nodesApi.createFolder(folder886)).entry.id; + }); + + test('[XAT-886] Create a rule and press cancel', async ({ personalFiles, nodesPage }) => { + await personalFiles.navigate({ remoteUrl: `#/nodes/${folder886Id}/rules` }); + await nodesPage.rulesToolbar.clickCreateRuleButton(); + await expect(nodesPage.manageRulesDialog.createRuleButton).toBeDisabled(); + await nodesPage.manageRulesDialog.cancelRuleButton.click(); + expect(await nodesPage.manageRules.checkIfRuleListEmpty()).toBe(true); + }); }); - test('[XAT-887] Create a disabled rule', async ({ personalFiles, nodesPage }) => { - await personalFiles.navigate({ remoteUrl: `#/nodes/${folder887Id}/rules` }); - await nodesPage.rulesToolbar.clickCreateRuleButton(); - await nodesPage.manageRulesDialog.ruleNameInputLocator.fill(randomRuleName); - await nodesPage.actionsDropdown.selectAction(ActionType.IncrementCounter, 0); - await nodesPage.manageRulesDialog.ruleDisableCheckbox.click(); - await nodesPage.manageRulesDialog.createRuleButton.click(); - await expect(nodesPage.manageRules.ruleToggleFalse).toBeVisible(); + test.describe('[XAT-887] - Folder Rules Actions', () => { + test.beforeAll(async () => { + folder887Id = (await nodesApi.createFolder(folder887)).entry.id; + }); + + test('[XAT-887] Create a disabled rule', async ({ personalFiles, nodesPage }) => { + await personalFiles.navigate({ remoteUrl: `#/nodes/${folder887Id}/rules` }); + await nodesPage.rulesToolbar.clickCreateRuleButton(); + await nodesPage.manageRulesDialog.ruleNameInputLocator.fill(randomRuleName); + await nodesPage.actionsDropdown.selectActions([ActionType.IncrementCounter]); + await nodesPage.manageRulesDialog.ruleDisableCheckbox.click(); + await nodesPage.manageRulesDialog.createRuleButton.click(); + await expect(nodesPage.manageRules.ruleToggleFalse).toBeVisible(); + }); }); - test('[XAT-888] Create a rule with multiple actions', async ({ personalFiles, nodesPage }) => { - const checkInValue = 'check In Value'; - const actionValue = 'Site Container [st:siteContainer]'; - const specialiseTypeValue = 'Action Base Type [act:actionbase]'; - const simpleWorkFlow = 'accept reject'; + test.describe('[XAT-888] - Folder Rules Actions', () => { + test.beforeAll(async () => { + folder888Id = (await nodesApi.createFolder(folder888)).entry.id; + }); - await personalFiles.navigate({ remoteUrl: `#/nodes/${folder888Id}/rules` }); - await nodesPage.rulesToolbar.clickCreateRuleButton(); - await nodesPage.manageRulesDialog.ruleNameInputLocator.fill(randomRuleName); + test('[XAT-888] Create a rule with multiple actions', async ({ personalFiles, nodesPage }) => { + const checkInValue = 'check In Value'; + const actionValue = 'Site Container [st:siteContainer]'; + const specialiseTypeValue = 'Action Base Type [act:actionbase]'; + const simpleWorkFlow = 'accept reject'; - await nodesPage.actionsDropdown.selectAction(ActionType.IncrementCounter, 0); - await nodesPage.actionsDropdown.selectAction(ActionType.CheckIn, 1); - await nodesPage.actionsDropdown.insertCheckInActionValues(checkInValue, 1); - await nodesPage.actionsDropdown.selectAction(ActionType.AddAspect, 2); - await nodesPage.actionsDropdown.insertAddAspectActionValues(actionValue, 2); - await nodesPage.actionsDropdown.selectAction(ActionType.SpecialiseType, 3); - await nodesPage.actionsDropdown.insertSpecialiseTypeActionValues(specialiseTypeValue, 3); - await nodesPage.actionsDropdown.selectAction(ActionType.SimpleWorkflow, 4); - await nodesPage.actionsDropdown.insertSimpleWorkflowActionValues(simpleWorkFlow, 4); + await personalFiles.navigate({ remoteUrl: `#/nodes/${folder888Id}/rules` }); + await nodesPage.rulesToolbar.clickCreateRuleButton(); + await nodesPage.manageRulesDialog.ruleNameInputLocator.fill(randomRuleName); - await nodesPage.manageRulesDialog.createRuleButton.click(); + await nodesPage.actionsDropdown.selectActions([ + ActionType.IncrementCounter, + { type: ActionType.CheckIn, value: checkInValue }, + { type: ActionType.AddAspect, value: actionValue }, + { type: ActionType.SpecialiseType, value: specialiseTypeValue }, + { type: ActionType.SimpleWorkflow, value: simpleWorkFlow } + ]); - await nodesPage.manageRules.checkIfRuleIsOnTheList(randomRuleName); + await nodesPage.manageRulesDialog.createRuleButton.click(); + + await nodesPage.manageRules.checkIfRuleIsOnTheList(randomRuleName); + }); }); - test('[XAT-889] Create a rule which runs when items are deleted or leave a folder', async ({ nodesPage, personalFiles }) => { - await personalFiles.navigate({ remoteUrl: `#/nodes/${folder889Id}/rules` }); - await nodesPage.rulesToolbar.clickCreateRuleButton(); - await nodesPage.manageRulesDialog.ruleNameInputLocator.fill(randomRuleName); - await nodesPage.manageRulesDialog.whenCreatedCheckbox.click(); - await nodesPage.manageRulesDialog.whenDeletedCheckbox.click(); - await nodesPage.actionsDropdown.selectAction(ActionType.Copy, 0); - await nodesPage.manageRulesDialog.destinationFolderButton.click(); - await nodesPage.contentNodeSelectorDialog.getFolderIcon.click(); - await nodesPage.contentNodeSelectorDialog.getOptionLocator(username).click(); - await nodesPage.contentNodeSelectorDialog.selectDestination(folder889Second); - await nodesPage.contentNodeSelectorDialog.actionButton.click(); - await nodesPage.manageRulesDialog.createRuleButton.click(); - await nodesPage.manageRules.checkIfRuleIsOnTheList(randomRuleName); + test.describe('[XAT-889] - Folder Rules Actions', () => { + test.beforeAll(async () => { + folder889Id = (await nodesApi.createFolder(folder889)).entry.id; + folder889SecondId = (await nodesApi.createFolder(folder889Second)).entry.id; + await nodesApi.createFile(copyFileName, folder889Id); + }); - await personalFiles.navigate({ remoteUrl: `#/personal-files/${folder889Id}` }); - await personalFiles.dataTable.selectItems(copyFileName); - await personalFiles.acaHeader.clickMoreActions(); - await personalFiles.acaHeader.matMenu.clickMenuItem('Delete'); - await personalFiles.snackBar.message.waitFor({ state: 'visible' }); + test('[XAT-889] Create a rule which runs when items are deleted or leave a folder', async ({ nodesPage, personalFiles }) => { + await personalFiles.navigate({ remoteUrl: `#/nodes/${folder889Id}/rules` }); + await nodesPage.rulesToolbar.clickCreateRuleButton(); + await nodesPage.manageRulesDialog.ruleNameInputLocator.fill(randomRuleName); + await nodesPage.manageRulesDialog.whenCreatedCheckbox.click(); + await nodesPage.manageRulesDialog.whenDeletedCheckbox.click(); + await nodesPage.actionsDropdown.selectActions([ActionType.Copy]); + await nodesPage.manageRulesDialog.destinationFolderButton.click(); + await nodesPage.contentNodeSelectorDialog.getFolderIcon.click(); + await nodesPage.contentNodeSelectorDialog.getOptionLocator(username).click(); + await nodesPage.contentNodeSelectorDialog.selectDestination(folder889Second); + await nodesPage.contentNodeSelectorDialog.actionButton.click(); + await nodesPage.manageRulesDialog.createRuleButton.click(); + await nodesPage.manageRules.checkIfRuleIsOnTheList(randomRuleName); - await personalFiles.navigate({ remoteUrl: `#/personal-files/${folder889SecondId}` }); - await expect(personalFiles.dataTable.getRowByName(copyFileName)).toBeVisible(); + await personalFiles.navigate({ remoteUrl: `#/personal-files/${folder889Id}` }); + await personalFiles.dataTable.selectItems(copyFileName); + await personalFiles.acaHeader.clickMoreActions(); + await personalFiles.acaHeader.matMenu.clickMenuItem('Delete'); + await personalFiles.snackBar.message.waitFor({ state: 'visible' }); + + await personalFiles.navigate({ remoteUrl: `#/personal-files/${folder889SecondId}` }); + await expect(personalFiles.dataTable.getRowByName(copyFileName)).toBeVisible(); + }); }); - test('[XAT-890] Create a rule which adds multiple aspects when its ran', async ({ nodesPage, personalFiles }) => { - await personalFiles.navigate({ remoteUrl: `#/nodes/${folder890Id}/rules` }); - await nodesPage.rulesToolbar.clickCreateRuleButton(); - await nodesPage.manageRulesDialog.ruleNameInputLocator.fill(randomRuleName); - await nodesPage.actionsDropdown.selectAction(ActionType.AddAspect, 0); - await nodesPage.actionsDropdown.insertAddAspectActionValues('Classifiable', 0); - await nodesPage.actionsDropdown.selectAction(ActionType.AddAspect, 1); - await nodesPage.actionsDropdown.insertAddAspectActionValues('Countable', 1); - await nodesPage.actionsDropdown.selectAction(ActionType.AddAspect, 2); - await nodesPage.actionsDropdown.insertAddAspectActionValues('Incomplete', 2); - await nodesPage.actionsDropdown.selectAction(ActionType.AddAspect, 3); - await nodesPage.actionsDropdown.insertAddAspectActionValues('Site container', 3); - await nodesPage.manageRulesDialog.createRuleButton.click(); - await nodesPage.manageRulesDialog.createRuleButton.waitFor({ state: 'hidden' }); - await expect(nodesPage.manageRules.getGroupsList(randomRuleName)).toBeVisible(); + test.describe('[XAT-890] - Folder Rules Actions', () => { + test.beforeAll(async () => { + folder890Id = (await nodesApi.createFolder(folder890)).entry.id; + }); + + test('[XAT-890] Create a rule which adds multiple aspects when its ran', async ({ nodesPage, personalFiles }) => { + await personalFiles.navigate({ remoteUrl: `#/nodes/${folder890Id}/rules` }); + await nodesPage.rulesToolbar.clickCreateRuleButton(); + await nodesPage.manageRulesDialog.ruleNameInputLocator.fill(randomRuleName); + await nodesPage.actionsDropdown.selectActions([ + { type: ActionType.AddAspect, value: 'Classifiable' }, + { type: ActionType.AddAspect, value: 'Countable' }, + { type: ActionType.AddAspect, value: 'Incomplete' }, + { type: ActionType.AddAspect, value: 'Site container' } + ]); + await nodesPage.manageRulesDialog.createRuleButton.click(); + await nodesPage.manageRulesDialog.createRuleButton.waitFor({ state: 'hidden' }); + await expect(nodesPage.manageRules.getGroupsList(randomRuleName)).toBeVisible(); + }); }); - test('[XAT-891] Prevent rule creation after clicking on cancel during selecting destination folder', async ({ nodesPage, personalFiles }) => { - await personalFiles.navigate({ remoteUrl: `#/nodes/${folder891Id}/rules` }); - await nodesPage.rulesToolbar.clickCreateRuleButton(); - await nodesPage.manageRulesDialog.ruleNameInputLocator.fill(randomRuleName); - await nodesPage.actionsDropdown.selectAction(ActionType.AddAspect, 0); - await nodesPage.actionsDropdown.insertAddAspectActionValues('Classifiable', 0); - await expect(nodesPage.manageRulesDialog.createRuleButton).toBeEnabled(); - await nodesPage.actionsDropdown.selectAction(ActionType.Copy, 1); - await nodesPage.manageRulesDialog.destinationFolderButton.click(); - await nodesPage.contentNodeSelectorDialog.cancelButton.click(); - await expect(nodesPage.manageRulesDialog.createRuleButton).toBeDisabled(); + test.describe('[XAT-891] - Folder Rules Actions', () => { + test.beforeAll(async () => { + folder891Id = (await nodesApi.createFolder(folder891)).entry.id; + }); + + test('[XAT-891] Prevent rule creation after clicking on cancel during selecting destination folder', async ({ nodesPage, personalFiles }) => { + await personalFiles.navigate({ remoteUrl: `#/nodes/${folder891Id}/rules` }); + await nodesPage.rulesToolbar.clickCreateRuleButton(); + await nodesPage.manageRulesDialog.ruleNameInputLocator.fill(randomRuleName); + await nodesPage.actionsDropdown.selectActions([{ type: ActionType.AddAspect, value: 'Classifiable' }]); + await expect(nodesPage.manageRulesDialog.createRuleButton).toBeEnabled(); + await nodesPage.actionsDropdown.selectActions([ActionType.Copy]); + await nodesPage.manageRulesDialog.destinationFolderButton.click(); + await nodesPage.contentNodeSelectorDialog.cancelButton.click(); + await expect(nodesPage.manageRulesDialog.createRuleButton).toBeDisabled(); + }); }); - test('[XAT-892] Prevent rule creation when missing any required field for action', async ({ nodesPage, personalFiles }) => { - await personalFiles.navigate({ remoteUrl: `#/nodes/${folder892Id}/rules` }); - await nodesPage.rulesToolbar.clickCreateRuleButton(); - await nodesPage.manageRulesDialog.ruleNameInputLocator.fill(randomRuleName); - await nodesPage.actionsDropdown.selectAction(ActionType.AddAspect, 0); - await nodesPage.actionsDropdown.insertAddAspectActionValues('Classifiable', 0); - await expect(nodesPage.manageRulesDialog.createRuleButton).toBeEnabled(); - await nodesPage.actionsDropdown.selectAction(ActionType.Copy, 1); - await expect(nodesPage.manageRulesDialog.createRuleButton).toBeDisabled(); + test.describe('[XAT-892] - Folder Rules Actions', () => { + test.beforeAll(async () => { + folder892Id = (await nodesApi.createFolder(folder892)).entry.id; + }); + + test('[XAT-892] Prevent rule creation when missing any required field for action', async ({ nodesPage, personalFiles }) => { + await personalFiles.navigate({ remoteUrl: `#/nodes/${folder892Id}/rules` }); + await nodesPage.rulesToolbar.clickCreateRuleButton(); + await nodesPage.manageRulesDialog.ruleNameInputLocator.fill(randomRuleName); + await nodesPage.actionsDropdown.selectActions([{ type: ActionType.AddAspect, value: 'Classifiable' }]); + await expect(nodesPage.manageRulesDialog.createRuleButton).toBeEnabled(); + await nodesPage.actionsDropdown.selectActions([ActionType.Copy]); + await expect(nodesPage.manageRulesDialog.createRuleButton).toBeDisabled(); + }); }); - test('[XAT-893] Removing values from required fields should restore disabled state for Create button', async ({ nodesPage, personalFiles }) => { - await personalFiles.navigate({ remoteUrl: `#/nodes/${folder893Id}/rules` }); - await nodesPage.rulesToolbar.clickCreateRuleButton(); - await nodesPage.manageRulesDialog.ruleNameInputLocator.fill(randomRuleName); - await nodesPage.actionsDropdown.selectAction(ActionType.AddAspect, 0); - await nodesPage.actionsDropdown.insertAddAspectActionValues('Classifiable', 0); - await expect(nodesPage.manageRulesDialog.createRuleButton).toBeEnabled(); - await nodesPage.actionsDropdown.insertAddAspectActionValues('None', 0); - await expect(nodesPage.manageRulesDialog.createRuleButton).toBeDisabled(); + test.describe('[XAT-893] - Folder Rules Actions', () => { + test.beforeAll(async () => { + folder893Id = (await nodesApi.createFolder(folder893)).entry.id; + }); + + test('[XAT-893] Removing values from required fields should restore disabled state for Create button', async ({ nodesPage, personalFiles }) => { + await personalFiles.navigate({ remoteUrl: `#/nodes/${folder893Id}/rules` }); + await nodesPage.rulesToolbar.clickCreateRuleButton(); + await nodesPage.manageRulesDialog.ruleNameInputLocator.fill(randomRuleName); + await nodesPage.actionsDropdown.selectActions([{ type: ActionType.AddAspect, value: 'Classifiable' }]); + await expect(nodesPage.manageRulesDialog.createRuleButton).toBeEnabled(); + await nodesPage.actionsDropdown.insertAddAspectActionValues('None', 0); + await expect(nodesPage.manageRulesDialog.createRuleButton).toBeDisabled(); + }); }); - test('[XAT-894] Create rule with filled required fields and empty optional fields', async ({ nodesPage, personalFiles }) => { - await personalFiles.navigate({ remoteUrl: `#/nodes/${folder894Id}/rules` }); - await nodesPage.rulesToolbar.clickCreateRuleButton(); - await nodesPage.manageRulesDialog.ruleNameInputLocator.fill(randomRuleName); - await nodesPage.actionsDropdown.selectAction(ActionType.AddAspect, 0); - await nodesPage.actionsDropdown.insertAddAspectActionValues('Classifiable', 0); - await expect(nodesPage.manageRulesDialog.createRuleButton).toBeEnabled(); - await nodesPage.actionsDropdown.selectAction(ActionType.CheckIn, 1); - await expect(nodesPage.manageRulesDialog.createRuleButton).toBeEnabled(); + test.describe('[XAT-894] - Folder Rules Actions', () => { + test.beforeAll(async () => { + folder894Id = (await nodesApi.createFolder(folder894)).entry.id; + }); + + test('[XAT-894] Create rule with filled required fields and empty optional fields', async ({ nodesPage, personalFiles }) => { + await personalFiles.navigate({ remoteUrl: `#/nodes/${folder894Id}/rules` }); + await nodesPage.rulesToolbar.clickCreateRuleButton(); + await nodesPage.manageRulesDialog.ruleNameInputLocator.fill(randomRuleName); + await nodesPage.actionsDropdown.selectActions([{ type: ActionType.AddAspect, value: 'Classifiable' }]); + await expect(nodesPage.manageRulesDialog.createRuleButton).toBeEnabled(); + await nodesPage.actionsDropdown.selectActions([ActionType.CheckIn]); + await expect(nodesPage.manageRulesDialog.createRuleButton).toBeEnabled(); + }); }); - test('[XAT-895] Create a rule with multiple conditions utilising all available comparators and conditions', async ({ - personalFiles, - nodesPage - }) => { - await personalFiles.navigate({ remoteUrl: `#/nodes/${folder895Id}/rules` }); - await nodesPage.rulesToolbar.clickCreateRuleButton(); - await nodesPage.manageRulesDialog.ruleNameInputLocator.fill(randomRuleName); - await nodesPage.conditionsDropdown.addCondition(Field.Size, specialChars, 0, Comparator.Equals); - await nodesPage.conditionsDropdown.addCondition(Field.Name, specialChars, 1, Comparator.Equals); - await nodesPage.conditionsDropdown.addCondition(Field.Encoding, specialChars, 2); - await nodesPage.conditionsDropdown.addCondition(Field.HasTag, specialChars, 3); - await nodesPage.conditionsDropdown.addCondition(Field.HasAspect, specialChars, 4); - await nodesPage.actionsDropdown.selectAction(ActionType.IncrementCounter, 0); - await nodesPage.manageRulesDialog.createRuleButton.click(); + test.describe('[XAT-895] - Folder Rules Actions', () => { + test.beforeAll(async () => { + folder895Id = (await nodesApi.createFolder(folder895)).entry.id; + }); - await nodesPage.manageRules.checkIfRuleIsOnTheList(randomRuleName); + test('[XAT-895] Create a rule with multiple conditions utilising all available comparators and conditions', async ({ + personalFiles, + nodesPage + }) => { + await personalFiles.navigate({ remoteUrl: `#/nodes/${folder895Id}/rules` }); + await nodesPage.rulesToolbar.clickCreateRuleButton(); + await nodesPage.manageRulesDialog.ruleNameInputLocator.fill(randomRuleName); + await nodesPage.conditionsDropdown.addConditions([ + { field: Field.Size, value: specialChars, comparator: Comparator.Equals }, + { field: Field.Name, value: specialChars, comparator: Comparator.Equals }, + { field: Field.Encoding, value: specialChars }, + { field: Field.HasTag, value: specialChars }, + { field: Field.HasAspect, value: specialChars } + ]); + await nodesPage.actionsDropdown.selectActions([ActionType.IncrementCounter]); + await nodesPage.manageRulesDialog.createRuleButton.click(); + + await nodesPage.manageRules.checkIfRuleIsOnTheList(randomRuleName); + }); }); - test('[XAT-896] Create a rule with multiple groups utilising all available comparators and conditions', async ({ personalFiles, nodesPage }) => { - await personalFiles.navigate({ remoteUrl: `#/nodes/${folder896Id}/rules` }); - await nodesPage.rulesToolbar.clickCreateRuleButton(); - await nodesPage.manageRulesDialog.ruleNameInputLocator.fill(randomRuleName); - await nodesPage.conditionsDropdown.addConditionGroup(Field.Size, specialChars, 0, Comparator.Equals); - await nodesPage.conditionsDropdown.addConditionGroup(Field.Name, specialChars, 1, Comparator.Equals); - await nodesPage.conditionsDropdown.addConditionGroup(Field.Encoding, specialChars, 2); - await nodesPage.conditionsDropdown.addConditionGroup(Field.HasTag, specialChars, 3); - await nodesPage.conditionsDropdown.addConditionGroup(Field.HasAspect, specialChars, 4); - await nodesPage.actionsDropdown.selectAction(ActionType.IncrementCounter, 0); - await nodesPage.manageRulesDialog.createRuleButton.click(); + test.describe('[XAT-896] - Folder Rules Actions', () => { + test.beforeAll(async () => { + folder896Id = (await nodesApi.createFolder(folder896)).entry.id; + }); - await nodesPage.manageRules.checkIfRuleIsOnTheList(randomRuleName); + test('[XAT-896] Create a rule with multiple groups utilising all available comparators and conditions', async ({ personalFiles, nodesPage }) => { + await personalFiles.navigate({ remoteUrl: `#/nodes/${folder896Id}/rules` }); + await nodesPage.rulesToolbar.clickCreateRuleButton(); + await nodesPage.manageRulesDialog.ruleNameInputLocator.fill(randomRuleName); + await nodesPage.conditionsDropdown.addConditionGroups([ + { field: Field.Size, value: specialChars, comparator: Comparator.Equals }, + { field: Field.Name, value: specialChars, comparator: Comparator.Equals }, + { field: Field.Encoding, value: specialChars }, + { field: Field.HasTag, value: specialChars }, + { field: Field.HasAspect, value: specialChars } + ]); + await nodesPage.actionsDropdown.selectActions([ActionType.IncrementCounter]); + await nodesPage.manageRulesDialog.createRuleButton.click(); + + await nodesPage.manageRules.checkIfRuleIsOnTheList(randomRuleName); + }); }); - test('[XAT-910] Create a rule and disable it', async ({ personalFiles, nodesPage }) => { - await personalFiles.navigate({ remoteUrl: `#/nodes/${folder910Id}/rules` }); - await nodesPage.rulesToolbar.clickCreateRuleButton(); - await nodesPage.manageRulesDialog.ruleNameInputLocator.fill(randomRuleName); - await nodesPage.actionsDropdown.selectAction(ActionType.IncrementCounter, 0); - await nodesPage.manageRulesDialog.createRuleButton.click(); - await nodesPage.manageRules.ruleToggle.click(); - await expect(nodesPage.manageRules.ruleToggleFalse).toBeVisible(); + test.describe('[XAT-910] - Folder Rules Actions', () => { + test.beforeAll(async () => { + folder910Id = (await nodesApi.createFolder(folder910)).entry.id; + }); + + test('[XAT-910] Create a rule and disable it', async ({ personalFiles, nodesPage }) => { + await personalFiles.navigate({ remoteUrl: `#/nodes/${folder910Id}/rules` }); + await nodesPage.rulesToolbar.clickCreateRuleButton(); + await nodesPage.manageRulesDialog.ruleNameInputLocator.fill(randomRuleName); + await nodesPage.actionsDropdown.selectActions([ActionType.IncrementCounter]); + await nodesPage.manageRulesDialog.createRuleButton.click(); + await nodesPage.manageRules.ruleToggle.click(); + await expect(nodesPage.manageRules.ruleToggleFalse).toBeVisible(); + }); }); }); diff --git a/e2e/playwright/folder-rules/src/tests/delete-view-rules.e2e.ts b/e2e/playwright/folder-rules/src/tests/delete-view-rules.e2e.ts index 4761c0f85..c4dd87496 100644 --- a/e2e/playwright/folder-rules/src/tests/delete-view-rules.e2e.ts +++ b/e2e/playwright/folder-rules/src/tests/delete-view-rules.e2e.ts @@ -25,7 +25,7 @@ import { ApiClientFactory, test, Utils, NodesApi, TrashcanApi, RulesApi } 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(); diff --git a/e2e/playwright/folder-rules/src/tests/transform-rules.e2e.ts b/e2e/playwright/folder-rules/src/tests/transform-rules.e2e.ts index b42119a82..c75f3ae82 100644 --- a/e2e/playwright/folder-rules/src/tests/transform-rules.e2e.ts +++ b/e2e/playwright/folder-rules/src/tests/transform-rules.e2e.ts @@ -63,9 +63,7 @@ async function setupTransformationTest( await nodesPage.rulesToolbar.clickCreateRuleButton(); await nodesPage.manageRulesDialog.ruleNameInputLocator.fill(testString); await nodesPage.manageRulesDialog.ruleDescriptionInputLocator.fill(testString); - await nodesPage.actionsDropdown.selectAction(ActionType.TransformAndCopyContent, 0); - await nodesPage.actionsDropdown.selectMimeType(mimeType, 0); - await nodesPage.actionsDropdown.selectDestinationFolderTransformAndCopyContent(0, destinationFolderName); + await nodesPage.actionsDropdown.selectActions([{ type: ActionType.TransformAndCopyContent, mimeType, destinationFolder: destinationFolderName }]); await nodesPage.manageRulesDialog.createRuleButton.click(); await expect(nodesPage.manageRules.getGroupsList(testString)).toBeVisible(); return parentFolderId; @@ -105,7 +103,7 @@ async function verifyTransformation( } } -test.use({ launchOptions: { slowMo: 300 } }); +test.use({ launchOptions: { slowMo: 500 } }); test.describe('Folder Rules Actions', () => { const apiClientFactory = new ApiClientFactory(); 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 c7d5fd374..020150df2 100644 --- a/e2e/playwright/folder-rules/src/tests/update-rules.e2e.ts +++ b/e2e/playwright/folder-rules/src/tests/update-rules.e2e.ts @@ -128,7 +128,7 @@ test.describe('Rules - Manage Rules', () => { await nodesPage.manageRules.getGroupsList(randomRuleName899).click(); await nodesPage.manageRules.ruleDetailsEditButton.click(); await nodesPage.manageRulesDialog.deleteActions(2); - await nodesPage.actionsDropdown.selectAction(ActionType.IncrementCounter, 1); + await nodesPage.actionsDropdown.selectActions([ActionType.IncrementCounter]); await nodesPage.manageRulesDialog.createRuleButton.click(); await nodesPage.manageRulesDialog.createRuleButton.waitFor({ state: 'hidden' }); await nodesPage.manageRules.getGroupsList(randomRuleName899).click(); @@ -141,8 +141,7 @@ test.describe('Rules - Manage Rules', () => { await nodesPage.manageRules.getGroupsList(randomRuleName900).click(); await nodesPage.manageRules.ruleDetailsEditButton.click(); await nodesPage.manageRulesDialog.deleteActions(2); - await nodesPage.actionsDropdown.selectAction(ActionType.AddAspect, 1); - await nodesPage.actionsDropdown.insertAddAspectActionValues('History', 1); + await nodesPage.actionsDropdown.selectActions([{ type: ActionType.AddAspect, value: 'History' }]); await nodesPage.manageRulesDialog.createRuleButton.click(); await nodesPage.manageRulesDialog.createRuleButton.waitFor({ state: 'hidden' }); await nodesPage.manageRules.getGroupsList(randomRuleName900).click(); @@ -155,7 +154,7 @@ test.describe('Rules - Manage Rules', () => { await nodesPage.manageRules.getGroupsList(randomRuleName901).click(); await nodesPage.manageRules.ruleDetailsEditButton.click(); await nodesPage.manageRulesDialog.deleteActions(2); - await nodesPage.actionsDropdown.selectAction(ActionType.Copy, 1); + await nodesPage.actionsDropdown.selectActions([ActionType.Copy]); await nodesPage.manageRulesDialog.destinationFolderButton.click(); await nodesPage.contentNodeSelectorDialog.cancelButton.click(); await nodesPage.contentNodeSelectorDialog.cancelButton.waitFor({ state: 'hidden' }); @@ -166,7 +165,7 @@ test.describe('Rules - 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); + await nodesPage.actionsDropdown.selectActions([ActionType.AddAspect]); await expect(nodesPage.manageRulesDialog.createRuleButton).toBeDisabled(); }); diff --git a/e2e/playwright/navigation/src/tests/breadcrumb.e2e.ts b/e2e/playwright/navigation/src/tests/breadcrumb.e2e.ts index 6e2b85582..3dc8e5130 100644 --- a/e2e/playwright/navigation/src/tests/breadcrumb.e2e.ts +++ b/e2e/playwright/navigation/src/tests/breadcrumb.e2e.ts @@ -27,113 +27,151 @@ import { ApiClientFactory, TrashcanApi, NodesApi, SitesApi, test, timeouts, Util import { Site } from '@alfresco/js-api'; test.describe('viewer action file', () => { - let nodesApi: NodesApi; - let siteActions: SitesApi; - let trashcanApi: TrashcanApi; - const username = `user-${Utils.random()}`; - const parent = `parent-viewer-${Utils.random()}`; - let parentId: string; - const subFolder1 = `subFolder1-${Utils.random()}`; - let subFolder1Id: string; - const subFolder2 = `subFolder2-${Utils.random()}`; - let subFolder2Id: string; - const fileName1 = `file1-${Utils.random()}.txt`; + test.describe('Personal Files folder hierarchy', () => { + let nodesApi: NodesApi; + let trashcanApi: TrashcanApi; + const username = `breadcrumb-pf-${Utils.random()}`; + const parent = `parent-viewer-${Utils.random()}`; + const subFolder1 = `subFolder1-${Utils.random()}`; + const subFolder2 = `subFolder2-${Utils.random()}`; + const fileName1 = `file1-${Utils.random()}.txt`; + let subFolder1Id: string; + let subFolder2Id: string; - const siteName = `site-breadcrumb-${Utils.random()}`; - let docLibId: string; - const parentFromSite = `parent-in-site-${Utils.random()}`; - let parentFromSiteId: string; - const subFolder1FromSite = `subFolder1-in-site-${Utils.random()}`; - let subFolder1FromSiteId: string; - const subFolder2FromSite = `subFolder2-in-site-${Utils.random()}`; - let subFolder2FromSiteId: string; - const fileName1FromSite = `file1-in-site-${Utils.random()}.txt`; + test.beforeAll(async () => { + test.setTimeout(timeouts.extendedTest); + const apiClientFactory = new ApiClientFactory(); + await apiClientFactory.setUpAcaBackend('admin'); + await apiClientFactory.createUser({ username }); + nodesApi = await NodesApi.initialize(username, username); + trashcanApi = await TrashcanApi.initialize(username, username); + const parentId = (await nodesApi.createFolder(parent)).entry.id; + subFolder1Id = (await nodesApi.createFolder(subFolder1, parentId)).entry.id; + subFolder2Id = (await nodesApi.createFolder(subFolder2, subFolder1Id)).entry.id; + await nodesApi.createFile(fileName1, subFolder2Id); + }); - const parent2 = `parent2-${Utils.random()}`; - let parent2Id: string; - const folder1 = `folder1-${Utils.random()}`; - let folder1Id: string; - const folder1Renamed = `renamed-${Utils.random()}`; + test.beforeEach(async ({ loginPage }) => { + await Utils.tryLoginUser(loginPage, username, username, 'beforeEach failed'); + }); - test.beforeAll(async () => { - test.setTimeout(timeouts.extendedTest); - const apiClientFactory = new ApiClientFactory(); - await apiClientFactory.setUpAcaBackend('admin'); - await apiClientFactory.createUser({ username }); - nodesApi = await NodesApi.initialize(username, username); - siteActions = await SitesApi.initialize(username, username); - trashcanApi = await TrashcanApi.initialize(username, username); - const parentNode = await nodesApi.createFolder(parent); - parentId = parentNode.entry.id; - subFolder1Id = (await nodesApi.createFolder(subFolder1, parentId)).entry.id; - subFolder2Id = (await nodesApi.createFolder(subFolder2, subFolder1Id)).entry.id; - await nodesApi.createFile(fileName1, subFolder2Id); + test.afterAll(async () => { + await Utils.deleteNodesSitesEmptyTrashcan(nodesApi, trashcanApi, 'afterAll failed'); + }); - parent2Id = (await nodesApi.createFolder(parent2)).entry.id; - folder1Id = (await nodesApi.createFolder(folder1, parent2Id)).entry.id; + test('[XAT-4387] Personal Files breadcrumb main node', async ({ personalFiles }) => { + await personalFiles.navigate({ remoteUrl: `#/personal-files/` }); + await expect(personalFiles.breadcrumb.items).toHaveCount(1); + await expect(personalFiles.breadcrumb.currentItem).toHaveText('Personal Files'); + }); - await siteActions.createSite(siteName, Site.VisibilityEnum.PUBLIC); - docLibId = await siteActions.getDocLibId(siteName); - parentFromSiteId = (await nodesApi.createFolder(parentFromSite, docLibId)).entry.id; - subFolder1FromSiteId = (await nodesApi.createFolder(subFolder1FromSite, parentFromSiteId)).entry.id; - subFolder2FromSiteId = (await nodesApi.createFolder(subFolder2FromSite, subFolder1FromSiteId)).entry.id; - await nodesApi.createFile(fileName1FromSite, subFolder2FromSiteId); + test('[XAT-4388] Personal Files breadcrumb for a folder hierarchy', async ({ personalFiles }) => { + await personalFiles.navigate({ remoteUrl: `#/personal-files/${subFolder2Id}` }); + const expectedBreadcrumb = ['Personal Files', parent, subFolder1, subFolder2]; + expect(await personalFiles.breadcrumb.getAllItems()).toEqual(expectedBreadcrumb); + }); + + test('[XAT-4396] User can navigate to any location by clicking on any step from the breadcrumb', async ({ personalFiles }) => { + await personalFiles.navigate({ remoteUrl: `#/personal-files/${subFolder2Id}` }); + await personalFiles.breadcrumb.clickItem(subFolder1); + await personalFiles.dataTable.spinnerWaitForReload(); + const expectedBreadcrumb = ['Personal Files', parent, subFolder1]; + expect(await personalFiles.breadcrumb.getAllItems()).toEqual(expectedBreadcrumb); + }); + + test('[XAT-4397] Tooltip appears on hover on a step in breadcrumb', async ({ personalFiles }) => { + await personalFiles.navigate({ remoteUrl: `#/personal-files/${subFolder2Id}` }); + const item = personalFiles.breadcrumb.items.nth(2); + await expect(item).toHaveAttribute('title', subFolder1); + }); + + test('[XAT-4399] Browser back navigates to previous location regardless of breadcrumb steps', async ({ personalFiles, trashPage }) => { + await personalFiles.navigate({ remoteUrl: `#/personal-files/${subFolder2Id}` }); + await trashPage.navigate(); + await personalFiles.page.goBack(); + await personalFiles.dataTable.spinnerWaitForReload(); + const expectedBreadcrumb = ['Personal Files', parent, subFolder1, subFolder2]; + expect(await personalFiles.breadcrumb.getAllItems()).toEqual(expectedBreadcrumb); + }); }); - test.beforeEach(async ({ loginPage }) => { - await Utils.tryLoginUser(loginPage, username, username, 'beforeEach failed'); + test.describe('My Libraries folder hierarchy', () => { + let nodesApi: NodesApi; + let siteActions: SitesApi; + let trashcanApi: TrashcanApi; + const username = `breadcrumb-lib-${Utils.random()}`; + const siteName = `site-breadcrumb-${Utils.random()}`; + const parentFromSite = `parent-in-site-${Utils.random()}`; + const subFolder1FromSite = `subFolder1-in-site-${Utils.random()}`; + const subFolder2FromSite = `subFolder2-in-site-${Utils.random()}`; + const fileName1FromSite = `file1-in-site-${Utils.random()}.txt`; + let docLibId: string; + let subFolder2FromSiteId: string; + + test.beforeAll(async () => { + test.setTimeout(timeouts.extendedTest); + const apiClientFactory = new ApiClientFactory(); + await apiClientFactory.setUpAcaBackend('admin'); + await apiClientFactory.createUser({ username }); + nodesApi = await NodesApi.initialize(username, username); + siteActions = await SitesApi.initialize(username, username); + trashcanApi = await TrashcanApi.initialize(username, username); + await siteActions.createSite(siteName, Site.VisibilityEnum.PUBLIC); + docLibId = await siteActions.getDocLibId(siteName); + const parentFromSiteId = (await nodesApi.createFolder(parentFromSite, docLibId)).entry.id; + const subFolder1FromSiteId = (await nodesApi.createFolder(subFolder1FromSite, parentFromSiteId)).entry.id; + subFolder2FromSiteId = (await nodesApi.createFolder(subFolder2FromSite, subFolder1FromSiteId)).entry.id; + await nodesApi.createFile(fileName1FromSite, subFolder2FromSiteId); + }); + + test.beforeEach(async ({ loginPage }) => { + await Utils.tryLoginUser(loginPage, username, username, 'beforeEach failed'); + }); + + test.afterAll(async () => { + await Utils.deleteNodesSitesEmptyTrashcan(nodesApi, trashcanApi, 'afterAll failed', siteActions, [siteName]); + }); + + test('[XAT-4391] My Libraries breadcrumb for a folder hierarchy', async ({ myLibrariesPage }) => { + await myLibrariesPage.navigate({ remoteUrl: `#/libraries/${subFolder2FromSiteId}` }); + const expectedItems = ['My Libraries', siteName, parentFromSite, subFolder1FromSite, subFolder2FromSite]; + expect(await myLibrariesPage.breadcrumb.getAllItems()).toEqual(expectedItems); + }); }); - test.afterAll(async () => { - await Utils.deleteNodesSitesEmptyTrashcan(nodesApi, trashcanApi, 'afterAll failed', siteActions, [docLibId]); - }); + test.describe('Folder rename', () => { + let nodesApi: NodesApi; + let trashcanApi: TrashcanApi; + const username = `breadcrumb-rename-${Utils.random()}`; + const parent2 = `parent2-${Utils.random()}`; + const folder1 = `folder1-${Utils.random()}`; + const folder1Renamed = `renamed-${Utils.random()}`; + let folder1Id: string; - test('[XAT-4387] Personal Files breadcrumb main node', async ({ personalFiles }) => { - await personalFiles.navigate({ remoteUrl: `#/personal-files/` }); - expect(await personalFiles.breadcrumb.items.count(), 'Breadcrumb has incorrect number of items').toEqual(1); - await expect(personalFiles.breadcrumb.currentItem).toHaveText('Personal Files'); - }); + test.beforeAll(async () => { + const apiClientFactory = new ApiClientFactory(); + await apiClientFactory.setUpAcaBackend('admin'); + await apiClientFactory.createUser({ username }); + nodesApi = await NodesApi.initialize(username, username); + trashcanApi = await TrashcanApi.initialize(username, username); + const parent2Id = (await nodesApi.createFolder(parent2)).entry.id; + folder1Id = (await nodesApi.createFolder(folder1, parent2Id)).entry.id; + }); - test('[XAT-4388] Personal Files breadcrumb for a folder hierarchy', async ({ personalFiles }) => { - await personalFiles.navigate({ remoteUrl: `#/personal-files/${subFolder2Id}` }); - const expectedBreadcrumb = ['Personal Files', parent, subFolder1, subFolder2]; - expect(await personalFiles.breadcrumb.getAllItems()).toEqual(expectedBreadcrumb); - }); + test.beforeEach(async ({ loginPage }) => { + await Utils.tryLoginUser(loginPage, username, username, 'beforeEach failed'); + }); - test('[XAT-4391] My Libraries breadcrumb for a folder hierarchy', async ({ myLibrariesPage }) => { - await myLibrariesPage.navigate({ remoteUrl: `#/libraries/${subFolder2FromSiteId}` }); - const expectedItems = ['My Libraries', siteName, parentFromSite, subFolder1FromSite, subFolder2FromSite]; - expect(await myLibrariesPage.breadcrumb.getAllItems()).toEqual(expectedItems); - }); + test.afterAll(async () => { + await Utils.deleteNodesSitesEmptyTrashcan(nodesApi, trashcanApi, 'afterAll failed'); + }); - test('[XAT-4396] User can navigate to any location by clicking on any step from the breadcrumb', async ({ personalFiles }) => { - await personalFiles.navigate({ remoteUrl: `#/personal-files/${subFolder2Id}` }); - await personalFiles.breadcrumb.clickItem(subFolder1); - await personalFiles.dataTable.spinnerWaitForReload(); - const expectedBreadcrumb = ['Personal Files', parent, subFolder1]; - expect(await personalFiles.breadcrumb.getAllItems()).toEqual(expectedBreadcrumb); - }); - - test('[XAT-4397] Tooltip appears on hover on a step in breadcrumb', async ({ personalFiles }) => { - await personalFiles.navigate({ remoteUrl: `#/personal-files/${subFolder2Id}` }); - const item = personalFiles.breadcrumb.items.nth(2); - await expect(item).toHaveAttribute('title', subFolder1); - }); - - test('[XAT-4398] Breadcrumb updates correctly when folder is renamed', async ({ personalFiles, nodesApiAction }) => { - await nodesApiAction.renameNode(folder1Id, folder1Renamed); - await personalFiles.navigate({ remoteUrl: `#/personal-files/${folder1Id}` }); - await personalFiles.page.reload(); - await personalFiles.dataTable.spinnerWaitForReload(); - await expect(personalFiles.breadcrumb.currentItem).toHaveText(folder1Renamed); - }); - - test('[XAT-4399] Browser back navigates to previous location regardless of breadcrumb steps', async ({ personalFiles, trashPage }) => { - await personalFiles.navigate({ remoteUrl: `#/personal-files/${subFolder2Id}` }); - await trashPage.navigate(); - await personalFiles.page.goBack(); - await personalFiles.dataTable.spinnerWaitForReload(); - const expectedBreadcrumb = ['Personal Files', parent, subFolder1, subFolder2]; - expect(await personalFiles.breadcrumb.getAllItems()).toEqual(expectedBreadcrumb); + test('[XAT-4398] Breadcrumb updates correctly when folder is renamed', async ({ personalFiles, nodesApiAction }) => { + await nodesApiAction.renameNode(folder1Id, folder1Renamed); + await personalFiles.navigate({ remoteUrl: `#/personal-files/${folder1Id}` }); + await personalFiles.page.reload(); + await personalFiles.dataTable.spinnerWaitForReload(); + await expect(personalFiles.breadcrumb.currentItem).toHaveText(folder1Renamed); + }); }); }); diff --git a/e2e/playwright/navigation/src/tests/sidebar.e2e.ts b/e2e/playwright/navigation/src/tests/sidebar.e2e.ts index 7dc59175d..71d6be206 100644 --- a/e2e/playwright/navigation/src/tests/sidebar.e2e.ts +++ b/e2e/playwright/navigation/src/tests/sidebar.e2e.ts @@ -26,69 +26,99 @@ import { expect } from '@playwright/test'; import { ApiClientFactory, APP_ROUTES, SIDEBAR_LABELS, test, Utils } from '@alfresco/aca-playwright-shared'; test.describe('Sidebar', () => { - const username = `user-${Utils.random()}`; + test.describe('Navigation from sidebar', () => { + const username = `sidebar-nav-${Utils.random()}`; - test.beforeAll(async () => { - const apiClientFactory = new ApiClientFactory(); - await apiClientFactory.setUpAcaBackend('admin'); - await apiClientFactory.createUser({ username }); + test.beforeAll(async () => { + const apiClientFactory = new ApiClientFactory(); + await apiClientFactory.setUpAcaBackend('admin'); + await apiClientFactory.createUser({ username }); + }); + + test.beforeEach(async ({ loginPage }) => { + await Utils.tryLoginUser(loginPage, username, username, 'beforeEach failed'); + }); + + test('[XAT-5368] Navigate to My Libraries', async ({ personalFiles, myLibrariesPage }) => { + await personalFiles.navigate(); + await personalFiles.sidenav.openPanel(SIDEBAR_LABELS.MY_LIBRARIES); + await personalFiles.dataTable.spinnerWaitForReload(); + expect(myLibrariesPage.page.url()).toContain(APP_ROUTES.MY_LIBRARIES); + expect(await myLibrariesPage.sidenav.isActive(SIDEBAR_LABELS.MY_LIBRARIES), 'My Libraries link not active').toBe(true); + }); + + test('[XAT-19271] Repository / Company Home button is accessible for all users on the sidebar', async ({ personalFiles }) => { + await personalFiles.navigate(); + await personalFiles.sidenav.openPanel(SIDEBAR_LABELS.REPOSITORY); + expect(await personalFiles.sidenav.isActive(SIDEBAR_LABELS.REPOSITORY), 'Repository tab not active').toBe(true); + await personalFiles.dataTable.spinnerWaitForReload(); + expect(await personalFiles.dataTable.isEmpty()).toBe(false); + }); }); - test.beforeEach(async ({ loginPage }) => { - await Utils.tryLoginUser(loginPage, username, username, 'beforeEach failed'); + test.describe('Sidenav expand/collapse', () => { + const username = `sidebar-toggle-${Utils.random()}`; + + test.beforeAll(async () => { + const apiClientFactory = new ApiClientFactory(); + await apiClientFactory.setUpAcaBackend('admin'); + await apiClientFactory.createUser({ username }); + }); + + test.beforeEach(async ({ loginPage }) => { + await Utils.tryLoginUser(loginPage, username, username, 'beforeEach failed'); + }); + + test('[XAT-5384] Sidenav state is preserved on page refresh', async ({ personalFiles }) => { + await personalFiles.navigate(); + await expect(personalFiles.sidenav.expandedSidenav, 'Sidebar not expanded').toBeVisible(); + await personalFiles.reload(); + await expect(personalFiles.sidenav.expandedSidenav, 'Sidebar not expanded').toBeVisible(); + + await personalFiles.sidenav.collapseSideNav(); + + await expect(personalFiles.sidenav.expandedSidenav, 'Sidebar expanded').toBeHidden(); + await personalFiles.reload(); + await expect(personalFiles.sidenav.expandedSidenav, 'Sidebar expanded').toBeHidden(); + }); + + test('[XAT-5382] Sidenav can be collapsed and expanded', async ({ personalFiles }) => { + await personalFiles.navigate(); + await personalFiles.sidenav.collapseSideNav(); + await expect(personalFiles.sidenav.expandedSidenav, 'Sidebar expanded').toBeHidden(); + await personalFiles.sidenav.expandSideNav(); + await expect(personalFiles.sidenav.expandedSidenav, 'Sidebar not expanded').toBeVisible(); + }); }); - test('[XAT-5368] Navigate to My Libraries', async ({ personalFiles, myLibrariesPage }) => { - await personalFiles.navigate(); - await personalFiles.sidenav.openPanel(SIDEBAR_LABELS.MY_LIBRARIES); - await personalFiles.dataTable.spinnerWaitForReload(); - expect(myLibrariesPage.page.url()).toContain(APP_ROUTES.MY_LIBRARIES); - expect(await myLibrariesPage.sidenav.isActive(SIDEBAR_LABELS.MY_LIBRARIES), 'My Libraries link not active').toBe(true); - }); + test.describe('Sidenav with search results', () => { + const username = `sidebar-search-${Utils.random()}`; - test('[XAT-5387] The sidenav can be collapsed when search results page is displayed', async ({ personalFiles }) => { - await personalFiles.navigate({ remoteUrl: `#/search;q=test` }); - await expect(personalFiles.sidenav.expandedSidenav, 'Sidebar expanded').toBeVisible(); - await personalFiles.sidenav.collapseSideNav(); - await expect(personalFiles.sidenav.expandedSidenav, 'Sidebar not collapsed').toBeHidden(); - }); + test.beforeAll(async () => { + const apiClientFactory = new ApiClientFactory(); + await apiClientFactory.setUpAcaBackend('admin'); + await apiClientFactory.createUser({ username }); + }); - test('[XAT-5384] Sidenav state is preserved on page refresh', async ({ personalFiles }) => { - await personalFiles.navigate(); - await expect(personalFiles.sidenav.expandedSidenav, 'Sidebar not expanded').toBeVisible(); - await personalFiles.reload(); - await expect(personalFiles.sidenav.expandedSidenav, 'Sidebar not expanded').toBeVisible(); + test.beforeEach(async ({ loginPage }) => { + await Utils.tryLoginUser(loginPage, username, username, 'beforeEach failed'); + }); - await personalFiles.sidenav.collapseSideNav(); + test('[XAT-5387] The sidenav can be collapsed when search results page is displayed', async ({ personalFiles }) => { + await personalFiles.navigate({ remoteUrl: `#/search;q=test` }); + await expect(personalFiles.sidenav.expandedSidenav, 'Sidebar expanded').toBeVisible(); + await personalFiles.sidenav.collapseSideNav(); + await expect(personalFiles.sidenav.expandedSidenav, 'Sidebar not collapsed').toBeHidden(); + }); - await expect(personalFiles.sidenav.expandedSidenav, 'Sidebar expanded').toBeHidden(); - await personalFiles.reload(); - await expect(personalFiles.sidenav.expandedSidenav, 'Sidebar expanded').toBeHidden(); - }); - - test('[XAT-5382] Sidenav can be collapsed and expanded', async ({ personalFiles }) => { - await personalFiles.navigate(); - await personalFiles.sidenav.collapseSideNav(); - await expect(personalFiles.sidenav.expandedSidenav, 'Sidebar expanded').toBeHidden(); - await personalFiles.sidenav.expandSideNav(); - await expect(personalFiles.sidenav.expandedSidenav, 'Sidebar not expanded').toBeVisible(); - }); - - test('[XAT-5386] The sidenav returns to the default state when navigating away from the search results page', async ({ - personalFiles, - searchPage - }) => { - await personalFiles.navigate({ remoteUrl: `#/search;q=test` }); - await searchPage.searchInputComponent.searchCloseButton.click(); - await searchPage.sidenav.expandedSidenav.waitFor({ state: 'attached' }); - await expect(personalFiles.sidenav.expandedSidenav, 'Sidebar not expanded').toBeVisible(); - }); - - test('[XAT-19271] Repository / Company Home button is accessible for all users on the sidebar', async ({ personalFiles }) => { - await personalFiles.navigate(); - await personalFiles.sidenav.openPanel(SIDEBAR_LABELS.REPOSITORY); - expect(await personalFiles.sidenav.isActive(SIDEBAR_LABELS.REPOSITORY), 'Repository tab not active').toBe(true); - await personalFiles.dataTable.spinnerWaitForReload(); - expect(await personalFiles.dataTable.isEmpty()).toBe(false); + test('[XAT-5386] The sidenav returns to the default state when navigating away from the search results page', async ({ + personalFiles, + searchPage + }) => { + await personalFiles.navigate({ remoteUrl: `#/search;q=test` }); + await searchPage.searchInputComponent.searchCloseButton.click(); + await searchPage.sidenav.expandedSidenav.waitFor({ state: 'attached' }); + await expect(personalFiles.sidenav.expandedSidenav, 'Sidebar not expanded').toBeVisible(); + }); }); }); diff --git a/e2e/playwright/navigation/src/tests/single-click.e2e.ts b/e2e/playwright/navigation/src/tests/single-click.e2e.ts index 05b9e1ea0..a82a5923c 100644 --- a/e2e/playwright/navigation/src/tests/single-click.e2e.ts +++ b/e2e/playwright/navigation/src/tests/single-click.e2e.ts @@ -26,66 +26,107 @@ import { expect } from '@playwright/test'; import { ApiClientFactory, TrashcanApi, NodesApi, SitesApi, test, Utils } from '@alfresco/aca-playwright-shared'; test.describe('Single click on item name', () => { - let nodesApi: NodesApi; - let trashcanApi: TrashcanApi; - const username = `user-${Utils.random()}`; - const folder1 = `folder1-${Utils.random()}`; - const folderSearch = `folder1-${Utils.random()}`; + test.describe('in Trash', () => { + let nodesApi: NodesApi; + let trashcanApi: TrashcanApi; + const username = `single-click-trash-${Utils.random()}`; + const deletedFile1 = `file1-${Utils.random()}.txt`; + const deletedFolder1 = `folder1-${Utils.random()}`; - const deletedFile1 = `file1-${Utils.random()}.txt`; - const deletedFolder1 = `folder1-${Utils.random()}`; + test.beforeAll(async () => { + const apiClientFactory = new ApiClientFactory(); + await apiClientFactory.setUpAcaBackend('admin'); + await apiClientFactory.createUser({ username }); + nodesApi = await NodesApi.initialize(username, username); + trashcanApi = await TrashcanApi.initialize(username, username); + await nodesApi.createFile(deletedFile1); + await nodesApi.createFolder(deletedFolder1); + }); - const siteName = `site-single-${Utils.random()}`; - const fileSite = `fileSite-${Utils.random()}.txt`; + test.beforeEach(async ({ loginPage }) => { + await Utils.tryLoginUser(loginPage, username, username, 'beforeEach failed'); + }); - test.beforeAll(async () => { - const apiClientFactory = new ApiClientFactory(); - await apiClientFactory.setUpAcaBackend('admin'); - await apiClientFactory.createUser({ username }); - nodesApi = await NodesApi.initialize(username, username); - trashcanApi = await TrashcanApi.initialize(username, username); - const siteActions = await SitesApi.initialize(username, username); - await nodesApi.createFolder(folder1); - await nodesApi.createFolder(folderSearch); - await nodesApi.createFile(deletedFile1); - await nodesApi.createFolder(deletedFolder1); + test.afterAll(async () => { + await Utils.deleteNodesSitesEmptyTrashcan(nodesApi, trashcanApi, 'afterAll failed'); + }); - await siteActions.createSite(siteName); - const docLibId = await siteActions.getDocLibId(siteName); - await nodesApi.createFile(fileSite, docLibId); + test('[XAT-4894] Hyperlink does not appear for items in the Trash', async ({ trashPage }) => { + await trashPage.navigate(); + await expect(trashPage.dataTable.getCellLinkByName(deletedFile1), 'Link on name is present').toBeHidden(); + await expect(trashPage.dataTable.getCellLinkByName(deletedFolder1), 'Link on name is present').toBeHidden(); + }); }); - test.beforeEach(async ({ loginPage }) => { - await Utils.tryLoginUser(loginPage, username, username, 'beforeEach failed'); + test.describe('on Personal Files', () => { + let nodesApi: NodesApi; + let trashcanApi: TrashcanApi; + const username = `single-click-pf-${Utils.random()}`; + const folder1 = `folder1-${Utils.random()}`; + + test.beforeAll(async () => { + const apiClientFactory = new ApiClientFactory(); + await apiClientFactory.setUpAcaBackend('admin'); + await apiClientFactory.createUser({ username }); + nodesApi = await NodesApi.initialize(username, username); + trashcanApi = await TrashcanApi.initialize(username, username); + await nodesApi.createFolder(folder1); + }); + + test.beforeEach(async ({ loginPage }) => { + await Utils.tryLoginUser(loginPage, username, username, 'beforeEach failed'); + }); + + test.afterAll(async () => { + await Utils.deleteNodesSitesEmptyTrashcan(nodesApi, trashcanApi, 'afterAll failed'); + }); + + test('[XAT-4897] Navigate inside the folder when clicking the hyperlink - on Personal Files', async ({ personalFiles }) => { + await personalFiles.navigate(); + await personalFiles.dataTable.goThroughPagesLookingForRowWithName(folder1); + await personalFiles.dataTable.getCellLinkByName(folder1).click(); + await personalFiles.dataTable.spinnerWaitForReload(); + while ((await personalFiles.breadcrumb.currentItem.innerText()) === 'Personal Files') { + await personalFiles.breadcrumb.currentItem.innerText(); + } + await expect(personalFiles.breadcrumb.currentItem).toHaveText(folder1); + }); }); - test.afterAll(async () => { - await Utils.deleteNodesSitesEmptyTrashcan(nodesApi, trashcanApi, 'afterAll failed'); - }); + test.describe('in Libraries', () => { + let nodesApi: NodesApi; + let trashcanApi: TrashcanApi; + const username = `single-click-lib-${Utils.random()}`; + const siteName = `site-single-${Utils.random()}`; + const fileSite = `fileSite-${Utils.random()}.txt`; - test('[XAT-4894] Hyperlink does not appear for items in the Trash', async ({ trashPage }) => { - await trashPage.navigate(); - await expect(trashPage.dataTable.getCellLinkByName(deletedFile1), 'Link on name is present').toBeHidden(); - await expect(trashPage.dataTable.getCellLinkByName(deletedFolder1), 'Link on name is present').toBeHidden(); - }); + test.beforeAll(async () => { + const apiClientFactory = new ApiClientFactory(); + await apiClientFactory.setUpAcaBackend('admin'); + await apiClientFactory.createUser({ username }); + nodesApi = await NodesApi.initialize(username, username); + trashcanApi = await TrashcanApi.initialize(username, username); + const siteActions = await SitesApi.initialize(username, username); + await siteActions.createSite(siteName); + const docLibId = await siteActions.getDocLibId(siteName); + await nodesApi.createFile(fileSite, docLibId); + }); - test('[XAT-4897] Navigate inside the folder when clicking the hyperlink - on Personal Files', async ({ personalFiles }) => { - await personalFiles.navigate(); - await personalFiles.dataTable.goThroughPagesLookingForRowWithName(folder1); - await personalFiles.dataTable.getCellLinkByName(folder1).click(); - await personalFiles.dataTable.spinnerWaitForReload(); - while ((await personalFiles.breadcrumb.currentItem.innerText()) === 'Personal Files') { - await personalFiles.breadcrumb.currentItem.innerText(); - } - await expect(personalFiles.breadcrumb.currentItem).toHaveText(folder1); - }); + test.beforeEach(async ({ loginPage }) => { + await Utils.tryLoginUser(loginPage, username, username, 'beforeEach failed'); + }); - test('[XAT-4899] Navigate inside the library when clicking the hyperlink', async ({ myLibrariesPage }) => { - await myLibrariesPage.navigate(); - await myLibrariesPage.dataTable.goThroughPagesLookingForRowWithName(siteName); - await myLibrariesPage.dataTable.getCellLinkByName(siteName).click(); - await myLibrariesPage.dataTable.spinnerWaitForReload(); - await expect(myLibrariesPage.breadcrumb.currentItem).toHaveText(siteName); - await expect(myLibrariesPage.dataTable.getCellLinkByName(fileSite), `${fileSite} not displayed`).toBeVisible(); + test.afterAll(async () => { + await Utils.deleteNodesSitesEmptyTrashcan(nodesApi, trashcanApi, 'afterAll failed'); + }); + + test('[XAT-4899] Navigate inside the library when clicking the hyperlink', async ({ myLibrariesPage }) => { + await myLibrariesPage.navigate(); + await myLibrariesPage.dataTable.goThroughPagesLookingForRowWithName(siteName); + await myLibrariesPage.dataTable.getCellLinkByName(siteName).click(); + await myLibrariesPage.dataTable.spinnerWaitForReload(); + await expect(myLibrariesPage.breadcrumb.currentItem).toHaveText(siteName); + await expect(myLibrariesPage.dataTable.getCellLinkByName(fileSite), `${fileSite} not displayed`).toBeVisible(); + }); }); }); diff --git a/e2e/playwright/search/src/tests/search-highlighting.e2e.ts b/e2e/playwright/search/src/tests/search-highlighting.e2e.ts index 0ae829daf..f0f6c3ed4 100644 --- a/e2e/playwright/search/src/tests/search-highlighting.e2e.ts +++ b/e2e/playwright/search/src/tests/search-highlighting.e2e.ts @@ -23,7 +23,7 @@ */ import { expect } from '@playwright/test'; -import { ApiClientFactory, Utils, test, NodesApi, TrashcanApi, TEST_FILES, FileActionsApi } from '@alfresco/aca-playwright-shared'; +import { ApiClientFactory, Utils, test, NodesApi, TrashcanApi, TEST_FILES, FileActionsApi, SearchApi } from '@alfresco/aca-playwright-shared'; test.use({ launchOptions: { slowMo: 500 } }); @@ -31,17 +31,14 @@ test.describe('Search Highlighting', () => { let nodesApi: NodesApi; let trashcanApi: TrashcanApi; let fileActionsApi: FileActionsApi; + let searchApi: SearchApi; const randomId = Utils.random(); const username = `user-${randomId}`; const fileNameHighlight = `${randomId}-file-name.jpg`; const fileDescriptionHighlight = `${randomId}-file-description.jpg`; const fileDescription = `highlight`; const fileContentHighlight = `${randomId}-file-content.pdf`; - const fileContent = 'TEXT:Virtual'; - - test.beforeEach(async ({ loginPage }) => { - await Utils.tryLoginUser(loginPage, username, username, 'beforeEach failed'); - }); + const fileContent = 'Virtual'; test.beforeAll(async () => { try { @@ -51,9 +48,11 @@ test.describe('Search Highlighting', () => { nodesApi = await NodesApi.initialize(username, username); trashcanApi = await TrashcanApi.initialize(username, username); fileActionsApi = await FileActionsApi.initialize(username, username); + searchApi = await SearchApi.initialize(username, username); await nodesApi.createFile(fileNameHighlight, '-my-'); await nodesApi.createFile(fileDescriptionHighlight, '-my-', undefined, fileDescription); await fileActionsApi.uploadFileWithRename(TEST_FILES.PDF.path, fileContentHighlight); + await searchApi.waitFileForSearchIndexing(fileContentHighlight); await fileActionsApi.waitForNodesSearchHighlight(fileContentHighlight, { expect: 1 }); } catch (error) { @@ -61,6 +60,10 @@ test.describe('Search Highlighting', () => { } }); + test.beforeEach(async ({ loginPage }) => { + await Utils.tryLoginUser(loginPage, username, username, 'beforeEach failed'); + }); + test.afterAll(async () => { await Utils.deleteNodesSitesEmptyTrashcan(nodesApi, trashcanApi, 'afterAll failed'); }); diff --git a/e2e/playwright/share-action/src/tests/share/unshare-file-search-results.e2e.ts b/e2e/playwright/share-action/src/tests/share/unshare-file-search-results.e2e.ts index bbe826dba..219b7cb26 100755 --- a/e2e/playwright/share-action/src/tests/share/unshare-file-search-results.e2e.ts +++ b/e2e/playwright/share-action/src/tests/share/unshare-file-search-results.e2e.ts @@ -110,7 +110,7 @@ test.describe('Unshare a file from Search Results', () => { }); test.afterAll(async () => { - await Utils.deleteNodesSitesEmptyTrashcan(nodesApi, trashcanApi, 'afterAll failed', sitesApi, [docLibId]); + await Utils.deleteNodesSitesEmptyTrashcan(nodesApi, trashcanApi, 'afterAll failed', sitesApi, [sitePrivate]); }); test('[XAT-5197] Unshare dialog UI', async ({ personalFiles, searchPage }) => { diff --git a/e2e/playwright/smoke-test/src/tests/viewer/viewer.e2e.ts b/e2e/playwright/smoke-test/src/tests/viewer/viewer.e2e.ts index 05394b544..a6cb1d4a0 100644 --- a/e2e/playwright/smoke-test/src/tests/viewer/viewer.e2e.ts +++ b/e2e/playwright/smoke-test/src/tests/viewer/viewer.e2e.ts @@ -40,7 +40,6 @@ test.describe('viewer file', () => { const usernameViewer = `user-${Utils.random()}`; const randomDocxName = `${TEST_FILES.DOCX.name}-${Utils.random()}`; const siteAdmin = `siteAdmin-${Utils.random()}`; - let docLibId: string; let folderId: string; let fileDocxId: string; let nodesApi: NodesApi; @@ -63,10 +62,8 @@ test.describe('viewer file', () => { const fileActionApi = await FileActionsApi.initialize(usernameViewer, usernameViewer); trashcanApi = await TrashcanApi.initialize(usernameViewer, usernameViewer); siteActionsAdmin = await SitesApi.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; + folderId = (await nodesApi.createFolder(randomFolderName)).entry.id; + fileDocxId = (await fileActionApi.uploadFile(TEST_FILES.DOCX.path, randomDocxName, folderId)).entry.id; try { await siteActionsAdmin.createSite(siteAdmin, Site.VisibilityEnum.PRIVATE); @@ -76,8 +73,6 @@ test.describe('viewer file', () => { } } - docLibId = await siteActionsAdmin.getDocLibId(siteAdmin); - await fileActionApi.waitForNodes(randomDocxName, { expect: 1 }); }); @@ -88,7 +83,7 @@ test.describe('viewer file', () => { test.afterAll(async () => { await Utils.deleteNodesSitesEmptyTrashcan(nodesApi, trashcanApi, 'afterAll failed'); - await Utils.deleteNodesSitesEmptyTrashcan(nodesApi, trashcanApi, 'afterAll failed', siteActionsAdmin, [docLibId]); + await Utils.deleteNodesSitesEmptyTrashcan(nodesApi, trashcanApi, 'afterAll failed', siteActionsAdmin, [siteAdmin]); }); test('[XAT-17736] Open viewer with click action', async ({ personalFiles }) => { 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 9210b3b5f..0b5c9a9a7 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 @@ -181,7 +181,7 @@ test.describe('Special permissions : ', () => { }); test.afterAll(async () => { - await Utils.deleteNodesSitesEmptyTrashcan(undefined, undefined, 'afterAll failed', managerSiteActions, [docLibId]); + await Utils.deleteNodesSitesEmptyTrashcan(undefined, undefined, 'afterAll failed', managerSiteActions, [sitePrivate]); }); test.describe('Consumer', () => { diff --git a/e2e/playwright/viewer-actions/src/tests/viewer-action.e2e.ts b/e2e/playwright/viewer-actions/src/tests/viewer-action.e2e.ts index 1dc539f10..514aca22a 100644 --- a/e2e/playwright/viewer-actions/src/tests/viewer-action.e2e.ts +++ b/e2e/playwright/viewer-actions/src/tests/viewer-action.e2e.ts @@ -358,8 +358,10 @@ test.describe('viewer action file', () => { 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); + const downloadPromise = personalFiles.page.waitForEvent('download', { timeout: timeouts.medium }); + await personalFiles.matMenu.clickMenuItem('Download'); + const download = await downloadPromise; + expect(download.suggestedFilename()).toContain(file5713); }); test('[XAT-5714] Viewer: User can restore the current version of a file to a previous version with permissions', async ({ personalFiles }) => { 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 fe6cf9786..8e09db233 100644 --- a/e2e/playwright/viewer/src/tests/viewer-version-actions.e2e.ts +++ b/e2e/playwright/viewer/src/tests/viewer-version-actions.e2e.ts @@ -22,7 +22,7 @@ * from Hyland Software. If not, see . */ -import { expect } from '@playwright/test'; +import { expect, Download } from '@playwright/test'; import { ApiClientFactory, Utils, @@ -54,7 +54,9 @@ test.describe('Version actions', () => { let fileId: string; let fileAfterUpdateId: string; - async function viewFirstFileVersion(page: PersonalFilesPage | RecentFilesPage | FavoritesPage | SharedPage | SearchPage) { + type PageWithViewer = PersonalFilesPage | RecentFilesPage | FavoritesPage | SharedPage | SearchPage; + + async function viewFirstFileVersion(page: PageWithViewer) { await page.dataTable.selectItems(filenameAfterUpdate); await page.acaHeader.clickMoreActions(); await page.matMenu.clickMenuItem('Manage Versions'); @@ -62,6 +64,17 @@ test.describe('Version actions', () => { await page.matMenu.clickMenuItem('View'); } + async function waitForViewerDocumentToRender(page: PageWithViewer): Promise { + await page.viewer.waitForViewerToOpen(); + await page.viewer.waitForViewerContentToRender('document'); + } + + async function downloadFromViewer(page: PageWithViewer): Promise { + const downloadPromise = page.page.waitForEvent('download'); + await page.viewer.downloadButton.click(); + return downloadPromise; + } + test.beforeAll(async () => { try { const apiClientFactory = new ApiClientFactory(); @@ -112,7 +125,8 @@ test.describe('Version actions', () => { }); test('[XAT-5498] Should be possible to download a previous document version - Personal Files', async ({ personalFiles }) => { - const [download] = await Promise.all([personalFiles.page.waitForEvent('download'), await personalFiles.viewer.downloadButton.click()]); + await waitForViewerDocumentToRender(personalFiles); + const download = await downloadFromViewer(personalFiles); expect(download.suggestedFilename()).toContain(filenameBeforeUpdate); }); @@ -153,7 +167,8 @@ test.describe('Version actions', () => { }); test('[XAT-5501] Should be possible to download a previous document version - Recent Files', async ({ recentFilesPage }) => { - const [download] = await Promise.all([recentFilesPage.page.waitForEvent('download'), await recentFilesPage.viewer.downloadButton.click()]); + await waitForViewerDocumentToRender(recentFilesPage); + const download = await downloadFromViewer(recentFilesPage); expect(download.suggestedFilename()).toBe(filenameBeforeUpdate); }); }); @@ -178,7 +193,8 @@ test.describe('Version actions', () => { }); test('[XAT-5504] Should be possible to download a previous document version - Favorites', async ({ favoritePage }) => { - const [download] = await Promise.all([favoritePage.page.waitForEvent('download'), await favoritePage.viewer.downloadButton.click()]); + await waitForViewerDocumentToRender(favoritePage); + const download = await downloadFromViewer(favoritePage); expect(download.suggestedFilename()).toContain(filenameBeforeUpdate); }); }); @@ -203,7 +219,8 @@ test.describe('Version actions', () => { }); test('[XAT-5507] Should be possible to download a previous document version - Shared Files', async ({ sharedPage }) => { - const [download] = await Promise.all([sharedPage.page.waitForEvent('download'), await sharedPage.viewer.downloadButton.click()]); + await waitForViewerDocumentToRender(sharedPage); + const download = await downloadFromViewer(sharedPage); expect(download.suggestedFilename()).toContain(filenameBeforeUpdate); }); }); @@ -228,7 +245,8 @@ test.describe('Version actions', () => { }); test('[XAT-5510] Should be possible to download a previous document version - Search Results', async ({ searchPage }) => { - const [download] = await Promise.all([searchPage.page.waitForEvent('download'), await searchPage.viewer.downloadButton.click()]); + await waitForViewerDocumentToRender(searchPage); + const download = await downloadFromViewer(searchPage); expect(download.suggestedFilename()).toContain(filenameBeforeUpdate); }); }); diff --git a/e2e/playwright/viewer/src/tests/viewer-zoom-functionality.e2e.ts b/e2e/playwright/viewer/src/tests/viewer-zoom-functionality.e2e.ts index d332183a1..6f7c08701 100644 --- a/e2e/playwright/viewer/src/tests/viewer-zoom-functionality.e2e.ts +++ b/e2e/playwright/viewer/src/tests/viewer-zoom-functionality.e2e.ts @@ -118,7 +118,7 @@ test.describe('viewer zoom functionality and reset', () => { }); test.afterAll(async () => { - await Utils.deleteNodesSitesEmptyTrashcan(nodesApi, trashcanApi, 'afterAll failed', siteActionsUser, [docLibId]); + await Utils.deleteNodesSitesEmptyTrashcan(nodesApi, trashcanApi, 'afterAll failed', siteActionsUser, [randomLibraryName]); }); async function validateZoomScaleInViewer( diff --git a/e2e/playwright/viewer/src/tests/viewer.e2e.ts b/e2e/playwright/viewer/src/tests/viewer.e2e.ts index bf39e2550..53f886458 100644 --- a/e2e/playwright/viewer/src/tests/viewer.e2e.ts +++ b/e2e/playwright/viewer/src/tests/viewer.e2e.ts @@ -486,7 +486,7 @@ test.describe('viewer file', () => { }); test.afterAll(async () => { - await Utils.deleteNodesSitesEmptyTrashcan(nodesApi, trashcanApi, 'afterAll failed', siteActionsAdmin, [docLibId]); + await Utils.deleteNodesSitesEmptyTrashcan(nodesApi, trashcanApi, 'afterAll failed', siteActionsAdmin, [siteAdmin]); }); test('[XAT-5477] Viewer does not open when accessing the preview URL for a file without permissions', async ({ personalFiles }) => { diff --git a/package-lock.json b/package-lock.json index d57e3398e..72e79cff1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -60,7 +60,7 @@ "@nx/angular": "22.7.6", "@nx/eslint-plugin": "22.5.4", "@nx/workspace": "22.5.4", - "@playwright/test": "^1.56.1", + "@playwright/test": "^1.61.1", "@reportportal/agent-js-playwright": "^5.4.0", "@types/event-emitter": "^0.3.3", "@types/jasmine": "~3.6.0", diff --git a/package.json b/package.json index 6da8ba46b..757eaf98e 100644 --- a/package.json +++ b/package.json @@ -98,7 +98,7 @@ "@nx/angular": "22.7.6", "@nx/eslint-plugin": "22.5.4", "@nx/workspace": "22.5.4", - "@playwright/test": "^1.56.1", + "@playwright/test": "^1.61.1", "@reportportal/agent-js-playwright": "^5.4.0", "@types/event-emitter": "^0.3.3", "@types/jasmine": "~3.6.0", diff --git a/projects/aca-playwright-shared/src/api/api-client-factory.ts b/projects/aca-playwright-shared/src/api/api-client-factory.ts index a9b4bc00e..7198de2b2 100644 --- a/projects/aca-playwright-shared/src/api/api-client-factory.ts +++ b/projects/aca-playwright-shared/src/api/api-client-factory.ts @@ -150,7 +150,7 @@ export class ApiClientFactory { try { await this.alfrescoApi.login(user.username, user.password); } catch (error) { - logger.error(`[API Client Factory] Log in user ${user.username} failed ${error}`); + logger.error(`[API Client Factory] Log in user ${user.username} failed ${JSON.stringify(error)}`); throw error; } } @@ -162,7 +162,7 @@ export class ApiClientFactory { try { return await peopleApi.createPerson(person); } catch (error) { - if (String(error).includes('409')) { + if (JSON.stringify(error).includes('409')) { logger.warn(`[API Client Factory] createUser: user "${user.username}" already exists, skipping creation`); return null; } diff --git a/projects/aca-playwright-shared/src/api/file-actions.ts b/projects/aca-playwright-shared/src/api/file-actions.ts index bc1881e6c..6675bbae8 100644 --- a/projects/aca-playwright-shared/src/api/file-actions.ts +++ b/projects/aca-playwright-shared/src/api/file-actions.ts @@ -64,7 +64,7 @@ export class FileActionsApi { logger.info(`File uploaded successfully: ${fileName}`); return result; } catch (error) { - logger.error(`Failed to upload file: ${fileName}: ${error}`); + logger.error(`Failed to upload file: ${fileName}: ${JSON.stringify(error)}`); return Promise.reject(error); } } @@ -170,17 +170,11 @@ export class FileActionsApi { } async waitForNodes(searchTerm: string, data: { expect: number }): Promise { - logger.info(`waitForNodes: Waiting for ${data.expect} node(s) matching "${searchTerm}"`); const predicate = (totalItems: number) => totalItems === data.expect; - let pollCount = 0; const apiCall = async () => { try { - const totalItems = (await this.queryNodesNames(searchTerm)).list?.pagination?.totalItems || 0; - if (pollCount++ % 4 === 0) { - logger.info(`waitForNodes: "${searchTerm}" — found ${totalItems}, expecting ${data.expect}`); - } - return totalItems; + return (await this.queryNodesNames(searchTerm)).list?.pagination?.totalItems || 0; } catch { return 0; } @@ -188,6 +182,7 @@ export class FileActionsApi { try { await waitForApi(apiCall, predicate, 30, 2500); + logger.info(`waitForNodes: Found ${data.expect} node(s) matching "${searchTerm}"`); } catch { const actual = await apiCall(); const message = `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 6cb9e63e9..93d9b2d99 100755 --- a/projects/aca-playwright-shared/src/api/nodes-api.ts +++ b/projects/aca-playwright-shared/src/api/nodes-api.ts @@ -69,7 +69,7 @@ export class NodesApi { try { return await this.createNode('cm:content', name, parentId, title, description, null, author, majorVersion, aspectNames); } catch (error) { - const message = `${this.constructor.name} ${this.createFile.name}: ${error}`; + const message = `${this.constructor.name} ${this.createFile.name}: ${error instanceof Error ? error.message : JSON.stringify(error)}`; logger.error(message); throw new Error(message); } @@ -148,7 +148,16 @@ export class NodesApi { majorVersion }); } catch (error) { - const message = `${this.constructor.name} ${this.createNode.name}: ${error}`; + if (JSON.stringify(error).includes('409')) { + logger.warn( + `${this.constructor.name} ${this.createNode.name}: node "${name}" already exists in parent "${parentId}", retrieving existing node` + ); + const existingNodeId = await this.getNodeIdFromParent(name, parentId); + if (existingNodeId) { + return this.getNodeById(existingNodeId); + } + } + const message = `${this.constructor.name} ${this.createNode.name}: ${error instanceof Error ? error.message : JSON.stringify(error)}`; logger.error(message); throw new Error(message); } diff --git a/projects/aca-playwright-shared/src/api/search-api.ts b/projects/aca-playwright-shared/src/api/search-api.ts index 662519d5f..600a71f13 100755 --- a/projects/aca-playwright-shared/src/api/search-api.ts +++ b/projects/aca-playwright-shared/src/api/search-api.ts @@ -58,6 +58,119 @@ export class SearchApi { } } + async searchForNode(fileName: string, options?: { maxRetries?: number }): Promise { + const query = { + query: { + query: `cm:name:"${fileName}"`, + language: 'afts' + }, + include: ['path', 'allowableOperations', 'properties'], + paging: { + skipCount: 0, + maxItems: 25 + }, + filterQueries: [ + { + query: "+TYPE:'cm:folder' OR +TYPE:'cm:content'" + }, + { + query: "-TYPE:'cm:thumbnail' AND -TYPE:'cm:failedThumbnail' AND -TYPE:'cm:rating'" + }, + { + query: '-cm:creator:System' + }, + { + query: "-TYPE:'st:site' AND -ASPECT:'st:siteContainer' AND -ASPECT:'sys:hidden'" + }, + { + query: "-TYPE:'dl:dataList' AND -TYPE:'dl:todoList' AND -TYPE:'dl:issue'" + }, + { + query: "-TYPE:'fm:topic' AND -TYPE:'fm:post'" + }, + { + query: "-TYPE:'lnk:link'" + }, + { + query: "-PATH:'//cm:wiki/*'" + }, + { + query: "+TYPE:'cm:content'" + } + ], + facetQueries: undefined, + facetIntervals: undefined, + facetFields: { + facets: [ + { + field: 'creator', + mincount: 1, + label: 'SEARCH.FACET_FIELDS.CREATOR' + }, + { + field: 'modifier', + mincount: 1, + label: 'SEARCH.FACET_FIELDS.MODIFIER' + } + ] + }, + sort: [ + { + type: 'SCORE', + field: 'score', + ascending: false + } + ], + highlight: { + prefix: "", + postfix: '', + fields: [ + { + field: 'cm:title' + }, + { + field: 'cm:name' + }, + { + field: 'cm:description', + snippetCount: 1 + }, + { + field: 'cm:content', + snippetCount: 1 + } + ] + }, + facetFormat: 'V2' + }; + + let result: ResultSetPaging; + let retryCount = 0; + const retryLimit = options?.maxRetries ?? 90; + + do { + try { + result = await this.apiService.search.search(query); + } catch { + result = new ResultSetPaging(); + } + if ((result.list?.entries?.length ?? 0) === 0) { + retryCount++; + if (retryCount % 10 === 0) { + logger.info(`searchForNode: Still waiting for file "${fileName}" after ${retryCount} retries (max ${retryLimit}).`); + } + if (retryCount >= retryLimit) { + logger.error(`searchForNode: File "${fileName}" not found after ${retryLimit} retries.`); + throw new Error(`File with name ${fileName} not found after ${retryLimit} retries`); + } + await Utils.delayInSeconds(1); + } + } while ((result.list?.entries?.length ?? 0) === 0); + + logger.info(`searchForNode: Search succeeded for file "${fileName}"`); + return result; + } + async getTotalItems(username: string): Promise { return (await this.querySearchFiles(username)).list?.pagination?.totalItems ?? 0; } @@ -116,8 +229,24 @@ export class SearchApi { logger.info(`waitForFolderPathIndexing: Found expected ${options.nodesExpected} nodes in folder ${folderId}`); return result.list?.pagination?.count ?? 0; } catch (error) { - logger.error(`waitForFolderPathIndexing failed for folderId "${folderId}": ${error}`); - throw error; + const errorMessage = `waitForFolderPathIndexing failed for folderId "${folderId}": ${JSON.stringify(error)}`; + logger.error(errorMessage); + throw new Error(errorMessage); + } + } + + async waitFileForSearchIndexing(fileName: string, maxRetries?: number): Promise { + try { + const result = await this.searchForNode(fileName, { maxRetries: maxRetries }); + const entryNames = (result.list?.entries ?? []).map((entry) => entry.entry?.name).filter((name): name is string => Boolean(name)); + if (!entryNames.includes(fileName)) { + throw new Error(`File "${fileName}" not found in search results. Found: [${entryNames.join(', ')}]`); + } + logger.info(`waitFileForSearchIndexing: File "${fileName}" is indexed.`); + } catch (error) { + const errorMessage = `waitFileForSearchIndexing failed for file "${fileName}": ${JSON.stringify(error)}`; + logger.error(errorMessage); + throw new Error(errorMessage); } } } diff --git a/projects/aca-playwright-shared/src/api/shared-links-api.ts b/projects/aca-playwright-shared/src/api/shared-links-api.ts index fd93c0d27..d847d53ac 100755 --- a/projects/aca-playwright-shared/src/api/shared-links-api.ts +++ b/projects/aca-playwright-shared/src/api/shared-links-api.ts @@ -85,9 +85,7 @@ export class SharedLinksApi { const sharedFiles = (await this.getSharedLinks()).list?.entries?.map((link) => link.entry.nodeId) ?? []; const foundItems = fileIds.every((id) => sharedFiles.includes(id)); if (!foundItems) { - const message = 'Not all files are shared yet'; - logger.error(message); - throw new Error(message); + throw new Error('Not all files are shared yet'); } }; diff --git a/projects/aca-playwright-shared/src/api/sites-api.ts b/projects/aca-playwright-shared/src/api/sites-api.ts index 9e9fdd05f..75c3ce687 100755 --- a/projects/aca-playwright-shared/src/api/sites-api.ts +++ b/projects/aca-playwright-shared/src/api/sites-api.ts @@ -58,9 +58,14 @@ export class SitesApi { try { return await this.apiService.sites.createSite(site); } catch (error) { - const message = `SitesApi ${this.createSite.name}: ${error}`; - logger.error(message); - throw new Error(message); + if (JSON.stringify(error).includes('409')) { + logger.warn(`[SitesApi] createSite: site "${siteId || title}" already exists, skipping creation`); + return this.getSite(siteId || title); + } else { + const message = `SitesApi ${this.createSite.name}: ${JSON.stringify(error)}`; + logger.error(message); + throw new Error(message); + } } } diff --git a/projects/aca-playwright-shared/src/base-config/playwright.config.ts b/projects/aca-playwright-shared/src/base-config/playwright.config.ts index fc4086272..5472c0a55 100644 --- a/projects/aca-playwright-shared/src/base-config/playwright.config.ts +++ b/projects/aca-playwright-shared/src/base-config/playwright.config.ts @@ -159,7 +159,7 @@ export const getGlobalConfig: PlaywrightTestConfig = { /* Retry on CI only */ retries: env.CI ? 2 : 0, /* Opt out of parallel tests on CI. */ - workers: 3, + workers: Number(env.PLAYWRIGHT_WORKERS) || 3, /* Reporter to use. See https://playwright.dev/docs/test-reporters */ reporter: [['list'], ...getReporter()], globalSetup: require.resolve('./global.setup'), diff --git a/projects/aca-playwright-shared/src/page-objects/components/actions-dropdown.component.ts b/projects/aca-playwright-shared/src/page-objects/components/actions-dropdown.component.ts index 7ec21fb51..72be3bfbe 100644 --- a/projects/aca-playwright-shared/src/page-objects/components/actions-dropdown.component.ts +++ b/projects/aca-playwright-shared/src/page-objects/components/actions-dropdown.component.ts @@ -59,6 +59,13 @@ export enum MimeType { PNGImage = 'PNG Image [image/png]' } +export interface ActionConfig { + type: ActionType; + value?: string; + mimeType?: MimeType; + destinationFolder?: string; +} + export class ActionsDropdownComponent extends BaseComponent { private static readonly rootElement = 'aca-edit-rule-dialog aca-rule-action-list'; @@ -67,6 +74,7 @@ export class ActionsDropdownComponent extends BaseComponent { private readonly ruleActionLocator = this.getChild('aca-rule-action'); private readonly addActionButtonLocator = this.getChild('[data-automation-id="rule-action-list-add-action-button"]'); private readonly actionDropdownLocator = this.getChild('[data-automation-id="rule-action-select"]'); + private readonly selectActionLocator = this.actionDropdownLocator.locator('span', { hasText: 'Select an action' }); private readonly actionAspectNameLocator = '[data-automation-id="header-aspect-name"] .adf-property-field'; private readonly actionCheckInInputLocator = '[data-automation-id="header-description"] input'; private readonly actionSimpleWorkflowStepInputLocator = '[data-automation-id="header-approve-step"] input'; @@ -84,14 +92,60 @@ export class ActionsDropdownComponent extends BaseComponent { super(page, ActionsDropdownComponent.rootElement); } - async selectAction(action: Partial, index: number): Promise { - if (index > 0) { + async selectActions(actions: (ActionType | ActionConfig)[]): Promise { + for (const action of actions) { + await this.selectSingleAction(action); + } + } + + private normalizeAction(action: ActionType | ActionConfig): ActionConfig { + if (typeof action === 'string') { + return { type: action }; + } + return action; + } + + private async selectSingleAction(action: ActionType | ActionConfig): Promise { + const { type, value, mimeType, destinationFolder } = this.normalizeAction(action); + + if (await this.selectActionLocator.isHidden()) { await this.addActionButtonLocator.click(); } - await this.actionDropdownLocator.nth(index).hover({ timeout: 1000 }); - await this.actionDropdownLocator.nth(index).click(); - const option = this.getOptionLocator(action); - await option.click(); + await this.selectActionLocator.scrollIntoViewIfNeeded(); + await this.selectActionLocator.hover({ timeout: 1000 }); + await this.selectActionLocator.click(); + await this.getOptionLocator(type).click(); + + const actionIndex = (await this.ruleActionLocator.count()) - 1; + + if (value) { + await this.insertActionValues(type, value, actionIndex); + } + + if (mimeType) { + await this.selectMimeType(mimeType, actionIndex); + } + + if (destinationFolder) { + await this.selectDestinationFolderTransformAndCopyContent(actionIndex, destinationFolder); + } + } + + private async insertActionValues(type: ActionType, value: string, actionIndex: number): Promise { + switch (type) { + case ActionType.AddAspect: + await this.insertAddAspectActionValues(value, actionIndex); + break; + case ActionType.CheckIn: + await this.insertCheckInActionValues(value, actionIndex); + break; + case ActionType.SpecialiseType: + await this.insertSpecialiseTypeActionValues(value, actionIndex); + break; + case ActionType.SimpleWorkflow: + await this.insertSimpleWorkflowActionValues(value, actionIndex); + break; + } } async dropdownSelection(selectValue: string, locator: string, index: number): Promise { diff --git a/projects/aca-playwright-shared/src/page-objects/components/breadcrumb/breadcrumb.component.ts b/projects/aca-playwright-shared/src/page-objects/components/breadcrumb/breadcrumb.component.ts index 35b83f12f..6fa932395 100755 --- a/projects/aca-playwright-shared/src/page-objects/components/breadcrumb/breadcrumb.component.ts +++ b/projects/aca-playwright-shared/src/page-objects/components/breadcrumb/breadcrumb.component.ts @@ -39,7 +39,7 @@ export class Breadcrumb extends BaseComponent { const itemTexts = await Promise.all( itemElements.map(async (elem) => { const text = await elem.innerText(); - return text.split('\nchevron_right')[0]; + return text.split('\nchevron_right')[0].trim(); }) ); return itemTexts; diff --git a/projects/aca-playwright-shared/src/page-objects/components/conditions.component.ts b/projects/aca-playwright-shared/src/page-objects/components/conditions.component.ts index 0c079246b..d8995c5a3 100644 --- a/projects/aca-playwright-shared/src/page-objects/components/conditions.component.ts +++ b/projects/aca-playwright-shared/src/page-objects/components/conditions.component.ts @@ -42,6 +42,12 @@ export enum Comparator { EndsWith = 'Ends with' } +export interface ConditionConfig { + field: Field; + value: string; + comparator?: Comparator; +} + export class ConditionComponent extends ManageRulesDialogComponent { private readonly getOptionLocator = (optionName: string): Locator => this.page.locator('[role=listbox] [role=option]', { hasText: optionName }).first(); @@ -60,6 +66,7 @@ export class ConditionComponent extends ManageRulesDialogComponent { } async addCondition(fields: Partial, value: string, index: number, comparators?: Partial): Promise { + await this.addConditionButton.first().scrollIntoViewIfNeeded(); await this.addConditionButton.first().click(); await this.selectField(fields, index); if (comparators) { @@ -73,7 +80,9 @@ export class ConditionComponent extends ManageRulesDialogComponent { } async addConditionGroup(fields: Partial, value: string, index: number, comparators?: Partial): Promise { + await this.addConditionGroupButton.last().scrollIntoViewIfNeeded(); await this.addConditionGroupButton.last().click(); + await this.addConditionButton.nth(index).scrollIntoViewIfNeeded(); await this.addConditionButton.nth(index).click(); await this.selectField(fields, index); if (comparators) { @@ -81,4 +90,18 @@ export class ConditionComponent extends ManageRulesDialogComponent { } await this.valueField.nth(index).fill(value); } + + async addConditions(conditions: ConditionConfig[]): Promise { + for (let i = 0; i < conditions.length; i++) { + const { field, value, comparator } = conditions[i]; + await this.addCondition(field, value, i, comparator); + } + } + + async addConditionGroups(conditions: ConditionConfig[]): Promise { + for (let i = 0; i < conditions.length; i++) { + const { field, value, comparator } = conditions[i]; + await this.addConditionGroup(field, value, i, comparator); + } + } }