diff --git a/e2e/playwright/smoke-test/.eslintrc.json b/e2e/playwright/smoke-test/.eslintrc.json new file mode 100644 index 0000000000..bd35b2f907 --- /dev/null +++ b/e2e/playwright/smoke-test/.eslintrc.json @@ -0,0 +1,26 @@ +{ + "extends": "../../../.eslintrc.json", + "ignorePatterns": [ + "!**/*" + ], + "overrides": [ + { + "files": [ + "*.ts" + ], + "parserOptions": { + "project": [ + "e2e/playwright/smoke-test/tsconfig.e2e.json" + ], + "createDefaultProgram": true + }, + "plugins": [ + "rxjs", + "unicorn" + ], + "rules": { + "@typescript-eslint/no-floating-promises": "off" + } + } + ] +} diff --git a/e2e/playwright/smoke-test/exclude.tests.json b/e2e/playwright/smoke-test/exclude.tests.json new file mode 100644 index 0000000000..9e26dfeeb6 --- /dev/null +++ b/e2e/playwright/smoke-test/exclude.tests.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/e2e/playwright/smoke-test/playwright.config.ts b/e2e/playwright/smoke-test/playwright.config.ts new file mode 100644 index 0000000000..5ea402d6f5 --- /dev/null +++ b/e2e/playwright/smoke-test/playwright.config.ts @@ -0,0 +1,42 @@ +/*! + * Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved. + * + * Alfresco Example Content Application + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * from Hyland Software. If not, see . + */ + +import { PlaywrightTestConfig } from '@playwright/test'; +import { CustomConfig, getGlobalConfig, getExcludedTestsRegExpArray } from '@alfresco/aca-playwright-shared'; +import EXCLUDED_JSON from './exclude.tests.json'; + +const config: PlaywrightTestConfig = { + ...getGlobalConfig, + + grepInvert: getExcludedTestsRegExpArray(EXCLUDED_JSON, 'Smoke-test'), + projects: [ + { + name: 'Smoke-test', + testDir: './src/tests', + use: {} + } + ] +}; + +export default config; diff --git a/e2e/playwright/smoke-test/project.json b/e2e/playwright/smoke-test/project.json new file mode 100644 index 0000000000..7762fc0217 --- /dev/null +++ b/e2e/playwright/smoke-test/project.json @@ -0,0 +1,31 @@ +{ + "name": "smoke-test-e2e", + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "e2e/playwright/smoke-test/src", + "projectType": "application", + "targets": { + "e2e": { + "executor": "nx:run-commands", + "options": { + "commands": ["npx playwright test --config=e2e/playwright/smoke-test/playwright.config.ts"] + }, + "configurations": { + "production": { + "devServerTarget": "content-ce:serve:production" + }, + "ui": { + "args": ["--ui"] + }, + "debug": { + "args": ["--debug"] + }, + "headed": { + "args": ["--headed"] + } + } + }, + "lint": { + "executor": "@angular-eslint/builder:lint" + } + } +} diff --git a/e2e/playwright/smoke-test/src/tests/login/login.e2e.ts b/e2e/playwright/smoke-test/src/tests/login/login.e2e.ts new file mode 100644 index 0000000000..4f0e7ce1fd --- /dev/null +++ b/e2e/playwright/smoke-test/src/tests/login/login.e2e.ts @@ -0,0 +1,72 @@ +/*! + * Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved. + * + * Alfresco Example Content Application + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * from Hyland Software. If not, see . + */ + +import { expect } from '@playwright/test'; +import { ApiClientFactory, Utils, test } from '@alfresco/aca-playwright-shared'; + +test.describe('viewer file', () => { + const apiClientFactory = new ApiClientFactory(); + + const otherLanguageUser = { + /* cspell:disable-next-line */ + username: `пользвате${Utils.random()}`, + /* cspell:disable-next-line */ + password: '密碼中國' + }; + + const johnDoe = { + username: `user-${Utils.random()}`, + get password() { + return this.username; + }, + firstName: 'John', + lastName: 'Doe' + }; + + test.beforeAll(async () => { + await apiClientFactory.setUpAcaBackend('admin'); + + await apiClientFactory.createUser(otherLanguageUser); + await apiClientFactory.createUser(johnDoe); + }); + + test.describe('with invalid credentials', () => { + test('[C213106] unauthenticated user is redirected to Login page', async ({ personalFiles }) => { + await personalFiles.navigate(); + expect(personalFiles.page.url()).toContain('login'); + }); + }); + + test.describe('with valid credentials', () => { + test('[C213107] redirects to Home Page when navigating to the Login page while already logged in', async ({ loginPage }) => { + const { username } = johnDoe; + await loginPage.navigate(); + await loginPage.loginUser({ username: username, password: username }); + await loginPage.userProfileButton.waitFor({ state: 'attached' }); + await loginPage.navigate(); + await loginPage.userProfileButton.waitFor({ state: 'attached' }); + expect(loginPage.page.url()).toContain('personal-files'); + }); + }); +}); diff --git a/e2e/playwright/smoke-test/src/tests/search/personal-files.ts b/e2e/playwright/smoke-test/src/tests/search/personal-files.ts new file mode 100644 index 0000000000..3d35645997 --- /dev/null +++ b/e2e/playwright/smoke-test/src/tests/search/personal-files.ts @@ -0,0 +1,101 @@ +/*! + * Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved. + * + * Alfresco Example Content Application + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * from Hyland Software. If not, see . + */ + +import { test, timeouts } from '@alfresco/aca-playwright-shared'; +import { expect } from '@playwright/test'; + +export function personalFilesTests(userName: string, parentName: string) { + test.describe('Pagination controls : ', () => { + test.beforeEach(async ({ loginPage, personalFiles, page }) => { + await loginPage.navigate(); + await loginPage.loginUser({ username: userName, password: userName }); + await personalFiles.waitForPageLoad(); + await personalFiles.dataTable.getRowByName(parentName).dblclick(); + await page.waitForTimeout(timeouts.tiny); + }); + + test('[C280077] Pagination control default values', async ({ personalFiles }) => { + expect(await personalFiles.pagination.getRange()).toContain('Showing 1-25 of 51'); + expect(await personalFiles.pagination.getMaxItems()).toContain('25'); + expect(await personalFiles.pagination.getCurrentPage()).toContain('Page 1'); + expect(await personalFiles.pagination.getTotalPages()).toContain('of 3'); + expect(await personalFiles.pagination.isPreviousEnabled()).toBe(false); + expect(await personalFiles.pagination.isNextEnabled()).toBe(true); + }); + + test('[C280079] current page menu items', async ({ personalFiles }) => { + await personalFiles.pagination.openMaxItemsMenu(); + expect(await personalFiles.pagination.getItemsCount()).toBe(3); + await personalFiles.pagination.clickMenuItem('25'); + await personalFiles.dataTable.spinnerWaitForReload(); + expect(await personalFiles.pagination.getMaxItems()).toContain('25'); + expect(await personalFiles.pagination.getTotalPages()).toContain('of 3'); + + await personalFiles.pagination.openMaxItemsMenu(); + await personalFiles.pagination.clickMenuItem('50'); + expect(await personalFiles.pagination.getMaxItems()).toContain('50'); + expect(await personalFiles.pagination.getTotalPages()).toContain('of 2'); + + await personalFiles.pagination.openMaxItemsMenu(); + await personalFiles.pagination.clickMenuItem('100'); + expect(await personalFiles.pagination.getMaxItems()).toContain('100'); + expect(await personalFiles.pagination.getTotalPages()).toContain('of 1'); + + await personalFiles.pagination.resetToDefaultPageSize(); + }); + + test('[C280080] change the current page from menu', async ({ personalFiles }) => { + await personalFiles.pagination.clickOnNextPage(); + expect(await personalFiles.pagination.getRange()).toContain('Showing 26-50 of 51'); + expect(await personalFiles.pagination.getCurrentPage()).toContain('Page 2'); + expect(await personalFiles.pagination.isPreviousEnabled()).toBe(true); + expect(await personalFiles.pagination.isNextEnabled()).toBe(true); + await personalFiles.pagination.resetToDefaultPageSize(); + }); + + test('[C280083] navigate to next and previous pages', async ({ personalFiles }) => { + await personalFiles.pagination.openMaxItemsMenu(); + await personalFiles.pagination.clickMenuItem('25'); + expect(await personalFiles.pagination.getMaxItems()).toContain('25'); + await personalFiles.pagination.clickOnNextPage(); + await personalFiles.dataTable.spinnerWaitForReload(); + expect(await personalFiles.pagination.getRange()).toContain('Showing 26-50 of 51'); + await personalFiles.pagination.clickOnPreviousPage(); + await personalFiles.dataTable.spinnerWaitForReload(); + expect(await personalFiles.pagination.getRange()).toContain('Showing 1-25 of 51'); + }); + + test('[C280081] Previous button is disabled on first page', async ({ personalFiles }) => { + expect(await personalFiles.pagination.getCurrentPage()).toContain('Page 1'); + expect(await personalFiles.pagination.isPreviousEnabled()).toBe(false); + }); + + test('[C280082] Next button is disabled on last page', async ({ personalFiles }) => { + await personalFiles.pagination.openMaxItemsMenu(); + await personalFiles.pagination.clickNthItem(3); + expect(await personalFiles.pagination.getCurrentPage()).toContain('Page 1'); + expect(await personalFiles.pagination.isNextEnabled()).toBe(false); + }); + }); +} diff --git a/e2e/playwright/smoke-test/src/tests/search/search-results-general.e2e.ts b/e2e/playwright/smoke-test/src/tests/search/search-results-general.e2e.ts new file mode 100644 index 0000000000..a9d5055c07 --- /dev/null +++ b/e2e/playwright/smoke-test/src/tests/search/search-results-general.e2e.ts @@ -0,0 +1,122 @@ +/*! + * Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved. + * + * Alfresco Example Content Application + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * from Hyland Software. If not, see . + */ + +import { expect } from '@playwright/test'; +import { ApiClientFactory, Utils, test, TrashcanApi, NodesApi, SitesApi } from '@alfresco/aca-playwright-shared'; + +test.describe('Search Results - General', () => { + let trashcanApi: TrashcanApi; + let nodesApi: NodesApi; + let sitesApi: SitesApi; + + const random = Utils.random(); + const username = `user1-${random}`; + const file = `test-file-${random}.txt`; + const folder = `test-folder-${random}`; + const site = `test-site-${random}`; + + test.beforeAll(async () => { + try { + const apiClientFactory = new ApiClientFactory(); + await apiClientFactory.setUpAcaBackend('admin'); + await apiClientFactory.createUser({ username }); + trashcanApi = await TrashcanApi.initialize(username, username); + nodesApi = await NodesApi.initialize(username, username); + sitesApi = await SitesApi.initialize(username, username); + await nodesApi.createFolder(folder); + await nodesApi.createFile(file, '-my-'); + await sitesApi.createSite(site); + } catch (error) { + console.error(`beforeAll failed: ${error}`); + } + }); + + test.beforeEach(async ({ loginPage }) => { + await Utils.tryLoginUser(loginPage, username, username, 'beforeEach failed'); + }); + + test.afterAll(async () => { + await Utils.deleteNodesSitesEmptyTrashcan(nodesApi, trashcanApi, 'afterAll failed', sitesApi, [site]); + }); + + test('[C290005] Only files are returned when Files option is the only one checked', async ({ searchPage }) => { + await searchPage.searchWithin(`*${random}`, 'files'); + + expect(await searchPage.dataTable.isItemPresent(file)).toBeTruthy(); + expect(await searchPage.dataTable.isItemPresent(folder)).toBeFalsy(); + expect(await searchPage.dataTable.isItemPresent(site)).toBeFalsy(); + }); + + test('[C290006] Only folders are returned when Folders option is the only one checked', async ({ searchPage }) => { + await searchPage.searchWithin(`*${random}`, 'folders'); + + expect(await searchPage.dataTable.isItemPresent(file)).toBeFalsy(); + expect(await searchPage.dataTable.isItemPresent(folder)).toBeTruthy(); + expect(await searchPage.dataTable.isItemPresent(site)).toBeFalsy(); + }); + + test('[C290007] Files and folders are returned when both Files and Folders options are checked', async ({ searchPage }) => { + await searchPage.searchWithin(`*${random}`, 'filesAndFolders'); + + expect(await searchPage.dataTable.isItemPresent(file)).toBeTruthy(); + expect(await searchPage.dataTable.isItemPresent(folder)).toBeTruthy(); + expect(await searchPage.dataTable.isItemPresent(site)).toBeFalsy(); + }); + + test('[C290008] Only libraries are returned when Libraries option is checked', async ({ searchPage }) => { + await searchPage.searchWithin(`*${random}`, 'libraries'); + + expect(await searchPage.dataTable.isItemPresent(file)).toBeFalsy(); + expect(await searchPage.dataTable.isItemPresent(folder)).toBeFalsy(); + expect(await searchPage.dataTable.isItemPresent(site)).toBeTruthy(); + }); + + test('[C279162] Results are updated automatically when changing the search term', async ({ searchPage }) => { + await searchPage.searchWithin(file, 'filesAndFolders'); + + expect(await searchPage.dataTable.isItemPresent(file)).toBeTruthy(); + expect(await searchPage.dataTable.isItemPresent(folder)).toBeFalsy(); + + await searchPage.clickSearchButton(); + await searchPage.searchOverlay.searchFor(folder); + await searchPage.dataTable.progressBarWaitForReload(); + + expect(await searchPage.dataTable.isItemPresent(file)).toBeFalsy(); + expect(await searchPage.dataTable.isItemPresent(folder)).toBeTruthy(); + }); + + test('[C279178] Results are returned when accessing an URL containing a search query', async ({ searchPage, personalFiles }) => { + await searchPage.searchWithin(site, 'libraries'); + + expect(await searchPage.dataTable.isItemPresent(site)).toBeTruthy(); + + const url = searchPage.page.url(); + + await personalFiles.navigate(); + await personalFiles.page.goto(url); + await searchPage.dataTable.progressBarWaitForReload(); + + expect(await searchPage.dataTable.isItemPresent(site)).toBeTruthy(); + }); +}); diff --git a/e2e/playwright/smoke-test/src/tests/search/sort-list.e2e.ts b/e2e/playwright/smoke-test/src/tests/search/sort-list.e2e.ts new file mode 100644 index 0000000000..d50218d3f5 --- /dev/null +++ b/e2e/playwright/smoke-test/src/tests/search/sort-list.e2e.ts @@ -0,0 +1,203 @@ +/*! + * Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved. + * + * Alfresco Example Content Application + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * from Hyland Software. If not, see . + */ + +import { expect } from '@playwright/test'; +import { + ApiClientFactory, + FavoritesPageApi, + FileActionsApi, + NodesApi, + PersonalFilesPage, + TEST_FILES, + Utils, + test, + timeouts +} from '@alfresco/aca-playwright-shared'; + +async function getSortState(myPersonalFiles: PersonalFilesPage): Promise<{ [key: string]: string }> { + return { + sortingColumn: await myPersonalFiles.dataTable.getSortedColumnHeaderText(), + sortingOrder: await myPersonalFiles.dataTable.getSortingOrder(), + firstElement: await myPersonalFiles.dataTable.getFirstElementDetail('Name') + }; +} + +test.describe('Remember sorting', () => { + const user1 = `userSort1-${Utils.random()}`; + const pdfFileNames = [...new Array(14).fill(100)].map((v, i) => `file-${v + i}.pdf`); + const jpgFileNames = [...new Array(12).fill(114)].map((v, i) => `file-${v + i}.jpg`); + const folderToMove = `folder1`; + const folderToContain = `folder2`; + const uiCreatedFolder = `folder3`; + + const testData = { + user1: { + files: { + jpg: jpgFileNames, + pdf: pdfFileNames + } + } + }; + + let initialSortState: { [key: string]: string }; + let nodeActionUser1: NodesApi; + + test.beforeAll(async () => { + try { + test.setTimeout(timeouts.extendedTest); + const apiClientFactory = new ApiClientFactory(); + await apiClientFactory.setUpAcaBackend('admin'); + await apiClientFactory.createUser({ username: user1 }); + const fileActionUser1 = await FileActionsApi.initialize(user1, user1); + const favoritesActions = await FavoritesPageApi.initialize(user1, user1); + nodeActionUser1 = await NodesApi.initialize(user1, user1); + const filesIdsUser1: { [key: string]: string } = {}; + await Promise.all( + testData.user1.files.pdf.map( + async (i) => (filesIdsUser1[i] = (await fileActionUser1.uploadFileWithRename(TEST_FILES.PDF.path, i, '-my-')).entry.id) + ) + ); + await Promise.all( + testData.user1.files.jpg.map( + async (i) => (filesIdsUser1[i] = (await fileActionUser1.uploadFileWithRename(TEST_FILES.JPG_FILE.path, i, '-my-')).entry.id) + ) + ); + await favoritesActions.addFavoritesByIds('file', [filesIdsUser1[pdfFileNames[0]], filesIdsUser1[pdfFileNames[1]]]); + } catch (error) { + console.error(`beforeAll failed : ${error}`); + } + }); + + test.beforeEach(async ({ loginPage, personalFiles }) => { + await NodesApi.initialize(user1, user1); + await loginPage.loginUser( + { username: user1, password: user1 }, + { + withNavigation: true, + waitForLoading: true + } + ); + await personalFiles.dataTable.sortBy('Name', 'asc'); + await personalFiles.dataTable.spinnerWaitForReload(); + initialSortState = await getSortState(personalFiles); + }); + + test.afterAll(async () => { + nodeActionUser1 = await NodesApi.initialize(user1, user1); + await nodeActionUser1.deleteCurrentUserNodes(); + }); + + test('[C261136] Sort order is retained when navigating to another part of the app', async ({ personalFiles, favoritePage }) => { + await personalFiles.dataTable.sortBy('Name', 'desc'); + await personalFiles.dataTable.spinnerWaitForReload(); + + const expectedSortData = await getSortState(personalFiles); + expect(expectedSortData).not.toEqual(initialSortState); + + await favoritePage.navigate(); + await personalFiles.navigate(); + + const actualSortData = await getSortState(personalFiles); + expect(actualSortData).toEqual(expectedSortData); + }); + + test('[C589205] Size sort order is retained after viewing a file and closing the viewer', async ({ personalFiles }) => { + await personalFiles.dataTable.sortBy('Size', 'desc'); + await personalFiles.dataTable.spinnerWaitForReload(); + const expectedSortData = await getSortState(personalFiles); + + await personalFiles.dataTable.performClickFolderOrFileToOpen(expectedSortData.firstElement); + await personalFiles.viewer.closeButtonLocator.click(); + await personalFiles.waitForPageLoad(); + + const actualSortData = await getSortState(personalFiles); + expect(actualSortData).toEqual(expectedSortData); + }); + + test('[C261147] Sort order is retained when user changes the page from pagination', async ({ personalFiles }) => { + const lastFileInArray = testData.user1.files.jpg.slice(-2).pop(); + const firstFileInArray = testData.user1.files.pdf[0]; + + await personalFiles.pagination.clickOnNextPage(); + await personalFiles.dataTable.spinnerWaitForReload(); + + let expectedPersonalFilesSortDataPage2 = { + sortingColumn: 'Name', + sortingOrder: 'asc', + firstElement: lastFileInArray + }; + + let currentPersonalFilesSortDataPage2 = await getSortState(personalFiles); + expect(currentPersonalFilesSortDataPage2).toEqual(expectedPersonalFilesSortDataPage2); + + await personalFiles.dataTable.sortBy('Name', 'desc'); + await personalFiles.dataTable.spinnerWaitForReload(); + expectedPersonalFilesSortDataPage2 = { + sortingColumn: 'Name', + sortingOrder: 'desc', + firstElement: firstFileInArray + }; + + currentPersonalFilesSortDataPage2 = await getSortState(personalFiles); + expect(expectedPersonalFilesSortDataPage2).toEqual(currentPersonalFilesSortDataPage2); + }); + + test.describe('Folder actions', () => { + test.beforeAll(async () => { + const folderIds: { [key: string]: string } = {}; + folderIds[folderToContain] = (await nodeActionUser1.createFolder(folderToContain)).entry.id; + folderIds[folderToMove] = (await nodeActionUser1.createFolder(folderToMove)).entry.id; + }); + + test('[C261138] Sort order is retained when creating a new folder', async ({ personalFiles }) => { + await personalFiles.dataTable.sortBy('Name', 'desc'); + await personalFiles.dataTable.spinnerWaitForReload(); + + const expectedSortData = { + sortingColumn: await personalFiles.dataTable.getSortedColumnHeaderText(), + sortingOrder: await personalFiles.dataTable.getSortingOrder(), + firstElement: uiCreatedFolder + }; + + await personalFiles.selectCreateFolder(); + await personalFiles.folderDialog.createNewFolderDialog(uiCreatedFolder); + await personalFiles.dataTable.isItemPresent(uiCreatedFolder); + + const actualSortData = await getSortState(personalFiles); + expect(actualSortData).toEqual(expectedSortData); + }); + + test('[C261139] Sort order is retained when moving a file', async ({ personalFiles }) => { + const expectedSortData = { + sortingColumn: await personalFiles.dataTable.getSortedColumnHeaderText(), + sortingOrder: await personalFiles.dataTable.getSortingOrder(), + firstElement: folderToContain + }; + await personalFiles.copyOrMoveContentInDatatable([folderToMove], folderToContain, 'Move'); + await personalFiles.dataTable.spinnerWaitForReload(); + const actualSortData = await getSortState(personalFiles); + expect(actualSortData).toEqual(expectedSortData); + }); + }); +}); diff --git a/e2e/playwright/smoke-test/src/tests/viewer/viewer.e2e.ts b/e2e/playwright/smoke-test/src/tests/viewer/viewer.e2e.ts new file mode 100644 index 0000000000..be1400a78a --- /dev/null +++ b/e2e/playwright/smoke-test/src/tests/viewer/viewer.e2e.ts @@ -0,0 +1,141 @@ +/*! + * Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved. + * + * Alfresco Example Content Application + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * from Hyland Software. If not, see . + */ + +import { expect } from '@playwright/test'; +import { + ApiClientFactory, + FileActionsApi, + NodesApi, + SitesApi, + test, + TEST_FILES, + timeouts, + Utils, + TrashcanApi +} from '@alfresco/aca-playwright-shared'; +import { Site } from '@alfresco/js-api'; + +test.describe('viewer file', () => { + const username = `user-${Utils.random()}`; + const randomDocxName = `${TEST_FILES.DOCX.name}-${Utils.random()}`; + const siteAdmin = `siteAdmin-${Utils.random()}`; + const fileAdmin = TEST_FILES.XLSX.name; + let fileAdminId: string; + let docLibId: string; + let folderId: string; + let fileDocxId: string; + let nodesApi: NodesApi; + let trashcanApi: TrashcanApi; + let siteActionsAdmin: SitesApi; + + test.beforeAll(async () => { + test.setTimeout(timeouts.extendedTest); + const randomFolderName = `viewer-${Utils.random()}`; + const apiClientFactory = new ApiClientFactory(); + await apiClientFactory.setUpAcaBackend('admin'); + try { + await apiClientFactory.createUser({ username }); + } catch (exception) { + if (JSON.parse(exception.message).error.statusCode !== 409) { + throw new Error(`----- beforeAll failed : ${exception}`); + } + } + nodesApi = await NodesApi.initialize(username, username); + const fileActionApi = await FileActionsApi.initialize(username, username); + trashcanApi = await TrashcanApi.initialize(username, username); + siteActionsAdmin = await SitesApi.initialize('admin'); + const fileActionApiAdmin = await FileActionsApi.initialize('admin'); + const node = await nodesApi.createFolder(randomFolderName); + folderId = node.entry.id; + const fileDoc = await fileActionApi.uploadFile(TEST_FILES.DOCX.path, randomDocxName, folderId); + fileDocxId = fileDoc.entry.id; + + try { + await siteActionsAdmin.createSite(siteAdmin, Site.VisibilityEnum.PRIVATE); + } catch (exception) { + if (JSON.parse(exception.message).error.statusCode !== 409) { + throw new Error(`----- beforeAll failed : ${exception}`); + } + } + + docLibId = await siteActionsAdmin.getDocLibId(siteAdmin); + + try { + fileAdminId = (await fileActionApiAdmin.uploadFile(TEST_FILES.DOCX.path, fileAdmin, docLibId)).entry.id; + } catch (exception) { + if (JSON.parse(exception.message).error.statusCode !== 409) { + throw new Error(`----- beforeAll failed : ${exception}`); + } + } + + await fileActionApi.waitForNodes(randomDocxName, { expect: 1 }); + }); + + test.beforeEach(async ({ personalFiles, loginPage }) => { + await Utils.tryLoginUser(loginPage, username, username, 'beforeEach failed'); + await personalFiles.navigate({ remoteUrl: `#/personal-files/${folderId}` }); + }); + + test.afterAll(async () => { + await Utils.deleteNodesSitesEmptyTrashcan(nodesApi, trashcanApi, 'afterAll failed'); + await Utils.deleteNodesSitesEmptyTrashcan(nodesApi, trashcanApi, 'afterAll failed', siteActionsAdmin, [docLibId]); + }); + + test('[C279270] Viewer opens when clicking the View action for a file', async ({ personalFiles }) => { + await personalFiles.dataTable.getRowByName(randomDocxName).click(); + await personalFiles.acaHeader.viewButton.click(); + await personalFiles.dataTable.spinnerWaitForReload(); + expect(await personalFiles.viewer.isViewerOpened(), 'Viewer is not opened').toBe(true); + }); + + test('[C279283] The viewer general elements are displayed', async ({ personalFiles }) => { + await personalFiles.dataTable.performClickFolderOrFileToOpen(randomDocxName); + expect(await personalFiles.viewer.isViewerOpened()).toBe(true); + await personalFiles.dataTable.spinnerWaitForReload(); + expect(await personalFiles.viewer.isCloseButtonDisplayed(), 'Close button is not displayed').toBe(true); + expect(await personalFiles.viewer.isFileTitleDisplayed(), 'File title is not displayed').toBe(true); + }); + + test('[C279271] Close the viewer', async ({ personalFiles }) => { + await personalFiles.dataTable.performClickFolderOrFileToOpen(randomDocxName); + expect(await personalFiles.viewer.isViewerOpened(), 'Viewer is not opened').toBe(true); + expect(await personalFiles.viewer.getCloseButtonTooltip()).toEqual('Close'); + await personalFiles.viewer.closeButtonLocator.click(); + await expect(personalFiles.dataTable.getCellLinkByName(randomDocxName), 'Viewer did not close').toBeVisible(); + }); + + test('[C279285] Viewer opens when accessing the preview URL for a file', async ({ personalFiles }) => { + const previewURL = `#/personal-files/${folderId}/(viewer:view/${fileDocxId})`; + await personalFiles.navigate({ remoteUrl: previewURL }); + await personalFiles.dataTable.spinnerWaitForReload(); + expect(await personalFiles.viewer.isViewerOpened(), 'Viewer is not opened').toBe(true); + await expect(personalFiles.viewer.fileTitleButtonLocator).toHaveText(randomDocxName); + }); + + test('[C279287] Viewer does not open when accessing the preview URL for a file without permissions', async ({ personalFiles }) => { + const previewURL = `#/libraries/${docLibId}/(viewer:view/${fileAdminId})`; + await personalFiles.navigate({ remoteUrl: `${previewURL}` }); + await expect(personalFiles.viewer.viewerLocator, 'Viewer should not be opened!').toBeHidden(); + }); +}); diff --git a/e2e/playwright/smoke-test/tsconfig.e2e.adf.json b/e2e/playwright/smoke-test/tsconfig.e2e.adf.json new file mode 100644 index 0000000000..47ea883b4e --- /dev/null +++ b/e2e/playwright/smoke-test/tsconfig.e2e.adf.json @@ -0,0 +1,15 @@ +{ + "extends": "../../../tsconfig.adf.json", + "compilerOptions": { + "outDir": "../../out-tsc/e2e", + "baseUrl": "./", + "module": "commonjs", + "target": "es2017", + "types": ["jasmine", "jasminewd2", "node"], + "skipLibCheck": true, + "paths": { + "@alfresco/aca-playwright-shared": ["dist/@alfresco/aca-playwright-shared"] + } + }, + "exclude": ["node_modules"] +} diff --git a/e2e/playwright/smoke-test/tsconfig.e2e.json b/e2e/playwright/smoke-test/tsconfig.e2e.json new file mode 100755 index 0000000000..16d87d8ec1 --- /dev/null +++ b/e2e/playwright/smoke-test/tsconfig.e2e.json @@ -0,0 +1,15 @@ +{ + "extends": "../../../tsconfig.json", + "compilerOptions": { + "outDir": "../../out-tsc/e2e", + "baseUrl": "./", + "module": "commonjs", + "target": "es2017", + "types": ["jasmine", "jasminewd2", "node", "@playwright/test"], + "skipLibCheck": true, + "paths": { + "@alfresco/aca-playwright-shared": ["dist/@alfresco/aca-playwright-shared"] + } + }, + "exclude": ["node_modules"] +}