[ACS-4586] Implemented Playwright Framework and add it to CI/CD (#2985)

This commit is contained in:
Kristian Dimitrov
2023-02-16 17:23:08 +00:00
committed by GitHub
parent 197ef8f0e3
commit d68deab2bd
47 changed files with 1413 additions and 117 deletions

View File

@@ -0,0 +1,34 @@
/*
* Copyright © 2005 - 2023 Alfresco Software, Ltd. All rights reserved.
*
* License rights for this program may be obtained from Alfresco Software, Ltd.
* pursuant to a written agreement and any use of this program without such an
* agreement is prohibited.
*/
import { PersonalFilesPage, NodesPage } from '../page-objects';
import { test as base } from '@playwright/test';
import { ApiClientFactory } from '@alfresco/playwright-shared';
interface Pages {
personalFiles: PersonalFilesPage;
nodesPage: NodesPage;
}
interface Api {
apiClient: ApiClientFactory;
}
export const test = base.extend<Pages & Api>({
personalFiles: async ({ page }, use) => {
await use(new PersonalFilesPage(page));
},
nodesPage: async ({ page }, use) => {
await use(new NodesPage(page));
},
apiClient: async ({}, use) => {
const apiClient = new ApiClientFactory();
await apiClient.setUpAcaBackend('admin');
await use(apiClient);
}
});

View File

@@ -0,0 +1,32 @@
/*
* Copyright © 2005 - 2023 Alfresco Software, Ltd. All rights reserved.
*
* License rights for this program may be obtained from Alfresco Software, Ltd.
* pursuant to a written agreement and any use of this program without such an
* agreement is prohibited.
*/
import { Locator, Page } from '@playwright/test';
import { BaseComponent } from '@alfresco/playwright-shared';
export enum ActionType {
Aspect = 'Add aspect',
SimpleWorkflow = 'Add simple workflow',
IncrementCounter = 'Increment Counter'
}
export class ActionsDropdownComponent extends BaseComponent {
private static rootElement = '.mat-select-panel';
public getOptionLocator = (optionName: string): Locator => this.getChild('.mat-option-text', { hasText: optionName });
constructor(page: Page) {
super(page, ActionsDropdownComponent.rootElement);
}
async selectAction(action: Partial<ActionType>): Promise<void> {
await this.page.locator(`aca-edit-rule-dialog [data-automation-id="rule-action-select"]`).click();
const option = this.getOptionLocator(action);
await option.click();
}
}

View File

@@ -0,0 +1,50 @@
/*
* Copyright © 2005 - 2023 Alfresco Software, Ltd. All rights reserved.
*
* License rights for this program may be obtained from Alfresco Software, Ltd.
* pursuant to a written agreement and any use of this program without such an
* agreement is prohibited.
*/
import { Locator, Page } from '@playwright/test';
import { ManageRulesDialogComponent } from './manage-rules-dialog.component';
export enum Field {
Name = 'Name',
Size = 'Size',
Mimetype = 'Mimetype'
}
export enum Comparator {
Equals = '(=) Equals',
Contains = 'Contains',
StartsWith = 'Starts with',
EndsWith = 'Ends with'
}
export class ConditionComponent extends ManageRulesDialogComponent {
private getOptionLocator = (optionName: string): Locator => this.page.locator(`.cdk-overlay-pane .mat-option span`, { hasText: optionName });
constructor(page: Page) {
super(page);
}
private async selectField(fields: Partial<Field>): Promise<void> {
await this.fieldDropDown.click();
const option = this.getOptionLocator(fields);
await option.click();
}
private async selectComparator(comparators: Partial<Comparator>): Promise<void> {
await this.comparatorDropDown.click();
const option = this.getOptionLocator(comparators);
await option.click();
}
async addCondition(fields: Partial<Field>, comparators: Partial<Comparator>, value: string): Promise<void> {
await this.addConditionButton.click();
await this.selectField(fields);
await this.selectComparator(comparators);
await this.typeConditionValue(value);
}
}

View File

@@ -0,0 +1,33 @@
/*
* Copyright © 2005 - 2023 Alfresco Software, Ltd. All rights reserved.
*
* License rights for this program may be obtained from Alfresco Software, Ltd.
* pursuant to a written agreement and any use of this program without such an
* agreement is prohibited.
*/
import { BaseComponent } from '@alfresco/playwright-shared';
import { Page } from '@playwright/test';
export class ManageRulesDialogComponent extends BaseComponent {
private static rootElement = 'aca-edit-rule-dialog';
public createRuleButton = this.getChild('[data-automation-id="edit-rule-dialog-submit"]');
private ruleNameInputLocator = this.getChild('[id="rule-details-name-input"]');
public addConditionButton = this.getChild('[data-automation-id="add-condition-button"]');
public fieldDropDown = this.getChild('[data-automation-id="field-select"]');
public comparatorDropDown = this.getChild('[data-automation-id="comparator-select"]');
private valueField = this.getChild('[data-automation-id="value-input"]');
constructor(page: Page) {
super(page, ManageRulesDialogComponent.rootElement);
}
async typeRuleName(ruleName: string): Promise<void> {
await this.ruleNameInputLocator.type(ruleName, { delay: 50 });
}
async typeConditionValue(ruleName: string): Promise<void> {
await this.valueField.type(ruleName, { delay: 50 });
}
}

View File

@@ -0,0 +1,21 @@
/*
* Copyright © 2005 - 2023 Alfresco Software, Ltd. All rights reserved.
*
* License rights for this program may be obtained from Alfresco Software, Ltd.
* pursuant to a written agreement and any use of this program without such an
* agreement is prohibited.
*/
import { Locator, Page } from '@playwright/test';
import { BaseComponent } from '@alfresco/playwright-shared';
export class ManageRules extends BaseComponent {
private static rootElement = '.aca-manage-rules';
public getGroupsList = (optionName: string): Locator => this.getChild('.aca-rule-list-item__header', { hasText: optionName });
public disableRuleToggle = this.getChild('.aca-manage-rules__container .mat-slide-toggle-bar').first();
constructor(page: Page) {
super(page, ManageRules.rootElement);
}
}

View File

@@ -0,0 +1,10 @@
/*
* Copyright © 2005 - 2023 Alfresco Software, Ltd. All rights reserved.
*
* License rights for this program may be obtained from Alfresco Software, Ltd.
* pursuant to a written agreement and any use of this program without such an
* agreement is prohibited.
*/
export * from './pages/personal-files.page';
export * from './pages/nodes.page';

View File

@@ -0,0 +1,28 @@
/*
* Copyright © 2005 - 2023 Alfresco Software, Ltd. All rights reserved.
*
* License rights for this program may be obtained from Alfresco Software, Ltd.
* pursuant to a written agreement and any use of this program without such an
* agreement is prohibited.
*/
import { BasePage, ToolbarComponent } from '@alfresco/playwright-shared';
import { Page } from '@playwright/test';
import { ManageRulesDialogComponent } from '../components/manage-rules-dialog.component';
import { ActionsDropdownComponent } from '../components/actions-dropdown.component';
import { ConditionComponent } from '../components/conditions.component';
import { ManageRules } from '../components/manage-rules.component';
export class NodesPage extends BasePage {
private static pageUrl = 'nodes';
constructor(page: Page) {
super(page, NodesPage.pageUrl);
}
public toolbar = new ToolbarComponent(this.page);
public manageRulesDialog = new ManageRulesDialogComponent(this.page);
public actionsDropdown = new ActionsDropdownComponent(this.page);
public conditionsDropdown = new ConditionComponent(this.page);
public manageRules = new ManageRules(this.page);
}

View File

@@ -0,0 +1,20 @@
/*
* Copyright © 2005 - 2023 Alfresco Software, Ltd. All rights reserved.
*
* License rights for this program may be obtained from Alfresco Software, Ltd.
* pursuant to a written agreement and any use of this program without such an
* agreement is prohibited.
*/
import { BasePage, DataTableComponent } from '@alfresco/playwright-shared';
import { Page } from '@playwright/test';
export class PersonalFilesPage extends BasePage {
private static pageUrl = 'personal-files';
constructor(page: Page) {
super(page, PersonalFilesPage.pageUrl);
}
public dataTable = new DataTableComponent(this.page);
}

View File

@@ -0,0 +1,52 @@
import { PlaywrightTestConfig, devices } from '@playwright/test';
require('dotenv').config();
export const config: PlaywrightTestConfig = {
testDir: './',
expect: {
/**
* Maximum time expect() should wait for the condition to be met.
* For example in `await expect(locator).toHaveText();`
*/
timeout: 10000
},
/* Run tests in files in parallel */
fullyParallel: true,
/* Fail the build on CI if you accidentally left test.only in the source code. */
forbidOnly: !!process.env.CI,
/* Retry on CI only */
retries: process.env.CI ? 2 : 0,
/* Opt out of parallel tests on CI. */
workers: 5,
timeout: 20000,
globalSetup: require.resolve('../../shared/base-config/global.setup'),
use: {
/* Maximum time each action such as `click()` can take. Defaults to 0 (no limit). */
storageState: './storage-state/AdminUserState.json',
actionTimeout: 0,
/* Base URL to use in actions like `await page.goto('/')`. */
baseURL: process.env.PLAYWRIGHT_E2E_HOST,
ignoreHTTPSErrors: true,
bypassCSP: true,
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
trace: 'on-first-retry',
launchOptions: {
devtools: false,
args: ['--disable-web-security', '--no-sandbox', '--disable-site-isolation-trials']
}
},
/* Configure projects for major browsers */
projects: [
{
name: 'chromium',
use: {
...devices['Desktop Chrome']
}
}
]
};
export default config;

View File

@@ -0,0 +1,34 @@
import { test } from '../fixtures/page-initialization';
import { NodeBodyCreate } from '@alfresco/aca-testing-shared';
import { ActionType } from '../page-objects/components/actions-dropdown.component';
import { expect } from '@playwright/test';
test.describe('Folder Rules Actions', () => {
const randomFolderName = `playwright-folder-${(Math.random() + 1).toString(36).substring(6)}`;
const randomRuleName = `playwright-rule-${(Math.random() + 1).toString(36).substring(6)}`;
let folderId: string;
test.beforeAll(async ({ apiClient }) => {
folderId = (await apiClient.nodes.createNode('-my-', new NodeBodyCreate(randomFolderName, 'cm:folder'))).entry.id;
});
test.beforeEach(async ({ personalFiles }) => {
await personalFiles.navigate({ waitUntil: 'domcontentloaded' });
});
test.afterAll(async ({ apiClient }) => {
await apiClient.nodes.deleteNode(folderId);
});
test('Create a rule with actions', async ({ personalFiles, nodesPage }) => {
await personalFiles.dataTable.performActionFromExpandableMenu(randomFolderName, 'Manage rules');
await nodesPage.toolbar.clickCreateRuleButton();
await nodesPage.manageRulesDialog.typeRuleName(randomRuleName);
await nodesPage.actionsDropdown.selectAction(ActionType.IncrementCounter);
await nodesPage.manageRulesDialog.createRuleButton.click();
await expect.soft(nodesPage.manageRules.getGroupsList(randomRuleName)).toBeVisible();
});
});

View File

@@ -0,0 +1,37 @@
import { test } from '../fixtures/page-initialization';
import { NodeBodyCreate } from '@alfresco/aca-testing-shared';
import { ActionType } from '../page-objects/components/actions-dropdown.component';
import { Comparator, Field } from '../page-objects/components/conditions.component';
import { expect } from '@playwright/test';
test.describe('Folder Rules Conditions', () => {
const randomFolderName = `playwright-folder-${(Math.random() + 1).toString(36).substring(6)}`;
const randomRuleName = `playwright-rule-${(Math.random() + 1).toString(36).substring(6)}`;
const specialChars = '!@£$%^&*()~#/';
let folderId: string;
test.beforeAll(async ({ apiClient }) => {
folderId = (await apiClient.nodes.createNode('-my-', new NodeBodyCreate(randomFolderName, 'cm:folder'))).entry.id;
});
test.beforeEach(async ({ personalFiles }) => {
await personalFiles.navigate();
});
test.afterAll(async ({ apiClient }) => {
await apiClient.nodes.deleteNode(folderId);
});
test('Create a rule with condition', async ({ personalFiles, nodesPage }) => {
await personalFiles.dataTable.performActionFromExpandableMenu(randomFolderName, 'Manage rules');
await nodesPage.toolbar.clickCreateRuleButton();
await nodesPage.manageRulesDialog.typeRuleName(randomRuleName);
await nodesPage.conditionsDropdown.addCondition(Field.Size, Comparator.Equals, specialChars);
await nodesPage.actionsDropdown.selectAction(ActionType.IncrementCounter);
await nodesPage.manageRulesDialog.createRuleButton.click();
await expect.soft(nodesPage.manageRules.getGroupsList(randomRuleName)).toBeVisible();
});
});

View File

@@ -0,0 +1,27 @@
import { test } from '../fixtures/page-initialization';
import { NodeBodyCreate } from '@alfresco/aca-testing-shared';
test.describe('Rules - Manage Rules', () => {
const randomName = `playwright-folder-${(Math.random() + 1).toString(36).substring(6)}`;
const randomRuleName = `playwright-rule-${(Math.random() + 1).toString(36).substring(6)}`;
let folderId: string;
test.beforeAll(async ({ apiClient }) => {
folderId = (await apiClient.nodes.createNode('-my-', new NodeBodyCreate(randomName, 'cm:folder'))).entry.id;
await apiClient.createRandomRule(folderId, randomRuleName);
});
test.beforeEach(async ({ personalFiles }) => {
await personalFiles.navigate();
});
test.afterAll(async ({ apiClient }) => {
await apiClient.nodes.deleteNode(folderId);
});
test('Disable an existing rule', async ({ personalFiles, nodesPage }) => {
await personalFiles.dataTable.performActionFromExpandableMenu(randomName, 'Manage rules');
await nodesPage.manageRules.disableRuleToggle.click();
});
});