From e7cd5741d247d95102c849f09f35e6b3bdc320d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20=C5=9Awiderski?= Date: Thu, 11 Jul 2024 10:53:04 +0200 Subject: [PATCH] [ACS-4892] [E2E] Created new tests for adding folder rules (#3895) * [ACS-4892] [E2E] Created new tests for adding folder rules * [ACS-4892] excluded one test for now * [ACS-4892] [E2E] The rest of test cases automated * [ACS-4892] deleted the unused if enum * [ACS-4892] review fixes 1 * [ACS-4892] review fixes 2 * [ACS-4892] review fixes 3 --- .../folder-rules/exclude.tests.json | 4 +- .../folder-rules/playwright.config.ts | 4 +- .../folder-rules/src/tests/actions.e2e.ts | 73 ----- .../folder-rules/src/tests/conditions.e2e.ts | 66 ----- .../src/tests/create-rules.e2e.ts | 280 ++++++++++++++++++ .../components/actions-dropdown.component.ts | 10 +- .../components/conditions.component.ts | 25 +- .../components/dataTable/toolbar.component.ts | 5 + .../dialogs/content-node-selector-dialog.ts | 21 +- .../page-objects/components/dialogs/index.ts | 1 + .../dialogs/link-rules.component.ts | 64 ++++ .../manage-rules-dialog.component.ts | 10 +- .../manageRules/manage-rules.component.ts | 23 +- .../src/page-objects/pages/nodes.page.ts | 13 +- 14 files changed, 433 insertions(+), 166 deletions(-) delete mode 100644 e2e/playwright/folder-rules/src/tests/actions.e2e.ts delete mode 100644 e2e/playwright/folder-rules/src/tests/conditions.e2e.ts create mode 100644 e2e/playwright/folder-rules/src/tests/create-rules.e2e.ts create mode 100755 projects/aca-playwright-shared/src/page-objects/components/dialogs/link-rules.component.ts diff --git a/e2e/playwright/folder-rules/exclude.tests.json b/e2e/playwright/folder-rules/exclude.tests.json index 0967ef424..c5d26040d 100644 --- a/e2e/playwright/folder-rules/exclude.tests.json +++ b/e2e/playwright/folder-rules/exclude.tests.json @@ -1 +1,3 @@ -{} +{ + "C691642": "https://hyland.atlassian.net/browse/ACS-4894" +} diff --git a/e2e/playwright/folder-rules/playwright.config.ts b/e2e/playwright/folder-rules/playwright.config.ts index 11aded7bf..21227baf7 100644 --- a/e2e/playwright/folder-rules/playwright.config.ts +++ b/e2e/playwright/folder-rules/playwright.config.ts @@ -34,9 +34,7 @@ const config: PlaywrightTestConfig = { { name: 'Folder Rules', testDir: './src/tests', - use: { - users: ['hruser'] - } + use: {} } ] }; diff --git a/e2e/playwright/folder-rules/src/tests/actions.e2e.ts b/e2e/playwright/folder-rules/src/tests/actions.e2e.ts deleted file mode 100644 index 961aad494..000000000 --- a/e2e/playwright/folder-rules/src/tests/actions.e2e.ts +++ /dev/null @@ -1,73 +0,0 @@ -/*! - * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. - * - * Alfresco Example Content Application - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * from Hyland Software. If not, see . - */ - -import { expect } from '@playwright/test'; -import { ActionType, ApiClientFactory, getUserState, test, Utils } from '@alfresco/playwright-shared'; - -test.use({ storageState: getUserState('hruser') }); -test.describe('Folder Rules Actions', () => { - const apiClientFactory = new ApiClientFactory(); - const randomFolderName = `folder-rules-actions-${Utils.random()}`; - const randomRuleName = `playwright-rule-${Utils.random()}`; - const checkInValue = 'check In Value'; - const actionValue = ' A site which contains sfdc content [sfdc:site] '; - const autoDeclareOptionsValue = 'For all major and minor versions [ALL]'; - const simpleWorkFlow = 'accept reject'; - - let folderId: string; - - test.beforeAll(async () => { - await apiClientFactory.setUpAcaBackend('hruser'); - const node = await apiClientFactory.nodes.createNode('-my-', { name: randomFolderName, nodeType: 'cm:folder' }); - folderId = node.entry.id; - }); - - test.beforeEach(async ({ personalFiles }) => { - await personalFiles.navigate({ remoteUrl: `#/nodes/${folderId}/rules` }); - }); - - test.afterAll(async () => { - await apiClientFactory.nodes.deleteNode(folderId, { permanent: true }); - }); - - test('[C691637] Create a rule with actions', async ({ nodesPage }) => { - await nodesPage.toolbar.clickCreateRuleButton(); - await nodesPage.manageRulesDialog.ruleNameInputLocator.type(randomRuleName); - - await nodesPage.actionsDropdown.selectAction(ActionType.HideRecord, 0); - await nodesPage.actionsDropdown.selectAction(ActionType.IncrementCounter, 1); - await nodesPage.actionsDropdown.selectAction(ActionType.CheckIn, 2); - await nodesPage.actionsDropdown.insertCheckInActionValues(checkInValue, 2); - await nodesPage.actionsDropdown.selectAction(ActionType.AddAspect, 3); - await nodesPage.actionsDropdown.insertAddAspectActionValues(actionValue, 3); - await nodesPage.actionsDropdown.selectAction(ActionType.AutoDeclareOptions, 4); - await nodesPage.actionsDropdown.insertAutoDeclareOptionsActionValues(autoDeclareOptionsValue, 4); - await nodesPage.actionsDropdown.selectAction(ActionType.SimpleWorkflow, 5); - await nodesPage.actionsDropdown.insertSimpleWorkflowActionValues(simpleWorkFlow, 5); - - await nodesPage.manageRulesDialog.createRuleButton.click(); - - await expect.soft(nodesPage.manageRules.getGroupsList(randomRuleName)).toBeVisible(); - }); -}); diff --git a/e2e/playwright/folder-rules/src/tests/conditions.e2e.ts b/e2e/playwright/folder-rules/src/tests/conditions.e2e.ts deleted file mode 100644 index 010673bf4..000000000 --- a/e2e/playwright/folder-rules/src/tests/conditions.e2e.ts +++ /dev/null @@ -1,66 +0,0 @@ -/*! - * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. - * - * Alfresco Example Content Application - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * from Hyland Software. If not, see . - */ - -import { expect } from '@playwright/test'; -import { ActionType, ApiClientFactory, Comparator, Field, getUserState, test, Utils } from '@alfresco/playwright-shared'; - -test.use({ storageState: getUserState('hruser') }); -test.describe('Folder Rules Conditions', () => { - const apiClientFactory = new ApiClientFactory(); - const randomFolderName = `folder-rules-conditions-${Utils.random()}`; - const randomRuleName = `playwright-rule-${Utils.random()}`; - const specialChars = '!@£$%^&*()~#/'; - - let folderId: string; - - test.beforeAll(async () => { - await apiClientFactory.setUpAcaBackend('hruser'); - const node = await apiClientFactory.nodes.createNode('-my-', { name: randomFolderName, nodeType: 'cm:folder' }); - folderId = node.entry.id; - }); - - test.beforeEach(async ({ personalFiles }) => { - await personalFiles.navigate(); - }); - - test.afterAll(async () => { - await apiClientFactory.nodes.deleteNode(folderId, { permanent: true }); - }); - - test('[C691638] Create a rule with condition', async ({ personalFiles, nodesPage }) => { - await personalFiles.dataTable.performActionFromExpandableMenu(randomFolderName, 'Manage rules'); - - await nodesPage.toolbar.clickCreateRuleButton(); - await nodesPage.manageRulesDialog.ruleNameInputLocator.type(randomRuleName); - await nodesPage.conditionsDropdown.addCondition(Field.Size, Comparator.Equals, specialChars, 0); - await nodesPage.conditionsDropdown.addCondition(Field.Size, Comparator.Equals, specialChars, 1); - await nodesPage.conditionsDropdown.addConditionGroupButton.click(); - await nodesPage.conditionsDropdown.addConditionGroup(Field.Size, Comparator.Equals, specialChars, 0); - await nodesPage.conditionsDropdown.addConditionGroup(Field.Size, Comparator.Equals, specialChars, 1); - await nodesPage.actionsDropdown.selectAction(ActionType.IncrementCounter, 0); - await nodesPage.manageRulesDialog.createRuleButton.click(); - - await expect.soft(nodesPage.manageRules.getGroupsList(randomRuleName)).toBeVisible(); - }); -}); diff --git a/e2e/playwright/folder-rules/src/tests/create-rules.e2e.ts b/e2e/playwright/folder-rules/src/tests/create-rules.e2e.ts new file mode 100644 index 000000000..9a3117e25 --- /dev/null +++ b/e2e/playwright/folder-rules/src/tests/create-rules.e2e.ts @@ -0,0 +1,280 @@ +/*! + * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. + * + * Alfresco Example Content Application + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * from Hyland Software. If not, see . + */ + +import { expect } from '@playwright/test'; +import { ActionType, ApiClientFactory, test, Utils, TrashcanApi, NodesApi, Comparator, Field } from '@alfresco/playwright-shared'; + +test.use({ launchOptions: { slowMo: 300 } }); +test.describe('Folder Rules Actions', () => { + const apiClientFactory = new ApiClientFactory(); + let nodesApi: NodesApi; + let trashcanApi: TrashcanApi; + const username = `user-e2e-${Utils.random()}`; + const folderName883 = `folder-XAT-883-${Utils.random()}`; + const folderName883_2 = `folder-XAT-883-2-${Utils.random()}`; + const folderName883_3 = `folder-XAT-883-3-${Utils.random()}`; + + let randomRuleName: string; + const copyFileName = `copy-file-XAT-888-${Utils.random()}`; + const specialChars = '!@£$%^&*()~#/'; + const testString = '"!@£$%^&*()_+{}|:""?><,/.\';][=-`~"'; + + let folderName883Id: string; + let folderName883Id2: string; + let folderName883Id3: string; + + test.beforeAll(async () => { + try { + await apiClientFactory.setUpAcaBackend('admin'); + await apiClientFactory.createUser({ username }); + nodesApi = await NodesApi.initialize(username, username); + trashcanApi = await TrashcanApi.initialize(username, username); + } catch (error) { + console.error(`beforeAll failed : ${error}`); + } + + folderName883Id = (await nodesApi.createFolder(folderName883)).entry.id; + folderName883Id2 = (await nodesApi.createFolder(folderName883_2)).entry.id; + folderName883Id3 = (await nodesApi.createFolder(folderName883_3, folderName883Id)).entry.id; + await nodesApi.createFile(copyFileName, folderName883Id); + }); + + test.beforeEach(async ({ loginPage }) => { + await Utils.tryLoginUser(loginPage, username, username, 'beforeEach failed'); + randomRuleName = `rule-XAT-${Utils.random()}`; + }); + + test.afterAll(async () => { + 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/${folderName883Id}/rules` }); + await nodesPage.toolbar.clickCreateRuleButton(); + await nodesPage.manageRulesDialog.ruleNameInputLocator.fill(testString); + await nodesPage.manageRulesDialog.ruleDescriptionInputLocator.fill(testString); + + await nodesPage.actionsDropdown.selectAction(ActionType.IncrementCounter, 0); + 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/${folderName883Id}/rules` }); + await nodesPage.toolbar.clickCreateRuleButton(); + await nodesPage.manageRulesDialog.ruleNameInputLocator.fill(randomRuleName); + await nodesPage.actionsDropdown.selectAction(ActionType.IncrementCounter, 0); + await nodesPage.manageRulesDialog.createRuleButton.click(); + + await personalFiles.navigate({ remoteUrl: `#/nodes/${folderName883Id2}/rules` }); + await nodesPage.toolbar.clickLinkRulesButton(); + await nodesPage.linkRulesDialog.waitForLinkRules(); + await nodesPage.linkRulesDialog.getFolderIcon.click(); + await nodesPage.linkRulesDialog.getOptionLocator(username).click(); + await nodesPage.linkRulesDialog.selectDestination(folderName883); + 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/${folderName883Id}/rules` }); + await nodesPage.toolbar.clickCreateRuleButton(); + await nodesPage.manageRulesDialog.ruleNameInputLocator.fill(randomRuleName); + await nodesPage.actionsDropdown.selectAction(ActionType.IncrementCounter, 0); + await nodesPage.manageRulesDialog.ruleSubfoldersCheckbox.click(); + await nodesPage.manageRulesDialog.createRuleButton.click(); + + await personalFiles.navigate({ remoteUrl: `#/nodes/${folderName883Id3}/rules` }); + await nodesPage.manageRules.checkIfRuleIsOnTheList(randomRuleName); + }); + + test('[XAT-886] Create a rule and press cancel', async ({ personalFiles, nodesPage }) => { + await personalFiles.navigate({ remoteUrl: `#/nodes/${folderName883Id}/rules` }); + await nodesPage.toolbar.clickCreateRuleButton(); + await expect(nodesPage.manageRulesDialog.createRuleButton).toBeDisabled(); + await nodesPage.manageRulesDialog.cancelRuleButton.click(); + expect(nodesPage.manageRules.checkIfRuleListEmpty()).toBeTruthy(); + }); + + test('[XAT-887] Create a disabled rule', async ({ personalFiles, nodesPage }) => { + await personalFiles.navigate({ remoteUrl: `#/nodes/${folderName883Id}/rules` }); + await nodesPage.toolbar.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('[XAT-888] Create a rule with multiple actions', async ({ personalFiles, nodesPage }) => { + const checkInValue = 'check In Value'; + const actionValue = ' A site which contains sfdc content [sfdc:site] '; + const autoDeclareOptionsValue = 'For all major and minor versions [ALL]'; + const simpleWorkFlow = 'accept reject'; + + await personalFiles.navigate({ remoteUrl: `#/nodes/${folderName883Id}/rules` }); + await nodesPage.toolbar.clickCreateRuleButton(); + await nodesPage.manageRulesDialog.ruleNameInputLocator.fill(randomRuleName); + + await nodesPage.actionsDropdown.selectAction(ActionType.HideRecord, 0); + await nodesPage.actionsDropdown.selectAction(ActionType.IncrementCounter, 1); + await nodesPage.actionsDropdown.selectAction(ActionType.CheckIn, 2); + await nodesPage.actionsDropdown.insertCheckInActionValues(checkInValue, 2); + await nodesPage.actionsDropdown.selectAction(ActionType.AddAspect, 3); + await nodesPage.actionsDropdown.insertAddAspectActionValues(actionValue, 3); + await nodesPage.actionsDropdown.selectAction(ActionType.AutoDeclareOptions, 4); + await nodesPage.actionsDropdown.insertAutoDeclareOptionsActionValues(autoDeclareOptionsValue, 4); + await nodesPage.actionsDropdown.selectAction(ActionType.SimpleWorkflow, 5); + await nodesPage.actionsDropdown.insertSimpleWorkflowActionValues(simpleWorkFlow, 5); + + 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/${folderName883Id}/rules` }); + await nodesPage.toolbar.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(folderName883_2); + await nodesPage.contentNodeSelectorDialog.actionButton.click(); + await nodesPage.manageRulesDialog.createRuleButton.click(); + await nodesPage.manageRules.checkIfRuleIsOnTheList(randomRuleName); + + await personalFiles.navigate({ remoteUrl: `#/personal-files/${folderName883Id}` }); + await personalFiles.dataTable.selectItem(copyFileName); + await personalFiles.acaHeader.clickMoreActions(); + await personalFiles.acaHeader.matMenu.clickMenuItem('Delete'); + await personalFiles.snackBar.message.waitFor({ state: 'visible' }); + + await personalFiles.navigate({ remoteUrl: `#/personal-files/${folderName883Id2}` }); + 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/${folderName883Id}/rules` }); + await nodesPage.toolbar.clickCreateRuleButton(); + await nodesPage.manageRulesDialog.ruleNameInputLocator.fill(randomRuleName); + await nodesPage.actionsDropdown.selectAction(ActionType.AddAspect, 0); + await nodesPage.actionsDropdown.insertAddAspectActionValues('Controls', 0); + await nodesPage.actionsDropdown.selectAction(ActionType.AddAspect, 1); + await nodesPage.actionsDropdown.insertAddAspectActionValues('CMM', 1); + await nodesPage.actionsDropdown.selectAction(ActionType.AddAspect, 2); + await nodesPage.actionsDropdown.insertAddAspectActionValues('folder', 2); + await nodesPage.actionsDropdown.selectAction(ActionType.AddAspect, 3); + await nodesPage.actionsDropdown.insertAddAspectActionValues('site which', 3); + await nodesPage.manageRulesDialog.createRuleButton.click(); + await nodesPage.manageRulesDialog.createRuleButton.waitFor({ state: 'hidden' }); + await nodesPage.manageRules.getGroupsList(randomRuleName).click(); + + await nodesPage.manageRules.checkAspects(['sc:controlsAreClearance', 'sfdc:objectModel', 'sfdc:folder', 'sfdc:site']); + }); + + test('[XAT-891] Prevent rule creation after clicking on cancel during selecting destination folder', async ({ nodesPage, personalFiles }) => { + await personalFiles.navigate({ remoteUrl: `#/nodes/${folderName883Id}/rules` }); + await nodesPage.toolbar.clickCreateRuleButton(); + await nodesPage.manageRulesDialog.ruleNameInputLocator.fill(randomRuleName); + await nodesPage.actionsDropdown.selectAction(ActionType.AddAspect, 0); + await nodesPage.actionsDropdown.insertAddAspectActionValues('Controls', 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('[XAT-892] Prevent rule creation when missing any required field for action', async ({ nodesPage, personalFiles }) => { + await personalFiles.navigate({ remoteUrl: `#/nodes/${folderName883Id}/rules` }); + await nodesPage.toolbar.clickCreateRuleButton(); + await nodesPage.manageRulesDialog.ruleNameInputLocator.fill(randomRuleName); + await nodesPage.actionsDropdown.selectAction(ActionType.AddAspect, 0); + await nodesPage.actionsDropdown.insertAddAspectActionValues('Controls', 0); + await expect(nodesPage.manageRulesDialog.createRuleButton).toBeEnabled(); + await nodesPage.actionsDropdown.selectAction(ActionType.Copy, 1); + 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/${folderName883Id}/rules` }); + await nodesPage.toolbar.clickCreateRuleButton(); + await nodesPage.manageRulesDialog.ruleNameInputLocator.fill(randomRuleName); + await nodesPage.actionsDropdown.selectAction(ActionType.AddAspect, 0); + await nodesPage.actionsDropdown.insertAddAspectActionValues('Controls', 0); + 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/${folderName883Id}/rules` }); + await nodesPage.toolbar.clickCreateRuleButton(); + await nodesPage.manageRulesDialog.ruleNameInputLocator.fill(randomRuleName); + await nodesPage.actionsDropdown.selectAction(ActionType.AddAspect, 0); + await nodesPage.actionsDropdown.insertAddAspectActionValues('Controls', 0); + await expect(nodesPage.manageRulesDialog.createRuleButton).toBeEnabled(); + await nodesPage.actionsDropdown.selectAction(ActionType.CheckIn, 1); + 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/${folderName883Id}/rules` }); + await nodesPage.toolbar.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(); + + 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/${folderName883Id}/rules` }); + await nodesPage.toolbar.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(); + + await nodesPage.manageRules.checkIfRuleIsOnTheList(randomRuleName); + }); +}); 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 9368b2116..d1144691b 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 @@ -50,13 +50,13 @@ export enum ActionType { } export class ActionsDropdownComponent extends BaseComponent { - private static rootElement = 'aca-rule-action-list'; + private static rootElement = 'aca-edit-rule-dialog aca-rule-action-list'; private getOptionLocator = (optionName: string): Locator => this.page.locator('.mat-select-panel .mat-option-text', { hasText: optionName }).first(); private ruleActionLocator = this.getChild('aca-rule-action'); private addActionButtonLocator = this.getChild('[data-automation-id="rule-action-list-add-action-button"]'); private actionDropdownLocator = this.getChild('[data-automation-id="rule-action-select"]'); - private actionAspectNameLocator = '[data-automation-id="header-aspect-name"] mat-select'; + private actionAspectNameLocator = '[data-automation-id="header-aspect-name"] .adf-property-field'; private actionCheckInInputLocator = '[data-automation-id="header-description"] input'; private actionAutoDeclareLocator = '[data-automation-id="header-version"] mat-select'; private actionSimpleWorkflowStepInputLocator = '[data-automation-id="header-approve-step"] input'; @@ -85,7 +85,7 @@ export class ActionsDropdownComponent extends BaseComponent { } async insertCheckInActionValues(checkInValue: string, index: number): Promise { - await this.ruleActionLocator.nth(index).locator(this.actionCheckInInputLocator).type(checkInValue, { delay: 50 }); + await this.ruleActionLocator.nth(index).locator(this.actionCheckInInputLocator).fill(checkInValue); } async insertAddAspectActionValues(AspectValue: string, index: number): Promise { @@ -97,11 +97,11 @@ export class ActionsDropdownComponent extends BaseComponent { } async insertSimpleWorkflowActionValues(stepValue: string, index: number): Promise { - await this.ruleActionLocator.nth(index).locator(this.actionSimpleWorkflowStepInputLocator).type(stepValue, { delay: 50 }); + await this.ruleActionLocator.nth(index).locator(this.actionSimpleWorkflowStepInputLocator).fill(stepValue); await this.ruleActionLocator.nth(index).locator(this.actionSimpleWorkflowApproveFolderLocator).click(); await this.page.locator(this.actionSimpleWorkflowActionChoiceLocator).click(); await this.ruleActionLocator.nth(index).locator(this.actionSimpleWorkflowLabelApproveLocator).click(); - await this.ruleActionLocator.nth(index).locator(this.actionSimpleWorkflowSRejectStepLocator).type(stepValue, { delay: 50 }); + await this.ruleActionLocator.nth(index).locator(this.actionSimpleWorkflowSRejectStepLocator).fill(stepValue); await this.ruleActionLocator.nth(index).locator(this.actionSimpleWorkflowRejectFolderLocator).click(); await this.page.locator(this.actionSimpleWorkflowActionChoiceLocator).click(); } 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 5ba5eeea0..957d34ae1 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 @@ -28,7 +28,11 @@ import { ManageRulesDialogComponent } from './manageRules/manage-rules-dialog.co export enum Field { Name = 'Name', Size = 'Size', - Mimetype = 'Mimetype' + Mimetype = 'Mimetype', + Encoding = 'Encoding', + HasCategory = 'Has category', + HasTag = 'Has tag', + HasAspect = 'Has aspect' } export enum Comparator { @@ -53,17 +57,22 @@ export class ConditionComponent extends ManageRulesDialogComponent { await option.click(); } - async addCondition(fields: Partial, comparators: Partial, value: string, index: number): Promise { + async addCondition(fields: Partial, value: string, index: number, comparators?: Partial): Promise { await this.addConditionButton.click(); await this.selectField(fields, index); - await this.selectComparator(comparators, index); - await this.valueField.nth(index).type(value); + if (comparators) { + await this.selectComparator(comparators, index); + } + await this.valueField.nth(index).fill(value); } - async addConditionGroup(fields: Partial, comparators: Partial, value: string, index: number): Promise { - await this.addConditionButton.nth(0).click(); + async addConditionGroup(fields: Partial, value: string, index: number, comparators?: Partial): Promise { + await this.addConditionGroupButton.last().click(); + await this.addConditionButton.nth(index).click(); await this.selectField(fields, index); - await this.selectComparator(comparators, index); - await this.valueField.nth(index).type(value); + if (comparators) { + await this.selectComparator(comparators, index); + } + await this.valueField.nth(index).fill(value); } } diff --git a/projects/aca-playwright-shared/src/page-objects/components/dataTable/toolbar.component.ts b/projects/aca-playwright-shared/src/page-objects/components/dataTable/toolbar.component.ts index bab77ede9..47a6773e6 100644 --- a/projects/aca-playwright-shared/src/page-objects/components/dataTable/toolbar.component.ts +++ b/projects/aca-playwright-shared/src/page-objects/components/dataTable/toolbar.component.ts @@ -28,6 +28,7 @@ import { Page } from '@playwright/test'; export class ToolbarComponent extends BaseComponent { private static rootElement = 'adf-toolbar'; private createRuleButton = this.getChild('[data-automation-id="manage-rules-create-button"]'); + private linkRulesButton = this.getChild('[data-automation-id="manage-rules-link-button"]'); constructor(page: Page) { super(page, ToolbarComponent.rootElement); @@ -36,4 +37,8 @@ export class ToolbarComponent extends BaseComponent { async clickCreateRuleButton(): Promise { await this.createRuleButton.click(); } + + async clickLinkRulesButton(): Promise { + await this.linkRulesButton.click(); + } } diff --git a/projects/aca-playwright-shared/src/page-objects/components/dialogs/content-node-selector-dialog.ts b/projects/aca-playwright-shared/src/page-objects/components/dialogs/content-node-selector-dialog.ts index e886c31dd..92fdc0669 100755 --- a/projects/aca-playwright-shared/src/page-objects/components/dialogs/content-node-selector-dialog.ts +++ b/projects/aca-playwright-shared/src/page-objects/components/dialogs/content-node-selector-dialog.ts @@ -22,7 +22,7 @@ * along with Alfresco. If not, see . */ -import { Locator, Page } from '@playwright/test'; +import { Locator, Page, expect } from '@playwright/test'; import { BaseComponent } from '../base.component'; export class ContentNodeSelectorDialog extends BaseComponent { @@ -40,13 +40,13 @@ export class ContentNodeSelectorDialog extends BaseComponent { private getRowByName = (name: string | number): Locator => this.getChild(`adf-datatable-row`, { hasText: name.toString() }); getDialogTitle = (text: string) => this.getChild('[data-automation-id="content-node-selector-title"]', { hasText: text }); getBreadcrumb = (text: string) => this.getChild('[data-automation-id="current-folder"]', { hasText: text }); - getFolderIcon = this.getChild('mat-icon[role="img"]', { hasText: "folder" }); + getFolderIcon = this.getChild('[data-automation-id="dropdown-breadcrumb-trigger"]'); loadMoreButton = this.getChild('[data-automation-id="adf-infinite-pagination-button"]'); async loadMoreNodes(): Promise { await this.spinnerWaitForReload(); while (await this.loadMoreButton.isVisible()) { - await this.loadMoreButton.click(); + await this.loadMoreButton.click(); } } @@ -59,8 +59,17 @@ export class ContentNodeSelectorDialog extends BaseComponent { async selectDestination(folderName: string): Promise { const row = this.getRowByName(folderName); - await row.click(); - await this.selectedRow.waitFor({ state: 'attached' }); - await this.selectedRow.isVisible(); + + await expect(row).toBeVisible(); + await row.click({ trial: true }); + + await expect(async () => { + await row.hover({ timeout: 1000 }); + await row.click(); + await expect(this.selectedRow).toBeVisible(); + }).toPass({ + intervals: [2_000, 2_000, 2_000, 2_000, 2_000, 2_000, 2_000], + timeout: 20_000 + }); } } diff --git a/projects/aca-playwright-shared/src/page-objects/components/dialogs/index.ts b/projects/aca-playwright-shared/src/page-objects/components/dialogs/index.ts index 3a01a9173..26b812f2d 100644 --- a/projects/aca-playwright-shared/src/page-objects/components/dialogs/index.ts +++ b/projects/aca-playwright-shared/src/page-objects/components/dialogs/index.ts @@ -34,3 +34,4 @@ export * from './upload-new-version-dialog.component'; export * from './manage-versions-dialog.component'; export * from './upload-dialog.component'; export * from './delete-trash-dialog.component'; +export * from './link-rules.component'; diff --git a/projects/aca-playwright-shared/src/page-objects/components/dialogs/link-rules.component.ts b/projects/aca-playwright-shared/src/page-objects/components/dialogs/link-rules.component.ts new file mode 100755 index 000000000..d6f1af24c --- /dev/null +++ b/projects/aca-playwright-shared/src/page-objects/components/dialogs/link-rules.component.ts @@ -0,0 +1,64 @@ +/*! + * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. + * + * Alfresco Example Content Application + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { Locator, Page, expect } from '@playwright/test'; +import { BaseComponent } from '../base.component'; + +export class LinkRulesDialog extends BaseComponent { + private static rootElement = 'aca-rule-set-picker'; + + constructor(page: Page) { + super(page, LinkRulesDialog.rootElement); + } + + cancelButton = this.getChild('[data-automation-id="content-node-selector-actions-cancel"]'); + selectFolderButton = this.getChild('button', { hasText: ' Select folder ' }); + emptyLinkRules = this.getChild('.adf-empty-content__title'); + getOptionLocator = (optionName: string): Locator => this.page.locator('.mat-select-panel .mat-option-text', { hasText: optionName }); + private getRowByName = (name: string | number): Locator => this.getChild(`adf-datatable-row`, { hasText: name.toString() }); + getDialogTitle = (text: string) => this.getChild('[data-automation-id="content-node-selector-title"]', { hasText: text }); + getBreadcrumb = (text: string) => this.getChild('[data-automation-id="current-folder"]', { hasText: text }); + getFolderIcon = this.getChild('.adf-dropdown-breadcrumb-icon', { hasText: 'folder' }); + getLibraryIcon = this.getChild('.adf-empty-content__icon', { hasText: 'library_books' }); + + async selectDestination(folderName: string): Promise { + const row = this.getRowByName(folderName); + + await expect(row).toBeVisible(); + await row.click({ trial: true }); + + await expect(async () => { + await row.hover({ timeout: 1000 }); + await row.click(); + await expect(this.selectFolderButton).toBeEnabled(); + }).toPass({ + intervals: [2_000, 2_000, 2_000, 2_000, 2_000, 2_000, 2_000], + timeout: 20_000 + }); + } + + async waitForLinkRules(): Promise { + await this.getLibraryIcon.waitFor(); + } +} diff --git a/projects/aca-playwright-shared/src/page-objects/components/manageRules/manage-rules-dialog.component.ts b/projects/aca-playwright-shared/src/page-objects/components/manageRules/manage-rules-dialog.component.ts index e75df3999..d6c542216 100644 --- a/projects/aca-playwright-shared/src/page-objects/components/manageRules/manage-rules-dialog.component.ts +++ b/projects/aca-playwright-shared/src/page-objects/components/manageRules/manage-rules-dialog.component.ts @@ -29,15 +29,23 @@ export class ManageRulesDialogComponent extends BaseComponent { private static rootElement = 'aca-edit-rule-dialog'; public createRuleButton = this.getChild('[data-automation-id="edit-rule-dialog-submit"]'); + public cancelRuleButton = this.getChild('.aca-edit-rule-dialog__footer button').filter({ hasText: 'Cancel' }); public ruleNameInputLocator = this.getChild('[id="rule-details-name-input"]'); + public ruleDescriptionInputLocator = this.getChild('[id="rule-details-description-textarea"]'); public addConditionButton = this.getChild('[data-automation-id="add-condition-button"]'); public addConditionGroupButton = this.getChild('[data-automation-id="add-group-button"]'); public fieldDropDown = this.getChild('[data-automation-id="field-select"]'); public comparatorDropDown = this.getChild('[data-automation-id="comparator-select"]'); public valueField = this.getChild('[data-automation-id="value-input"]'); + public whenCreatedCheckbox = this.getChild('[data-automation-id="rule-trigger-checkbox-inbound"]'); + public whenUpdatedCheckbox = this.getChild('[data-automation-id="rule-trigger-checkbox-update"]'); + public whenDeletedCheckbox = this.getChild('[data-automation-id="rule-trigger-checkbox-outbound"]'); + public destinationFolderButton = this.getChild('[data-automation-id="card-textitem-clickable-icon-destination-folder"]'); + public ruleInBackgroundCheckbox = this.getChild('[data-automation-id="rule-option-checkbox-asynchronous"]'); + public ruleSubfoldersCheckbox = this.getChild('[data-automation-id="rule-option-checkbox-inheritable"]'); + public ruleDisableCheckbox = this.getChild('[data-automation-id="rule-option-checkbox-disabled"]'); constructor(page: Page) { super(page, ManageRulesDialogComponent.rootElement); } - } diff --git a/projects/aca-playwright-shared/src/page-objects/components/manageRules/manage-rules.component.ts b/projects/aca-playwright-shared/src/page-objects/components/manageRules/manage-rules.component.ts index 6187a1180..10268e2ef 100644 --- a/projects/aca-playwright-shared/src/page-objects/components/manageRules/manage-rules.component.ts +++ b/projects/aca-playwright-shared/src/page-objects/components/manageRules/manage-rules.component.ts @@ -22,7 +22,7 @@ * from Hyland Software. If not, see . */ -import { Locator, Page } from '@playwright/test'; +import { Locator, Page, expect } from '@playwright/test'; import { BaseComponent } from '../base.component'; export class ManageRules extends BaseComponent { @@ -31,8 +31,29 @@ export class ManageRules extends BaseComponent { public getGroupsList = (optionName: string): Locator => this.getChild('.aca-rule-list-item__header', { hasText: optionName }); public ruleToggle = this.getChild('.aca-manage-rules__container .mat-slide-toggle-bar').first(); public ruleToggleFalse = this.getChild('aca-rule-list-grouping input[type="checkbox"][aria-checked="false"]').first(); + public ruleDetailsTitle = this.getChild('.aca-manage-rules__container__rule-details__header__title__name'); + public ruleDetailsTrashButton = this.getChild('#delete-rule-btn'); + public ruleDetailsEditButton = this.getChild('#edit-rule-btn'); + public ruleDetailsWhenText = this.getChild('[data-automation-id="rule-details-triggers-component"]'); + public ruleDetailsPerformActionsDiv = this.getChild('adf-card-view-textitem mat-form-field input'); + public rulesEmptyListTitle = this.getChild('.adf-empty-content__title'); constructor(page: Page) { super(page, ManageRules.rootElement); } + + async checkAspects(aspects: string[]): Promise { + for (let i = 0; i < aspects.length; i++) { + const aspectsActions = await this.ruleDetailsPerformActionsDiv.nth(i).inputValue(); + expect(aspects).toContain(aspectsActions); + } + } + + async checkIfRuleListEmpty(): Promise { + return await this.rulesEmptyListTitle.isVisible(); + } + + async checkIfRuleIsOnTheList(ruleName: string): Promise { + await expect(this.getGroupsList(ruleName)).toBeVisible({ timeout: 5000 }); + } } diff --git a/projects/aca-playwright-shared/src/page-objects/pages/nodes.page.ts b/projects/aca-playwright-shared/src/page-objects/pages/nodes.page.ts index 12dd3ff22..1da32c2b2 100644 --- a/projects/aca-playwright-shared/src/page-objects/pages/nodes.page.ts +++ b/projects/aca-playwright-shared/src/page-objects/pages/nodes.page.ts @@ -23,10 +23,17 @@ */ import { Page } from '@playwright/test'; -import { ConditionComponent, ManageRules, ManageRulesDialogComponent, ToolbarComponent, ActionsDropdownComponent } from '../components'; +import { + ConditionComponent, + ManageRules, + ManageRulesDialogComponent, + ToolbarComponent, + ActionsDropdownComponent, + ContentNodeSelectorDialog, + LinkRulesDialog +} from '../components'; import { BasePage } from './base.page'; - export class NodesPage extends BasePage { private static pageUrl = 'nodes'; @@ -39,4 +46,6 @@ export class NodesPage extends BasePage { public actionsDropdown = new ActionsDropdownComponent(this.page); public conditionsDropdown = new ConditionComponent(this.page); public manageRules = new ManageRules(this.page); + public contentNodeSelectorDialog = new ContentNodeSelectorDialog(this.page); + public linkRulesDialog = new LinkRulesDialog(this.page); }