diff --git a/e2e/playwright/actions/src/tests/share/share-file.spec.ts b/e2e/playwright/actions/src/tests/share/share-file.spec.ts new file mode 100644 index 0000000000..e6e040b78e --- /dev/null +++ b/e2e/playwright/actions/src/tests/share/share-file.spec.ts @@ -0,0 +1,246 @@ +/*! + * Copyright © 2005-2023 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 { ApiClientFactory, NodesApi, test, timeouts, Utils, SharedLinksApi } from '@alfresco/playwright-shared'; +import { expect } from '@playwright/test'; + +test.describe('Share a file', () => { + const random = Utils.random(); + + const username = `user-${random}`; + const parent = `parent-${random}`; + let parentId: string; + + const file3 = `file3-${random}.txt`; + const file4 = `file4-${random}.txt`; + const file5 = `file5-${random}.txt`; + const file6 = `file6-${random}.txt`; + const file7 = `file7-${random}.txt`; + const file8 = `file8-${random}.txt`; + const file9 = `file9-${random}.txt`; + + const shareLinkPreUrl = `/#/preview/s/`; + + const apiClientFactory = new ApiClientFactory(); + + test.beforeAll(async () => { + await apiClientFactory.setUpAcaBackend('admin'); + await apiClientFactory.createUser({ username }); + const nodesApi = await NodesApi.initialize(username, username); + + parentId = (await nodesApi.createFolder(parent)).entry.id; + }); + + test.afterAll(async () => { + await apiClientFactory.nodes.deleteNodes([parentId]); + }); + + test.describe('when logged out', () => { + let file6SharedLink: string; + let file6Id: string; + + test.beforeAll(async () => { + const nodesApi = await NodesApi.initialize(username, username); + const shareApi = await SharedLinksApi.initialize(username, username); + + file6Id = (await nodesApi.createFile(file6, parentId))?.entry.id; + + const sharedId = (await shareApi.shareFileById(file6Id)).entry.id; + file6SharedLink = `${shareLinkPreUrl}${sharedId}`; + await shareApi.waitForFilesToBeShared([file6Id]); + }); + + test.afterAll(async () => { + await apiClientFactory.nodes.deleteNodes([file6Id]); + }); + + test('[C286326] A non-logged user can download the shared file from the viewer', async ({ personalFiles, page }) => { + await page.goto(file6SharedLink); + await personalFiles.viewer.waitForViewerToOpen(); + + const downloadPromise = personalFiles.page.waitForEvent('download'); + await personalFiles.viewer.toolbar.sharedDownloadButton.click(); + const download = await downloadPromise; + expect(download.suggestedFilename()).toBe(file6); + }); + }); + + test.describe('when logged in', () => { + const expiryDateObj = new Date(); + expiryDateObj.setFullYear(expiryDateObj.getFullYear() + 1); + const expiryDate: any = expiryDateObj.toISOString().replace('Z', '+0000'); + + test.describe('from Personal Files', () => { + let file3Id: string; + let file4Id: string; + let file5Id: string; + let file6Id: string; + let file7Id: string; + let file8Id: string; + let file9Id: string; + + test.beforeAll(async () => { + test.setTimeout(timeouts.extendedTest); + const nodesApi = await NodesApi.initialize(username, username); + const shareApi = await SharedLinksApi.initialize(username, username); + + file3Id = (await nodesApi.createFile(file3, parentId))?.entry.id; + file4Id = (await nodesApi.createFile(file4, parentId))?.entry.id; + file5Id = (await nodesApi.createFile(file5, parentId))?.entry.id; + file6Id = (await nodesApi.createFile(file6, parentId))?.entry.id; + file7Id = (await nodesApi.createFile(file7, parentId))?.entry.id; + file8Id = (await nodesApi.createFile(file8, parentId))?.entry.id; + file9Id = (await nodesApi.createFile(file9, parentId))?.entry.id; + + await shareApi.shareFilesByIds([file6Id, file7Id], expiryDate); + await shareApi.waitForFilesToBeShared([file6Id, file7Id]); + }); + + test.beforeEach(async ({ loginPage, personalFiles, page }) => { + await loginPage.navigate(); + await loginPage.loginUser({ username: username, password: username }); + + await personalFiles.waitForPageLoad(); + await personalFiles.dataTable.getCellByColumnNameAndRowItem(parent, 'Size').dblclick(); + await page.waitForTimeout(timeouts.tiny); + }); + + test.afterAll(async () => { + const nodesApi = await NodesApi.initialize(username, username); + await nodesApi.deleteNodes([file3Id, file4Id, file5Id, file6Id, file7Id, file8Id, file9Id]); + }); + + test('[C286327] Share dialog default values', async ({ personalFiles }) => { + expect(await personalFiles.dataTable.performActionFromExpandableMenu(file3, 'Share')); + const labels = await personalFiles.shareDialog.getLabels(); + expect(await personalFiles.shareDialog.getDialogTitle()).toEqual(`Share ${file3}`); + expect(labels[0].trim()).toBe(`Share ${file3}`); + expect(await personalFiles.shareDialog.getInfoText()).toEqual('Share Link'); + expect(await personalFiles.shareDialog.getLinkUrl()).toContain(shareLinkPreUrl); + expect(await personalFiles.shareDialog.isUrlReadOnly()).toBe(true); + expect(await personalFiles.shareDialog.isShareToggleChecked()).toBe(true); + expect(labels[1].trim()).toBe('Link Expiry Date'); + expect(await personalFiles.shareDialog.isExpireToggleEnabled()).toBe(false); + expect(await personalFiles.shareDialog.isCloseEnabled()).toBe(true); + }); + + test('[C286329] Share a file', async ({ personalFiles, nodesApiAction }) => { + expect(await personalFiles.dataTable.performActionFromExpandableMenu(file3, 'Share')); + + const url = await personalFiles.shareDialog.getLinkUrl(); + await personalFiles.shareDialog.clickClose(); + + const sharedId = await nodesApiAction.getSharedId(file3Id); + expect(url).toContain(sharedId); + }); + + test('[C286330] Copy shared file URL', async ({ personalFiles, page }) => { + expect(await personalFiles.dataTable.performActionFromExpandableMenu(file4, 'Share')); + + const url = await personalFiles.shareDialog.getLinkUrl(); + expect(url).toContain(shareLinkPreUrl); + + await personalFiles.shareDialog.urlAction.click(); + + const shareSnackBar = personalFiles.snackBar; + await expect(shareSnackBar.getByMessageLocator('Link copied to the clipboard')).toBeVisible(); + + await page.goto(url); + await personalFiles.viewer.waitForViewerToOpen(); + + const downloadPromise = personalFiles.page.waitForEvent('download'); + await personalFiles.viewer.toolbar.sharedDownloadButton.click(); + + const download = await downloadPromise; + expect(download.suggestedFilename()).toBe(file4); + }); + + test('[C286332] Share a file with expiration date', async ({ personalFiles, nodesApiAction, page }) => { + expect(await personalFiles.dataTable.performActionFromExpandableMenu(file5, 'Share')); + + await personalFiles.shareDialog.expireToggle.click(); + expect(await personalFiles.shareDialog.isExpireToggleEnabled()).toBe(true); + + await personalFiles.shareDialog.datetimePickerButton.click(); + expect(await personalFiles.shareDialog.dateTimePicker.isCalendarOpen()).toBe(true); + + await personalFiles.shareDialog.dateTimePicker.pickDateTime(); + + const inputDate = await personalFiles.shareDialog.getExpireDate(); + + await page.waitForTimeout(timeouts.normal); + const expireDateProperty = await nodesApiAction.getSharedExpiryDate(file5Id); + + expect(Utils.formatDate(expireDateProperty)).toEqual(Utils.formatDate(inputDate)); + }); + + test('[C286337] Expire date is displayed correctly', async ({ personalFiles, nodesApiAction }) => { + expect(await personalFiles.dataTable.performActionFromExpandableMenu(file6, 'Share')); + const expireProperty = await nodesApiAction.getSharedExpiryDate(file6Id); + + expect(expireProperty).toEqual(expiryDate); + expect(await personalFiles.shareDialog.isExpireToggleEnabled()).toBe(true); + expect(Utils.formatDate(await personalFiles.shareDialog.getExpireDate())).toEqual(Utils.formatDate(expiryDate)); + }); + + test('[C286333] Disable the share link expiration', async ({ personalFiles, nodesApiAction, page }) => { + expect(await personalFiles.dataTable.performActionFromExpandableMenu(file7, 'Share')); + + expect(await personalFiles.shareDialog.isExpireToggleEnabled()).toBe(true); + expect(await personalFiles.shareDialog.getExpireDate()).not.toBe(''); + + await personalFiles.shareDialog.expireToggle.click(); + expect(await personalFiles.shareDialog.isExpireToggleEnabled()).toBe(false); + + await page.waitForTimeout(timeouts.tiny); + await personalFiles.shareDialog.clickClose(); + expect(await nodesApiAction.getSharedExpiryDate(file7Id)).toBe(''); + }); + + test('[C286335] Shared file URL is not changed when Share dialog is closed and opened again', async ({ personalFiles }) => { + expect(await personalFiles.dataTable.performActionFromExpandableMenu(file8, 'Share')); + + const url1 = await personalFiles.shareDialog.getLinkUrl(); + await personalFiles.shareDialog.clickClose(); + + await personalFiles.dataTable.selectItem(file8); + await personalFiles.acaHeader.shareButton.click(); + const url2 = await personalFiles.shareDialog.getLinkUrl(); + + expect(url1).toEqual(url2); + }); + + test('[C286345] Share a file from the context menu', async ({ personalFiles, nodesApiAction }) => { + expect(await personalFiles.dataTable.performActionFromExpandableMenu(file9, 'Share')); + + const url = await personalFiles.shareDialog.getLinkUrl(); + await personalFiles.shareDialog.clickClose(); + + const sharedId = await nodesApiAction.getSharedId(file9Id); + expect(await nodesApiAction.isFileShared(file9Id)).toBe(true); + expect(url).toContain(sharedId); + }); + }); + }); +}); diff --git a/e2e/protractor/suites/actions/share/share-file.test.ts b/e2e/protractor/suites/actions/share/share-file.test.ts deleted file mode 100755 index ea6a4dd41c..0000000000 --- a/e2e/protractor/suites/actions/share/share-file.test.ts +++ /dev/null @@ -1,268 +0,0 @@ -/*! - * Copyright © 2005-2023 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 { browser } from 'protractor'; -import { AdminActions, UserActions, LoginPage, BrowsingPage, RepoClient, ShareDialog, Viewer, Utils } from '@alfresco/aca-testing-shared'; -import { BrowserActions } from '@alfresco/adf-testing'; - -describe('Share a file', () => { - const username = `user-${Utils.random()}`; - const parent = `parent-${Utils.random()}`; - let parentId: string; - - const file3 = `file3-${Utils.random()}.txt`; - const file4 = `file4-${Utils.random()}.txt`; - const file5 = `file5-${Utils.random()}.txt`; - const file6 = `file6-${Utils.random()}.txt`; - const file7 = `file7-${Utils.random()}.txt`; - const file8 = `file8-${Utils.random()}.txt`; - const file9 = `file9-${Utils.random()}.txt`; - - const viewer = new Viewer(); - const page = new BrowsingPage(); - const { dataTable, toolbar } = page; - const shareLinkPreUrl = `/#/preview/s/`; - - const apis = { - user: new RepoClient(username, username) - }; - - const adminApiActions = new AdminActions(); - const userActions = new UserActions(); - - beforeAll(async () => { - await adminApiActions.createUser({ username }); - await userActions.login(username, username); - - parentId = await apis.user.createFolder(parent); - }); - - afterAll(async () => { - await userActions.deleteNodes([parentId]); - }); - - describe('when logged out', () => { - let file6SharedLink: string; - let file6Id: string; - - beforeAll(async () => { - file6Id = await apis.user.createFile(file6, parentId); - - const sharedId = (await apis.user.shared.shareFileById(file6Id)).entry.id; - file6SharedLink = `${shareLinkPreUrl}${sharedId}`; - await apis.user.shared.waitForFilesToBeShared([file6Id]); - }); - - afterAll(async () => { - await userActions.deleteNodes([file6Id]); - }); - - it('[C286326] A non-logged user can download the shared file from the viewer', async () => { - await browser.get(file6SharedLink); - await viewer.waitForTxtViewerToLoad(); - - expect(await viewer.getFileTitle()).toEqual(file6); - - await BrowserActions.click(viewer.toolbar.downloadButton); - expect(await Utils.fileExistsOnOS(file6)).toBe(true, 'File not found in download location'); - }); - }); - - describe('when logged in', () => { - const expiryDateObj: Date = new Date(); - expiryDateObj.setFullYear(expiryDateObj.getFullYear() + 1); - const expiryDate: any = expiryDateObj.toISOString().replace('Z', '+0000'); - - const loginPage = new LoginPage(); - const shareDialog = new ShareDialog(); - const contextMenu = dataTable.menu; - - beforeAll(async () => { - await loginPage.loginWith(username); - }); - - describe('from Personal Files', () => { - let file3Id: string; - let file4Id: string; - let file5Id: string; - let file6Id: string; - let file7Id: string; - let file8Id: string; - let file9Id: string; - - beforeAll(async () => { - file3Id = await apis.user.createFile(file3, parentId); - file4Id = await apis.user.createFile(file4, parentId); - file5Id = await apis.user.createFile(file5, parentId); - file6Id = await apis.user.createFile(file6, parentId); - file7Id = await apis.user.createFile(file7, parentId); - file8Id = await apis.user.createFile(file8, parentId); - file9Id = await apis.user.createFile(file9, parentId); - - await userActions.login(username, username); - await userActions.shareNodes([file6Id, file7Id], expiryDate); - await apis.user.shared.waitForFilesToBeShared([file6Id, file7Id]); - }); - - beforeEach(async () => { - await page.clickPersonalFilesAndWait(); - await dataTable.doubleClickOnRowByName(parent); - await dataTable.waitForHeader(); - }); - - afterEach(async () => { - await Utils.pressEscape(); - await page.closeOpenDialogs(); - }); - - afterAll(async () => { - await userActions.deleteNodes([file3Id, file4Id, file5Id, file6Id, file7Id, file8Id, file9Id]); - }); - - it('[C286327] Share dialog default values', async () => { - await dataTable.selectItem(file3); - await toolbar.shareButton.click(); - await shareDialog.waitForDialogToOpen(); - - expect(await shareDialog.getDialogTitle()).toEqual(`Share ${file3}`); - expect(await shareDialog.getInfoText()).toEqual('Share Link'); - expect(await shareDialog.labels.get(0).getText()).toEqual(`Share ${file3}`); - expect(await shareDialog.getLinkUrl()).toContain(shareLinkPreUrl); - expect(await shareDialog.isUrlReadOnly()).toBe(true, 'url is not readonly'); - expect(await shareDialog.isShareToggleChecked()).toBe(true, 'Share toggle not checked'); - expect(await shareDialog.labels.get(1).getText()).toEqual('Link Expiry Date'); - expect(await shareDialog.isExpireToggleEnabled()).toBe(false, 'Expire toggle is checked'); - expect(await shareDialog.isCloseEnabled()).toBe(true, 'Close button is not enabled'); - }); - - it('[C286329] Share a file', async () => { - await dataTable.selectItem(file3); - await toolbar.shareButton.click(); - await shareDialog.waitForDialogToOpen(); - - const url = await shareDialog.getLinkUrl(); - await shareDialog.clickClose(); - - const sharedId = await apis.user.nodes.getSharedId(file3Id); - expect(url).toContain(sharedId); - }); - - it('[C286330] Copy shared file URL', async () => { - await dataTable.selectItem(file4); - await toolbar.shareButton.click(); - await shareDialog.waitForDialogToOpen(); - - const url = await shareDialog.getLinkUrl(); - expect(url).toContain(shareLinkPreUrl); - - await BrowserActions.click(shareDialog.urlAction); - expect(await page.getSnackBarMessage()).toBe('Link copied to the clipboard'); - - await browser.get(url); - - await viewer.waitForViewerToOpen(); - expect(await viewer.getFileTitle()).toEqual(file4); - - await page.load(); - }); - - it('[C286332] Share a file with expiration date', async () => { - await dataTable.selectItem(file5); - await toolbar.shareButton.click(); - await shareDialog.waitForDialogToOpen(); - - await BrowserActions.click(shareDialog.expireToggle); - expect(await shareDialog.isExpireToggleEnabled()).toBe(true, 'Expire toggle not checked'); - - await BrowserActions.click(shareDialog.datetimePickerButton); - expect(await shareDialog.dateTimePicker.isCalendarOpen()).toBe(true, 'Calendar not opened'); - await shareDialog.dateTimePicker.pickDateTime(); - await shareDialog.dateTimePicker.waitForDateTimePickerToClose(); - - const inputDate = await shareDialog.getExpireDate(); - const expireDateProperty = await apis.user.nodes.getSharedExpiryDate(file5Id); - - expect(Utils.formatDate(expireDateProperty)).toEqual(Utils.formatDate(inputDate)); - }); - - it('[C286337] Expire date is displayed correctly', async () => { - await dataTable.selectItem(file6); - await BrowserActions.click(toolbar.shareButton); - await shareDialog.waitForDialogToOpen(); - - const expireProperty = await apis.user.nodes.getSharedExpiryDate(file6Id); - expect(expireProperty).toEqual(expiryDate); - expect(await shareDialog.isExpireToggleEnabled()).toBe(true, 'Expiration is not checked'); - expect(Utils.formatDate(await shareDialog.getExpireDate())).toEqual(Utils.formatDate(expiryDate)); - }); - - it('[C286333] Disable the share link expiration', async () => { - await dataTable.selectItem(file7); - await BrowserActions.click(toolbar.shareButton); - await shareDialog.waitForDialogToOpen(); - - expect(await shareDialog.isExpireToggleEnabled()).toBe(true, 'Expiration is not checked'); - expect(await shareDialog.getExpireDate()).not.toBe('', 'Expire date input is empty'); - - await BrowserActions.click(shareDialog.expireToggle); - expect(await shareDialog.isExpireToggleEnabled()).toBe(false, 'Expiration is checked'); - expect(await shareDialog.expireInput.isDisplayed()).toBe(false, 'Expire date input is not empty'); - - await shareDialog.clickClose(); - expect(await apis.user.nodes.getSharedExpiryDate(file7Id)).toBe('', `${file7} link still has expiration`); - }); - - it('[C286335] Shared file URL is not changed when Share dialog is closed and opened again', async () => { - await dataTable.selectItem(file8); - await toolbar.shareButton.click(); - await shareDialog.waitForDialogToOpen(); - - const url1 = await shareDialog.getLinkUrl(); - await shareDialog.clickClose(); - - await page.dataTable.clearSelection(); - await dataTable.selectItem(file8); - await BrowserActions.click(toolbar.shareButton); - await shareDialog.waitForDialogToOpen(); - const url2 = await shareDialog.getLinkUrl(); - - expect(url1).toEqual(url2); - }); - - it('[C286345] Share a file from the context menu', async () => { - await dataTable.rightClickOnItem(file9); - await contextMenu.waitForMenuToOpen(); - await contextMenu.shareAction.click(); - await shareDialog.waitForDialogToOpen(); - - const url = await shareDialog.getLinkUrl(); - await shareDialog.clickClose(); - - const sharedId = await apis.user.nodes.getSharedId(file9Id); - expect(await apis.user.nodes.isFileShared(file9Id)).toBe(true, `${file9} is not shared`); - expect(url).toContain(sharedId); - }); - }); - }); -}); diff --git a/projects/aca-playwright-shared/src/api/nodes-api.ts b/projects/aca-playwright-shared/src/api/nodes-api.ts index 4037ffd87e..3ef94b0883 100755 --- a/projects/aca-playwright-shared/src/api/nodes-api.ts +++ b/projects/aca-playwright-shared/src/api/nodes-api.ts @@ -409,4 +409,44 @@ export class NodesApi { return null; } } + + async getNodeProperty(nodeId: string, property: string): Promise { + try { + const node = await this.getNodeById(nodeId); + return node.entry.properties?.[property] || ''; + } catch (error) { + console.error(`${this.constructor.name} ${this.getNodeProperty.name}`, error); + return ''; + } + } + + async getSharedId(nodeId: string): Promise { + try { + const sharedId = await this.getNodeProperty(nodeId, 'qshare:sharedId'); + return sharedId || ''; + } catch (error) { + console.error(`${this.constructor.name} ${this.getSharedId.name}`, error); + return ''; + } + } + + async getSharedExpiryDate(nodeId: string): Promise { + try { + const expiryDate = await this.getNodeProperty(nodeId, 'qshare:expiryDate'); + return expiryDate || ''; + } catch (error) { + console.error(`${this.constructor.name} ${this.getSharedExpiryDate.name}`, error); + return ''; + } + } + + async isFileShared(nodeId: string): Promise { + try { + const sharedId = await this.getSharedId(nodeId); + return sharedId !== ''; + } catch (error) { + console.error(`${this.constructor.name} ${this.isFileShared.name}`, error); + return null; + } + } } 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 b7f995a32f..0a551213e4 100755 --- a/projects/aca-playwright-shared/src/api/shared-links-api.ts +++ b/projects/aca-playwright-shared/src/api/shared-links-api.ts @@ -50,12 +50,12 @@ export class SharedLinksApi { } } - async shareFilesByIds(ids: string[]): Promise { + async shareFilesByIds(ids: string[], expireDate?: Date): Promise { const sharedLinks: SharedLinkEntry[] = []; try { if (ids && ids.length > 0) { for (const id of ids) { - const sharedLink = await this.shareFileById(id); + const sharedLink = await this.shareFileById(id, expireDate); sharedLinks.push(sharedLink); } } diff --git a/projects/aca-playwright-shared/src/page-objects/components/aca-header.component.ts b/projects/aca-playwright-shared/src/page-objects/components/aca-header.component.ts index 2e0252b67d..9f9eceefb9 100644 --- a/projects/aca-playwright-shared/src/page-objects/components/aca-header.component.ts +++ b/projects/aca-playwright-shared/src/page-objects/components/aca-header.component.ts @@ -37,6 +37,7 @@ export class AcaHeader extends BaseComponent { public fullScreenButton = this.getChild('button[id="app.viewer.fullscreen"]'); public shareButton = this.getChild('button[id="share-action-button"]'); public downloadButton = this.getChild('button[id="app.viewer.download"]'); + public sharedDownloadButton = this.getChild('button[id="app.viewer.shared.download"]'); constructor(page: Page) { super(page, AcaHeader.rootElement); diff --git a/projects/aca-playwright-shared/src/page-objects/components/datetime-picker/datetime-picker.component.ts b/projects/aca-playwright-shared/src/page-objects/components/datetime-picker/datetime-picker.component.ts new file mode 100644 index 0000000000..60dc634754 --- /dev/null +++ b/projects/aca-playwright-shared/src/page-objects/components/datetime-picker/datetime-picker.component.ts @@ -0,0 +1,58 @@ +/*! + * Copyright © 2005-2023 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 { Page } from '@playwright/test'; +import { BaseComponent } from '../base.component'; + +export class DateTimePicker extends BaseComponent { + private static rootElement = '.mat-calendar'; + calendar = this.getChild('.mat-datepicker-popup'); + dayPicker = this.getChild('mat-month-view'); + nextMonthBtn = this.getChild('.mat-calendar-next-button'); + rootElemLocator = this.page.locator('.mat-datepicker-popup'); + + constructor(page: Page) { + super(page, DateTimePicker.rootElement); + } + + async isCalendarOpen(): Promise { + const element = this.rootElemLocator; + return element.isVisible(); + } + + async pickDateTime(): Promise { + const today = new Date(); + const nextAvailableDay = new Date(); + nextAvailableDay.setDate(today.getDate() + 2); + if (nextAvailableDay.getMonth() !== today.getMonth()) { + await this.nextMonthBtn.click(); + } + await this.selectDay(nextAvailableDay.getDate()); + } + + async selectDay(day: number): Promise { + const firstActiveDayElem = this.dayPicker.locator(`text=${day}`).first(); + await firstActiveDayElem.click(); + } +} 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 c1a913f24d..091bd03320 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 @@ -29,3 +29,4 @@ export * from './viewer-overlay-dialog.component'; export * from './content-node-selector-dialog'; export * from './create-from-template-dialog-component'; export * from './adf-confirm-dialog.component'; +export * from './share-dialog.component'; diff --git a/projects/aca-playwright-shared/src/page-objects/components/dialogs/share-dialog.component.ts b/projects/aca-playwright-shared/src/page-objects/components/dialogs/share-dialog.component.ts new file mode 100644 index 0000000000..fde0b404dc --- /dev/null +++ b/projects/aca-playwright-shared/src/page-objects/components/dialogs/share-dialog.component.ts @@ -0,0 +1,101 @@ +/*! + * Copyright © 2005-2023 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 { ElementHandle, Locator, Page } from '@playwright/test'; +import { BaseComponent } from '../base.component'; +import { timeouts } from '../../../utils'; +import { DateTimePicker } from '../datetime-picker/datetime-picker.component'; + +export class ShareDialogComponent extends BaseComponent { + private static rootElement = 'adf-share-dialog'; + + constructor(page: Page) { + super(page, ShareDialogComponent.rootElement); + } + + closeButton = this.getChild('[data-automation-id="adf-share-dialog-close"]'); + dialogTitle = this.getChild('[data-automation-id="adf-share-dialog-title"]'); + infoText = this.getChild('.adf-share-link__info').first(); + labels = '.adf-share-link__label'; + shareToggle = this.getChild(`[data-automation-id='adf-share-toggle']`); + url = this.getChild(`[data-automation-id='adf-share-link']`); + urlAction = this.getChild('.adf-input-action'); + expireToggle = this.getChild(`[data-automation-id='adf-expire-toggle']`); + expireInput = this.getChild('input[formcontrolname="time"]'); + datetimePickerButton = this.getChild('.mat-datepicker-toggle'); + + dateTimePicker = new DateTimePicker(this.page); + + getDialogLabel = () => this.getChild('label').innerText(); + getErrorByText = (text: string): Locator => this.page.locator('mat-error', { hasText: text }); + + async getLabels(): Promise> { + return await this.page.$$eval('.adf-share-link__label', (elements) => elements.map((element) => element.textContent)); + } + + async getDialogTitle(): Promise { + return await this.dialogTitle.innerText(); + } + + async getInfoText(): Promise { + return await this.infoText.innerText(); + } + + async getLinkUrl(): Promise { + return await this.url.inputValue(); + } + + async isUrlReadOnly(): Promise { + const urlAttr = await this.url.getAttribute('readonly'); + return urlAttr === 'true'; + } + + async isCloseEnabled(): Promise { + return await this.closeButton.isEnabled(); + } + + async clickClose(): Promise { + await this.page.waitForTimeout(timeouts.tiny); + await this.closeButton.click(); + } + + async isToggleStatus(toggle: ElementHandle, status: string): Promise { + const toggleClass = await toggle.getAttribute('class'); + return toggleClass.includes(status); + } + + async isShareToggleChecked(): Promise { + const shareToggleElement = await this.shareToggle.elementHandle(); + return this.isToggleStatus(shareToggleElement, 'checked'); + } + + async isExpireToggleEnabled(): Promise { + const expireToggleElement = await this.expireToggle.elementHandle(); + return this.isToggleStatus(expireToggleElement, 'checked'); + } + + async getExpireDate(): Promise { + return await this.expireInput.inputValue(); + } +} diff --git a/projects/aca-playwright-shared/src/page-objects/components/index.ts b/projects/aca-playwright-shared/src/page-objects/components/index.ts index ec64165a7d..74c2a84a56 100644 --- a/projects/aca-playwright-shared/src/page-objects/components/index.ts +++ b/projects/aca-playwright-shared/src/page-objects/components/index.ts @@ -39,3 +39,4 @@ export * from './breadcrumb/breadcrumb.component'; export * from './sidenav.component'; export * from './aca-header.component'; export * from './error.component'; +export * from './datetime-picker/datetime-picker.component'; diff --git a/projects/aca-playwright-shared/src/page-objects/pages/personal-files.page.ts b/projects/aca-playwright-shared/src/page-objects/pages/personal-files.page.ts index 9d014df8ea..d9f43da3f8 100644 --- a/projects/aca-playwright-shared/src/page-objects/pages/personal-files.page.ts +++ b/projects/aca-playwright-shared/src/page-objects/pages/personal-files.page.ts @@ -37,7 +37,8 @@ import { ViewerComponent, SidenavComponent, PaginationComponent, - ErrorComponent + ErrorComponent, + ShareDialogComponent } from '../components'; export class PersonalFilesPage extends BasePage { @@ -60,6 +61,7 @@ export class PersonalFilesPage extends BasePage { public createFromTemplateDialogComponent = new CreateFromTemplateDialogComponent(this.page); public pagination = new PaginationComponent(this.page); public errorDialog = new ErrorComponent(this.page); + public shareDialog= new ShareDialogComponent(this.page); async selectCreateFolder(): Promise { await this.acaHeader.createButton.click(); diff --git a/projects/aca-playwright-shared/src/utils/utils.ts b/projects/aca-playwright-shared/src/utils/utils.ts index d11ba3ed3f..3bc69e54ee 100644 --- a/projects/aca-playwright-shared/src/utils/utils.ts +++ b/projects/aca-playwright-shared/src/utils/utils.ts @@ -42,4 +42,8 @@ export class Utils { return run(retry); } + + static formatDate(date: string): string { + return new Date(date).toLocaleDateString('en-US'); + } }